bs - a compiler/interpreter for modest-sized programs
bs [file [args]]
bs is a remote descendant of BASIC and SNOBOL4 with some C language
added. 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 trace and dump statements, and useful
run-time error messages all simplify program testing. Furthermore,
incomplete programs can be debugged; inner functions can be tested
before outer functions have been written, and vice versa.
If file is specified on the command-line, it is used for input before
any input is taken from the keyboard. By default, statements read
from file are compiled for later execution. Likewise, statements
entered from the keyboard are normally executed immediately (see
compile and execute below). Unless the final operation is assignment,
the result of an immediate expression statement is printed.
bs programs are made up of input lines. If the last character on a
line is a \, the line is continued. bs accepts lines of the following
A label is a name (see below) followed by a colon. A label and a
variable can have the same name.
A bs statement is either an expression or a keyword followed by zero
or more expressions. Some keywords (clear, compile, !, execute,
include, ibase, obase, and run) are always executed as they are
expression The expression is executed for its side effects (value,
assignment, or function call). The details of
expressions follow the description of statement types
break break exits from the innermost for/while loop.
clear Clears the symbol table and compiled statements. clear
is executed immediately.
Succeeding statements are compiled (overrides the
Hewlett-Packard Company - 1 - HP-UX Release 11i: November 2000
immediate execution default). The optional expression
is evaluated and used as a file name for further input.
A clear is associated with this latter case. compile
is executed immediately.
continue continue transfers to the loop-continuation of the
current for/while loop.
dump [name] The name and current value of every non-local variable
is printed. Optionally, only the named variable is
reported. After an error or interrupt, the number of
the last statement is displayed. The user-function
trace is displayed after an error or stop that occurred
in a function.
edit A call is made to the editor selected by the EDITOR
environment variable if it is present, or ed(1) if
EDITOR is undefined or null. If the file argument is
present on the command line, file is passed to the
editor as the file to edit (otherwise no file name is
used). Upon exiting the editor, a compile statement
(and associated clear) is executed giving that file
name as its argument.
Return to system level. The expression is returned as
execute Change to immediate execution mode (an interrupt has a
similar effect). This statement does not cause stored
statements to execute (see run below).
for name = expression expression statement
for name = expression expression
for expression , expression , expression statement
for expression , expression , expression
next The 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).
Hewlett-Packard Company - 2 - HP-UX Release 11i: November 2000
fun f([a, ...]) [v, ...]
nuf 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 cannot be nested. Calling an
undefined function is permissible; see function calls
freturn A way to signal the failure of a user-written function.
See the interrogation operator (?) below. If
interrogation is not present, freturn merely returns
zero. When interrogation is active, freturn transfers
to that expression (possibly by-passing intermediate
goto name Control is passed to the internally stored statement
with the matching label.
ibase n ibase sets the input base (radix) to n. The only
supported values for n are the constants 8, 10 (the
default), and 16. Hexadecimal values 10-15 are entered
as a-f. A leading digit is required (i.e., f0a must be
entered as 0f0a). ibase (and obase discussed below)
are executed immediately.
if expression statement
fi The statement (first form) or group of statements
(second form) is executed if the expression evaluates
to non-zero. The strings 0 and "" (null) evaluate as
zero. In the second form, an optional else provides
for a second group of statements to be executed when
the first group is not. The only statement permitted
on the same line with an else is an if; only other fis
can be on the same line with a fi. The concatenation
of else and if into an elif is supported. Only a
single fi is required to close an if ... elif ...
[ else ... ] sequence.
expression must evaluate to a file name. The file must
contain bs source statements. Such statements become
part of the program being compiled. include statements
cannot be nested.
obase n obase sets the output base to n (see ibase above).
Hewlett-Packard Company - 3 - HP-UX Release 11i: November 2000
onintr onintr provides program control of interrupts. In the
first form, control passes to the label given, just as
if a goto had been executed at the time onintr was
executed. The effect of the statement is cleared after
each interrupt. In the second form, an interrupt
causes bs to terminate.
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.
run The random number generator is reset. Control is
passed to the first internal statement. If the run
statement is contained in a file, it should be the last
stop Execution of internal statements is stopped. bs
reverts to immediate mode.
The 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/returns is printed. Each return decrements the
trace expression value.
while expression statement
next while is similar to for except that only the
conditional expression for loop-continuation is given.
! shell command
An immediate escape to the shell.
# ... This statement is ignored (treated as a comment).
name A name is used to specify a variable. Names are
composed of a letter (uppercase or lowercase)
optionally followed by letters and digits. Only the
first six characters of a name are significant. Except
for names declared in 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 built-in function
Hewlett-Packard Company - 4 - HP-UX Release 11i: November 2000
name ( [expression [ , expression] ... ] )
Functions can be called by a name followed by the
arguments in parentheses separated by commas. Except
for built-in functions (listed below), the name must be
defined with a fun statement. Arguments to functions
are passed by value. If the function is undefined, the
call history to the call of that function is printed,
and a request for a return value (as an expression) is
made. The result of that expression is taken to be the
result of the undefined function. This permits
debugging programs where not all the functions are yet
defined. The value is read from the current input
name [ expression [ , expression ] ... ]
This syntax is used to reference either arrays or
tables (see built-in 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; a[1,2]
is the same as a. The truncated expressions are
restricted to values between 0 and 32767.
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 e followed by a possibly signed
string Character strings are delimited by " characters. The \
escape character allows the double quote (\"), new-line
(\n), carriage return (\r), backspace (\b), and tab
(\t) characters to appear in a string. Otherwise, \
stands for itself.
( expression ) Parentheses are used to alter the normal order of
( expression , expression [ , expression ... ] ) [ expression ]
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.
( False, True )[ a == b ]
has the value True if the comparison is true.
Hewlett-Packard Company - 5 - HP-UX Release 11i: November 2000
? expression 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 examples in the
Programming Tips section below), the result of the eval
built-in function, and for checking the return from
user-written functions (see freturn). An interrogation
``trap'' (end-of-file, etc.) causes an immediate
transfer to the most recent interrogation, possibly
skipping assignment statements or intervening function
- expression The result is the negation of the expression.
++ name Increments the value of the variable (or array
reference). The result is the new value.
-- name Decrements the value of the variable. The result is
the new value.
!expression The logical negation of the expression. Watch out for
the shell escape command.
expression operator expression 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.
Binary Operators (in increasing precedence):
= = is the assignment operator. The left operand must be
a name or an array element. The result is the right
operand. Assignment binds right to left, all other
operators bind left to right.
_ _ (underscore) is the concatenation operator.
&&&& | &&&& (logical AND) has result zero if either of its
arguments are zero. It has result one if both of its
arguments are non-zero; | (logical OR) has result zero
if both of its arguments are zero. It has result one
if either of its arguments is non-zero. Both operators
treat a null string as a zero.
<<<< <<<<= >>>> >>>>= == !=
The relational operators (<<<<: less than, <<<<=: less than
or equal, >>>>: greater than, >>>>=: greater than or equal,
==: equal to, !=: not equal to) return one if their
arguments are in the specified relation, or return zero
otherwise. Relational operators at the same level
extend as follows: a>>>>b>>>>c is equivalent to a>b & b>c. A
Hewlett-Packard Company - 6 - HP-UX Release 11i: November 2000
string comparison is made if both operands are strings.
+ - Add and subtract.
* / % Multiply, divide, and remainder.
Dealing with arguments
arg(i) is the value of the i-th actual parameter on the
current level of function call. At level zero, arg
returns the i-th command-line argument (arg(0) returns
narg() returns the number of arguments passed. At level zero,
the command argument count is returned.
abs(x) is the absolute value of x.
atan(x) is the arctangent of x. Its value is between -PI/2 and
ceil(x) returns the smallest integer not less than x.
cos(x) is the cosine of x (radians).
exp(x) is the exponential function of x.
floor(x) returns the largest integer not greater than x.
log(x) is the natural logarithm of x.
rand() is a uniformly distributed random number between zero
sin(x) is the sine of x (radians).
sqrt(x) is the square root of x.
size(s) the size (length in bytes) of s is returned.
format(f, a) returns the formatted value of a. f is assumed to be a
format specification in the style of printf(3S). Only
the %...f, %...e, and %...s types are safe. Since it
is not always possible to know whether a is a number or
Hewlett-Packard Company - 7 - HP-UX Release 11i: November 2000
a string when the format call is coded, coercing a to
the type required by f by either adding zero (for e or
f format) or concatenating (_) the null string (for s
format) should be considered.
index(x, y) returns the number of the first position in x that any
of the characters from y matches. No match yields
trans(s, f, t) Translates characters of the source s from matching
characters in f to a character in the same position in
t. Source characters that do not appear in f are
copied to the result. If the string f is longer than
t, source characters that match in the excess portion
of f do not appear in the result.
substr(s, start, width)
returns the sub-string of s defined by the starting
position and width.
mstring(n) The pattern is a regular expression according to the
Basic Regular Expression definition (see regexp(5)).
mstring returns the n-th (1 <= n <= 10) substring of
the subject that occurred between pairs of the pattern
symbols \( and \) for the most recent call to match.
To succeed, patterns must match the beginning of the
string (as if all patterns began with ^). The function
returns the number of characters matched. For example:
match("a123ab123", ".*\([a-z]\)") == 6
mstring(1) == "b"
open(name, file, function)
close(name) name argument must be a bs variable name (passed as a
string). For the open, the file argument can be:
1. a 0 (zero), 1, or 2 representing standard
input, output, or error output, respectively;
2. a string representing a file name; or
3. a string beginning with an ! representing a
command to be executed (via sh -c). The
function argument must be either r (read), w
(write), W (write without new-line), or a
(append). After a close, name reverts to
being an ordinary variable. If name was a
pipe, a wait() is executed before the close
completes (see wait(2)). The bs exit command
does not do such a wait. The initial
Hewlett-Packard Company - 8 - HP-UX Release 11i: November 2000
open("get", 0, "r")
open("put", 1, "w")
open("puterr", 2, "w")
Examples are given in the following section.
access(s, m) executes access() (see access(2)).
ftype(s) returns a single character file type indication: f for
regular file, p for FIFO (i.e., named pipe), d for
directory, b for block special, or c for character
A table in bs is an associatively accessed, single-
dimension array. ``Subscripts'' (called keys) are
strings (numbers are converted). The name argument
must be a bs variable name (passed as a string). The
size argument sets the minimum number of elements to be
allocated. bs prints an error message and stops on
table overflow. The result of table is name.
key() The item function accesses table elements sequentially
(in normal use, there is no orderly progression of key
values). Where the item function accesses values, the
key function accesses the ``subscript'' of the previous
item call. It fails (or in the absence of an
interrogate operator, returns null) if there was no
valid subscript for the previous item call. The 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:
# If word contains "party", the following expression adds one
# to the count of that word:
# To print out the the key/value pairs:
for i = 0, ?(s = item(t, i)), ++i if key() put = key()_":"_s
If the interrogation operator is not used, the result
of item is null if there are no further elements in the
table. Null is, however, a legal ``subscript''.
Hewlett-Packard Company - 9 - HP-UX Release 11i: November 2000
iskey tests whether the key word exists in the table
name and returns one for true, zero for false.
Odds and ends
eval(s) The string argument is evaluated as a bs expression.
The function is handy for converting numeric strings to
numeric internal form. eval can also be used as a
crude form of indirection, as in:
name = "xyz" eval("++"_ name)
which increments the variable xyz. In addition, eval
preceded by the interrogation operator permits the user
to control bs error conditions. For example:
?eval("open(\"X\", \"XXX\", \"r\")")
returns the value zero if there is no file named XXX
(instead of halting the user's program). The following
executes a goto to the label L (if it exists):
if !(?eval("goto "_ label)) puterr = "no label"
If the tplot command is available, the plot function
produces output on devices recognized by tplot. The
requests are as follows:
plot(0, term) causes further
plot output to
be piped into
tplot with an
argument of -
can be up to 40
plot(1) ``erases'' the
plot(2, string) labels the
Hewlett-Packard Company - 10 - HP-UX Release 11i: November 2000
plot(3, x1, y1, x2, y2) draws the line
plot(4, x, y, r) draws a circle
plot(5, x1, y1, x2, y2, x3, y3) draws an arc
plot(6) is not
plot(7, x, y) makes the
plot(8, x, y) draws a line
plot(9, x, y) draws a point
plot(10, string) sets the line
mode to string.
plot(11, x1, y1, x2, y2) makes (x1,y1)
the lower left
corner of the
and (x2,y2) the
corner of the
plot(12, x1, y1, x2, y2) causes
x1 (y1) and
then added to
Hewlett-Packard Company - 11 - HP-UX Release 11i: November 2000
x2 (y2) before
1.0, 1.0, 0.0,
Some requests do not apply to all plotters. All
requests except zero and twelve are implemented by
piping characters to tplot.
Each statement executed from the keyboard re-invokes
tplot, making the results unpredictable if a complete
picture is not done in a single operation. Plotting
should thus be done either in a function or a complete
program, so all the output can be directed to tplot in
a single stream.
last() in immediate mode, last returns the most recently
LC_COLLATE determines the collating sequence used in evaluating
LC_CTYPE determines the characters matched by character class
expressions in regular expressions.
If LC_COLLATE or LC_CTYPE is not specified in the environment or is
set to the empty string, the value of LANG is used as a default for
each unspecified or empty variable. If LANG is not specified or is
set to the empty string, a default of "C" (see lang(5)) is used
instead of LANG. If any internationalization variable contains an
invalid setting, bs behaves as if all internationalization variables
are set to "C". See environ(5).
International Code Set Support
Single-byte character code sets are supported.
Using bs as a calculator ($ is the shell prompt):
# Distance (inches) light travels in a nanosecond.
186000 * 5280 * 12 / 1e9
# Compound interest (6% for 5 years on $1,000).
Hewlett-Packard Company - 12 - HP-UX Release 11i: November 2000
int = .06 / 4
bal = 1000
for i = 1 5*4 bal = bal + bal*int
bal - 1000
The outline of a typical bs program:
# initialize things:
var1 = 1
open("read", "infile", "r")
while ?(str = read)
# clean up:
# last statement executed (exit or stop):
# last input line:
# Copy file oldfile to file newfile.
open("read", "oldfile", "r")
open("write", "newfile", "w")
while ?(write = read)
# close "read" and "write":
# Pipe between commands.
open("ls", "!ls *", "r")
open("pr", "!pr -2 -h 'List'", "w")
while ?(pr = ls) ...
# be sure to close (wait for) these:
The graphics mode (plot ...) is not particularly useful unless the
tplot command is available on your system.
Hewlett-Packard Company - 13 - HP-UX Release 11i: November 2000
bs is not tolerant of some errors. For example, mistyping a fun
declaration is difficult to correct because a new definition cannot be
made without doing a clear. The best solution in such a case is to
start by using the edit command.
ed(1), sh(1), access(2), printf(3S), stdio(3S), lang(5), regexp(5).
See Section (3M) for a further description of the mathematical
pow() is used for exponentiation - see exp(3M));
bs uses the Standard I/O package.
Hewlett-Packard Company - 14 - HP-UX Release 11i: November 2000