Files
seta75D 2e8a93c394 Init
2021-10-11 18:20:23 -03:00

1132 lines
21 KiB
Groff

.\" @(#)bs.1 1.1 92/07/30 SMI; from S5
.TH BS 1 "10 April 1986"
.SH NAME
bs \- a compiler/interpreter for modest-sized programs
.SH SYNOPSIS
.B bs
[ \fIsourcefile\fP [ \fIargs\fP ] ]
.SH DESCRIPTION
.I bs
is a remote descendant of Basic and Snobol4 with a little
.B C
language thrown in.
.I bs
is designed for programming tasks where program development time
is as important as the resulting speed of execution.
Formalities of data declaration and file/process manipulation
are minimized. Line-at-a-time debugging, the
.B trace
and
.B dump
statements, and useful run-time error messages all simplify program testing.
Furthermore, incomplete programs can be debugged;
.I inner
functions can be tested before
.I outer
functions have been written, and vice versa.
.PP
If the command line
.I sourcefile
argument is provided, it is used for input before the keyboard is read.
By default, statements read from
.I sourcefile
are compiled for later
execution. Likewise, statements entered from the keyboard are normally
executed immediately
(see
.B compile
and
.B execute
below).
Unless the final operation is assignment,
the result of an immediate expression statement is printed.
.SH USAGE
.SS Input Lines
.PP
If the last character on an input line is a \fB\e\fP, its text is continued
onto the next input line.
.I bs
accepts lines of the following form:
.PP
.RS
.I statement
.br
.IB label :
.I statement
.RE
.PP
A label and a variable can have the same name.
.PP
A
.I statement
is either an expression or a keyword followed by zero or more expressions.
Some keywords
.RB ( clear ,
.BR compile ,
.BR ! ,
.BR execute ,
.BR include ,
.BR ibase ,
.BR obase ,
and
.BR run )
are always executed as they are compiled.
.SS Statements
.TP .75i
.I expression
The expression is executed for its side
effects (value, assignment, or function call).
The details of expressions follow the description of
statement types below.
.TP
.B break
Exit from the inner-most
.BR for / while
loop.
.TP
.B clear
Clears the symbol table and compiled statements;
.B clear
is executed immediately.
.HP
.B compile
.RI [ " expression " ]
.br
Succeeding statements are compiled (overrides the immediate execution default).
The optional expression is evaluated and used as a filename for further input.
A
.B clear
is associated with this latter case.
.I compile
is executed immediately.
.TP
.B continue
Transfer to the loop-continuation of the current
.BR for / while
loop.
.HP
.B dump
.RI [ " name " ]
.br
The name and current value of every nonlocal variable is printed.
Optionally, only the named variable is reported.
After an error or interrupt, the number of the last
statement and (possibly) the user-function trace are displayed.
.HP
.B exit
.RI [ " expression " ]
.br
Return to system level.
The
.I expression
is returned as process status.
.TP
.B execute
Change to immediate execution mode (an interrupt has a similar effect).
This statement does not cause stored statements to execute (see
.I run
below).
.if t .bp
.PD 0
.HP
.B for
.I name
.B =
.I expression expression statement
.HP
.B for
.I name
.B =
.I expression expression
.TP
\&.\|.\|.
.HP
.B next
.HP
.B for
.I expression
.B ,
.I expression
.B ,
.I expression statement
.HP
.B for
.I expression
.B ,
.I expression
.B ,
.I expression
.TP
\&.\|.\|.
.TP
.B next
.IP
The
.I for
statement repetitively executes a statement (first form)
or a group of statements (second form) under control of a named variable.
The variable takes on the value of the first expression,
then is incremented by one on each loop, not to exceed the value of
the second expression. The third and fourth forms require three expressions
separated by commas. The first of these is the initialization, the second
is the test (true to continue), and the third is the
loop-continuation action (normally an increment).
.PD
.HP
.B fun
\fIf\fB(\fR[ \fIarg\|\fB, \fR\&.\|.\|. ]\|\fB) \fR[\|\fIvar\fB, \fR\&.\|.\|. ]
.br
\&.\|.\|.
.br
.ns
.TP
.B nuf
.I fun
defines the function name, arguments, and local variables
for a user-written function.
Up to ten arguments and local variables are allowed.
Such names cannot be arrays, nor can they be I/O associated.
Function definitions may not be nested.
.TP
.B freturn
A way to signal the failure of a user-written function.
See the interrogation operator (\fB?\fP) below.
If interrogation is not present,
.I freturn
merely returns zero. When interrogation
.I is
active,
.I freturn
transfers to that expression
(possibly bypassing intermediate function returns).
.TP
.BI goto \ name
Control is passed to the internally stored statement
with the matching label.
.TP
.BI ibase \ n
Set the input base (radix) to
.IR n .
The only supported values for
.I n
are
.BR 8 ,
.B 10
(the default), and
.BR 16 .
Hexadecimal values 10\-15 are entered as
.BR a \- f .
A leading digit is required
(i.e.,
.B f0a
must be entered as
.BR 0f0a ).
.B ibase
(and
.BR obase ", below)"
are executed immediately.
.HP
.B if
.I expression statement
.br
.ns
.HP
.B if
.I expression
.ns
.TP
\&.\|.\|.
.ns
.HP
[
.B else
.ns
.TP
\&.\|.\|.
.TP
]
.br
.ns
.HP
.B fi
.br
The statement (first form) or group of statements (second form)
is executed if the expression evaluates to nonzero. The strings
.B 0
and "" (null) evaluate to zero. In the second form,
an optional
.B else
allows for a group of statements to be executed when the first group is not.
The only statement permitted on the same line with an
.B else
is an
.IR if ;
only other
.BR fi "'s can be on the same line with a"
.BR fi .
.B elif
is supported.
Only a single
.B fi
is required to close an
\fBif .\|.\|. elif .\|.\|. \fR[ \fBelse .\|.\|. \fR]
sequence.
.TP
.BI include " expression"
The expression must evaluate to a file name.
The file must contain
.I bs
source statements.
Such statements become part of the program being compiled.
.B include
statements may not be nested.
.TP
.BI obase \ n
Set the output base to
.I n
(see
.I ibase
above).
.HP
.B onintr
.I label
.br
.ns
.TP
.B onintr
The
.B onintr
command provides program control of interrupts.
In the first form, control will pass to the label given, just as if a
.B goto
had been executed at the time
.B onintr
was executed. The effect of the statement is cleared after each interrupt.
In the second form, an interrupt will cause
.I bs
to terminate.
.HP
.B return
.RI [ " expression " ]
.br
The expression is evaluated and the result is passed
back as the value of a function call.
If no expression is given, zero is returned.
.TP
.B run
The random number generator is reset. Control is passed to the first internal
statement. If the
.B run
statement is contained in a file, it should be the
last statement.
.TP
.B stop
Execution of internal statements is stopped.
.I bs
reverts to immediate mode.
.HP
.B trace
.RI [ " expression " ]
.br
The
.B trace
statement controls function tracing.
If the expression is null (or evaluates to zero), tracing is turned off.
Otherwise, a record of user-function calls and returns is printed.
Each
.B return
decrements the
.B trace
expression value.
.PD 0
.TP
.B while
.I expression statement
.br
.ns
.TP
.B while
.I expression
.TP
\&.\|.\|.
.br
.ns
.TP
.B next
.B while
is similar to
.B for
except that only the conditional expression
for loop-continuation is given.
.PD
.HP
.B !
.I shell-command
.br
An immediate escape to the Shell.
.TP
.BR # \ \&.\|.\|.
Comment.
A comment is terminated at the next newline.
.SS Expressions
.TP .75i
.I name
A
.I name
is used to specify a variable. Names are composed of a letter
(upper or lower case) optionally followed by letters and digits.
Only the first six characters of a name are significant.
Except for names declared in
.B fun
statements, all names are global to the program.
Names can take on numeric (double float) values, string values,
or can be associated with input/output (see the builtin function
.BR open() ,
below).
.HP
.I name
.B (
.RI [ " expression " [
.B ,
.IR " expression " "] .\|.\|. ]"
.B )
.br
Functions can be called by a name followed by the arguments
in parentheses, separated by commas.
Except for builtin functions (listed below),
the name must be defined with a
.B fun
statement. Arguments to functions are passed by value.
.HP
.I name
.B [
.I expression
[
.B ,
.I expression
] .\|.\|.
.B ]
.br
This syntax is used to reference either arrays or tables
(see the builtin
.I table
functions below).
For arrays, each expression is truncated to an integer
and used as a specifier for the name.
The resulting array reference is syntactically identical to a name;
.B a[1,2]
is the same as
.BR a[1][2] .
The truncated expressions are restricted to
values between 0 and 32767.
.TP
.I number
A number is used to represent a constant value.
A number is written in Fortran style,
and contains digits, an optional decimal point,
and possibly a scale factor consisting
of an
.B e
followed by a possibly signed exponent.
.TP
.I string
Character strings are delimited by \fB"\fP characters.
The \fB\e\fP escape character allows the double quote (\fB\e"\fP),
newline (\fB\en\fP), carriage return (\fB\er\fP),
backspace (\fB\eb\fP), and tab (\fB\et\fP) characters
to appear in a string.
Otherwise, \fB\e\fP stands for itself.
.HP
.B (
.I expression
.B )
.br
Parentheses are used to alter the normal order of evaluation.
.HP
.B (
.IB expression ,
.I expression
.RB [ ,
.IR "expression " ".\|.\|. ]"
.B ") ["
.I expression
.B ]
.br
The bracketed expression is used as a subscript to select a
comma-separated expression from the parenthesized list.
List elements are numbered from the left, starting at zero.
The expression:
.PD 0
.RS
.IP
.B "( False, True )[ a == b ]"
.RE
.PD
.IP
has the value
.B true
if the comparison is true.
.HP
.B ?
.I expression
.br
The interrogation operator
tests for the success of the expression rather than its value.
At the moment, it is useful for testing end-of-file
(see
.SM EXAMPLES,
below),
the result of the
.B eval
builtin function,
and for checking the return from user-written functions
(see
.BR freturn ).
An interrogation ``trap'' (end-of-file, etc.)
causes an immediate transfer to the most recent
interrogation, possibly skipping assignment statements or intervening
function levels.
.TP
.BI \- " expression"
The result is the negation of the expression.
.TP
.BI ++ " name"
Increments the value of the variable (or array reference).
The result is the new value.
.TP
.BI \-\- " name"
Decrements the value of the variable. The result is the new value.
.TP
.B !
expression
.br
The logical negation of the expression.
Watch out for the shell escape command.
.HP
.I expression
.I operator
.I expression
.br
Common functions of two arguments are abbreviated
by the two arguments separated by an operator denoting the function.
Except for the assignment,
concatenation, and relational operators, both operands are converted to numeric form
before the function is applied.
.SS "Binary Operators"
The assignment operator binds right to left.
All other operators bind left to right.
Operators are grouped in order of precedence:
.TP
^
Exponentiation.
.TP
.B *\ /\ %
Multiply, divide, and remainder, respectively.
.TP
.B +\ \-
Add and subtract.
.TP
.B <\ <=\ >\ >=\ ==\ !=
Comparisons.
These comparison operators return ``1'' if the indicated relationship
holds true for their operands, or ``0'' otherwise.
.RS
.PD 0
.TP
\fB<\fP
less than
.TP
\fB<=\fP
less than or equal to
.TP
\fB>\fP
greater than
.TP
\fB>=\fP
greater than or equal to
.TP
\fB==\fP
equal to
.TP
\fB!=\fP
not equal
.LP
Relational operators at the same level extend as follows:
.RS
.IB a > b > c
.RE
is the same as
.RS
.IB a > b " & " b > c
.RE
A string comparison is made if both operands are strings.
.PD
.RE
.TP
.B & |
Logical Conjunctions.
.RS
.TP
.B &
Logical
.SM AND.
Has result ``0'' if either of its operands evaluates to ``0''.
It has result ``1'' if both of its operands are nonzero.
.TP
.B |
Logical
.SM OR.
Has result ``0'' if both of its arguments are ``0''.
It has result ``1'' if either of its arguments is nonzero.
Both operators treat a null string as a zero.
.RE
.TP
.B _
Concatenation.
.TP
.B =
Assignment.
The left operand must be a name or an array element.
The result is the right operand.
.if t .bp
.SS Builtin Functions
.SS \fIProcessing \fIArguments
.TP .75i
.BI arg( i )
The value of the
.IR i -th
actual parameter on the current level of function call.
At level zero,
.I arg
returns the
.IR i -th
command-line argument
.RB ( arg (0)
returns
.BR bs ).
.TP
.B narg(\|)
Returns the number of arguments passed.
At level zero, the command argument count is returned.
.SS \fIMathematical \fIFunctions
.TP .75i
.BI abs( x )
The absolute value of
.IR x .
.TP
.BI atan( x )
The arctangent of
.IR x .
Its value
is between \-\(*p/2 and \(*p/2.
.TP
.BI ceil( x )
Returns the smallest integer not less than
.IR x .
.TP
.BI cos( x )
The cosine of
.I x
.I x
is in radians.
.TP
.BI exp( x )
The exponential function of
.IR x .
.TP
.BI floor( x )
Returns the largest integer not greater than
.IR x .
.TP
.BI log( x )
The natural logarithm of
.IR x .
.TP
.B rand(\|)
A uniformly-distributed random number between zero and one.
.TP
.BI sin( x )
The sine of
.I x
(radians).
.TP
.BI sqrt( x )
The square root of
.IR x .
.SS \fIString \fIFunctions
.TP
.BI size( s )
the size (length in bytes) of
.I s
is returned.
.TP
.BI format( f , \ a )
Returns the formatted value of
.IR a .
.I f
is assumed to be a format specification in the style of
.IR printf (3S).
Only the
.BR %\|.\|.\|.\|f ,
.BR %\|.\|.\|.\|e ,
and
.B %\|.\|.\|.\|s
types are safe.
.TP
.BI index( x , \ y )
Returns the number of the first position in
.I x
that any of the characters from
.I y
matches. No match yields zero.
.TP
\fBtrans( \fIs\fB, \fIf\fB, \fIt\fB\|)
Translate characters of the source
.I s
from matching characters in
.I f
to a character in the same position in
.IR t .
Source characters that do not appear in
.I f
are copied to the result.
If the string
.I f
is longer than
.IR t ,
source characters that match in the excess portion of
.I f
do not appear in the result.
.TP
\fBsubstr(\fIs\fB, \fIstart\fB, \fIwidth\fB\|)
Returns the substring of
.I s
defined by the
.IR start ing
position and
.IR width .
.TP
.BI match( string , \ pattern )
.ns
.TP
.BI mstring( n )
The
.I pattern
is similar to the regular expression syntax of
.IR grep (1).
The characters \fB.\fP, \fB[\fP, \fB]\fP, \*^ (inside
brackets), \fB*\fP and \fB$\fP are special.
.IP
.B mstring()
returns the \fIn\fR-th (1 <= \fIn\fP <= 10) substring of the subject
that occurred between pairs of the pattern symbols \fB\e(\fP and \fB\e)\fP
for the most recent call to
.IR match .
To succeed, patterns must match the beginning of the string
(as if all patterns began with
.BR ^ ).
.IP
.B match
returns the number of characters matched. For example:
.RS
match("a123ab123", ".\(**\e([a\-z]\e)") == 6
.br
mstring(1) == "b"
.RE
.SS \fIFile \fII/O
.PD
.TP .75i
.BI open( name , \ file , \ fcn )
.ns
.TP
.BI close( name )
The
.I name
argument must be a
.I bs
variable name (passed as a string).
For
.BR open() ,
the
.I file
argument
may be
.PD 0
.RS
.TP
.B 0
standard input
.TP
.B 1
standard output
.TP
.B 3
standard error.
.TP
.I filename
a string representing a filename
.TP
.BI ! command
a string beginning with an \fB!\fP representing a command to be executed
(via
.IR "sh \-c" ).
.RE
.IP
.I fcn
is one of:
.RS
.TP
.B r
read
.TP
.B w
write
.TP
.B W
write without new-line
.TP
.B a
append
.RE
.PD
.IP
After a
.BR close() ,
.I name
reverts to being an ordinary variable. The initial associations are:
.RS
.RS
open("get", 0, "r")
.br
open("put", 1, "w")
.br
open("puterr", 2, "w")
.RE
.RE
.IP
(See
.SM EXAMPLES,
below.)
.TP
.BI access( s , \ m )
executes
.IR access (2).
.TP
.BI ftype( s )
returns a single character file-type indication:
.PD 0
.RS
.TP
.B f
regular file
.TP
.B p
.SM FIFO
(named pipe)
.TP
.B d
directory
.B b
block special
.TP
.B c
character special
.RE
.SS \fITables
.PD
.TP
.B "table(name, size)"
.br
A table in
.I bs
is an associatively accessed, single-dimension array.
``Subscripts'' (called keys)
are strings (numbers are converted).
The
.I name
argument must be a
.I bs
variable name
(passed as a string).
The
.I size
argument sets the minimum number of elements to be allocated.
.I bs
prints an error message and stops on table overflow.
.TP
.B item(name, i)
.ns
.TP
.B key()
The
.I item
function accesses table elements sequentially
(in normal use, there is no orderly progression of key values).
Where the
.I item
function accesses
values, the
.I key
function accesses the ``subscript'' of the previous
.I item
call.
The
.I name
argument should not be quoted.
Since exact table sizes are not defined, the interrogation operator should be used
to detect end-of-table; for example:
.RS
.IP
table("t", 100)
.br
\ \|.\|.\|.
.br
# If
.I word
contains "party", the following expression adds one
.br
# to the count of that word:
.br
++t[word]
.br
\ \|.\|.\|.
.br
# To print out the the key/value pairs:
.br
for i = 0, ?(s = item(t, i)), ++i \ if key() \ put = key()_":"_s
.RE
.TP
.BI iskey( name , \ word )
Test whether the key
.I word
exists in the table
.I name.
Returns ``1'' if true or ``0'' if false.
.SS "\fIOdds and Ends"
.PD
.TP .75i
.BI eval( s )
The string argument is evaluated as a
.I bs
expression.
The function is handy for converting numeric strings to
numeric internal form.
.B eval()
can also be used as a crude form of indirection, as in:
.RS
.PD 0
.IP
name = "xyz"
.br
eval("++"\(ul name)
.RE
.IP
which increments the variable
.IR xyz .
In addition,
.BR eval() ,
preceded by the interrogation operator, permits
the user to control
.I bs
error conditions.
For example:
.RS
.IP
?eval("open(\e"\s-1X\s+1\e", \e"\s-1XXX\s+1\e", \e"r\e")")
.RE
.IP
returns the value zero if there is no file named ``\s-1XXX\s+1''
(instead of halting the user's program).
The following executes a
.B goto
to the label
.I L
(if it exists):
.RS
.IP
label="L"
.br
if !(?eval("goto "\(ul label)) puterr = "no label"
.RE
.PD
.TP
.BI plot( request , \ args )
The
.B plot()
function produces output on devices
recognized by
.IR plot (1G).
.IP
Some requests do not apply to all plotters.
All requests except zero and twelve
are implemented by piping characters to
.IR plot (1G).
See
.IR plot (5)
for more details.
.IP
Available
.I requests
are as follows:
.RS
.PD 0
.TP
.BI plot(0, \ term )
Further
.B plot()
output is piped into
.IR plot (1G)
with an argument of
.BI \-T term.
.TP
.B plot(4)
``erase'' the plotter.
.TP
.BI plot(2, \ string)
Label the current point with
.IR string .
.TP
\fBplot(3, \fIx1\fB, \fIy1\fB, \fIx2\fB, \fIy2\fB)
Draw the line between
.BI ( x1 , \ y1 )
and
.BI ( x2 , \ y2 ).
.TP
.BI plot(4, \ x , \ y ,\ r )
Draw a circle with center
.BI ( x , \ y )
and radius
.IR r .
.TP
\fBplot(5, \fIx1\fB, \fIy1fB, \fIx2\fB, \fIy2\fB, \fIx3\fB, \fIy3\fB)
Draw an arc (counterclockwise)
with center
.BI ( x1 , \ y1 )
and endpoints
.BI ( x2 , \ y2 )
and
.BI ( x3 , \ y3 ) .
.IP plot(6)
Not implemented.
.TP
.BI plot(7, \ x , \ y )
Make the current point
.BI ( x , \ y ) .
.TP
.BI plot(8 , \ x , \ y )
Draw a line from the current point to
.BI ( x , \ y ) .
.TP
.BI plot(9, \ x , \ y )
Draw a point at
.BI ( x , \ y ) .
.TP
.BI plot(10, \ string )
Set the line mode to
.IR string .
.TP
\fBplot(11, \fIx1\fB, \fIy1\fB, \fIx2\fB, \fIy2\fB\|)
Make
.BI ( x1 , \ y1 )
the lower-left corner of the plotting area and
.BI ( x2 , \ y2 )
the upper-right corner of the plotting area.
.TP
.BI plot(12, \fIx1\fB, \fIy1\fB, \fIx2\fB, \fIy2\fB\|)
causes subsequent coordinates to be multiplied componentwise by
.I x1
and
.I y1,
respectively, and then added to
.I x2
and
.I y2
before being plotted.
The initial scaling is
.BR "plot(12, 1.0, 1.0, 0.0, 0.0)" .
.RE
.TP
.B last(\|)
in immediate mode,
.B last()
returns the most recently computed value.
.sp
.SH EXAMPLES
Using
.I bs
as a calculator:
.nf
.PP
.RS
$ bs
# Distance (inches) light travels in a nanosecond.
186000 \(** 5280 \(** 12 / 1e9
\fB11.78496\fP
\&.\|.\|.
.sp 1v
# Compound interest (6% for 5 years on $1,000).
int = .06 / 4
bal = 1000
for i = 1 5\(**4 bal = bal + bal\(**int
bal \- 1000
\fB346.855007\fP
\&.\|.\|.
exit
.RE
.fi
.PP
The outline of a typical
.I bs
program:
.nf
.PP
.RS
# initialize things:
var1 = 1
open("read", "infile", "r")
\&.\|.\|.
# compute:
while ?(str = read)
\&.\|.\|.
next
# clean up:
close("read")
\&.\|.\|.
# last statement executed (exit or stop):
exit
# last input line:
run
.RE
.fi
.PP
.PP
Input/Output examples:
.nf
.PP
.RS
# Copy "oldfile" to "newfile".
open("read", "oldfile", "r")
open("write", "newfile", "w")
\&.\|.\|.
while ?(write = read)
\&.\|.\|.
# close "read" and "write":
close("read")
close("write")
.sp 1v
# Pipe between commands.
open("ls", "!ls \(**", "r")
open("pr", "!pr \-2 \-h \(fmList\(fm", "w")
while ?(pr = ls) .\|.\|.
\&.\|.\|.
# be sure to close (wait for) these:
close("ls")
close("pr")
.RE
.fi
.SH SEE ALSO
ed(1), grep(1), plot(1G), sh(1), access(2), printf(3S), intro(3S), plot(5)
.br
See Section\ 3M of the \f2\s-1UNIX\s+1 Interface Reference Manual\fR for a
further description of the mathematical functions.