nickle (1) - Linux Manuals
nickle: a desk calculator language
Command to display nickle
manual in Linux: $ man 1 nickle
NAME
nickle - a desk calculator language
SYNOPSIS
nickle [--help|--usage] [-f file] [-l library] [-e expr] [ script ] [--] [arg ...]
DESCRIPTION
Nickle is a
desk calculator language
with powerful programming and scripting capabilities.
Nickle supports a variety of datatypes,
especially arbitrary precision
integers, rationals, and imprecise reals.
The input language vaguely resembles C. Some things in C
which do not
translate easily are different, some
design choices have been made differently,
and a very few features are simply missing.
USAGE
An un-flagged argument is treated as a Nickle script,
and replaces standard input. Any remaining arguments
following the script are placed in the Nickle string array
argv for programmatic inspection. When invoked without an
expression or script argument, Nickle reads from
standard input, and writes to standard output.
Options are as follows:
- --help,--usage
-
Print a help/usage message and exit. This is a built-in
feature of Nickle's ParseArgs module, and thus will also be
true of Nickle scripts that use this library.
- -f,--file file
-
Load
file
into Nickle before beginning execution.
- -l,--library library
-
Load
library
into Nickle before beginning execution.
See below for a description of the library facility.
- -e,--expr expr
-
Evaluate
expr
before beginning execution.
- --
-
Quit parsing arguments and pass the remainder, unevaluated, to
argv.
SYNTAX
To make the input language more
useful in an interactive setting, newline only terminates
statements at ``reasonable'' times. Newline terminates either
expressions or single statements typed by the user (with
the exception of a few statements which require lookahead:
notably if() and twixt(), which have an optional
else part). Inside compound
statements or function definitions, only a ;
terminates statements. This approach is convenient and does
not appear to cause problems in normal use.
The syntax of Nickle programs is as follows.
In this description,
name
denotes
any sequence of letters, digits and _ characters
not starting with a digit;
E
denotes any
expression;
S
denotes any statement;
and
T
denotes any type.
The syntax
X,X,...,X
denotes one or more comma-separated Xs, unless
otherwise indicated.
Comments:
C-style comments are enclosed in /* and */,
and shell-style comments are
denoted by a leading # at the start of a line.
Operands:
- real number
-
Can include exponent, need not
include decimal point or sign.
Will be treated as exact rationals.
If a trailing decimal part contains an opening
curly brace, the brace is silently ignored; if it
contains a curly-bracketed trailing portion,
it is treated as a repeating decimal.
`Floating point'' constants
are currently represented internally as rationals:
for floating constants with a given precision
(and an infinite-precision exponent), use the
imprecise() builtin function described below.
- octal number
-
Start with a 0 (e.g., 014 is the same as 12).
- hexidecimal number
-
Start with "0x" (e.g., 0x1a is the same as 26).
- string
-
As in C. String constants
are surrounded by double-quotes. Backslashed
characters (including double-quotes) stand for themselves, except "\n"
stands for newline, "\r" for carriage return,
"\b" for backspace, "\t" for tab and "\f" for formfeed.
- name
-
A variable reference.
- name() name(E,E,...,E)
-
A function call with zero or more arguments.
Functions are fully call-by-value: arrays and structures
are copied rather than being referenced as in C.
- desc name T name = value
-
Definition expressions: a new name is made available,
with the value of the definition being the value
of the initializer in the second form, and
uninitialized in the first form. The descriptor
desc is not optional: it consists of any combination
of visibility, storage class or type (in that order).
See QUALIFIERS immediately below for a description of these qualifiers.
A structured value expression is
also possible: see VALUES below.
-
In addition to being able to initialize a definition with
a Nickle value, C-style array, structure, and union definitions
are also allowed: For example, the following
int[*,*] name = {{0,1},{2,3}}
int[2,2] name = {{0...}...}
are permitted with the obvious semantics. This is the context
in which the dimensions in a type may be expressions: see the
discussion of array types above. See the discussion of
array and structure values for array and structure initializer syntax.
QUALIFIERS
A declaration or definition may be qualified,
as in C, to indicate details of programmatic behavior.
Unlike in C, these qualifiers, while optional, must appear in the
given order.
Visibility:
- public
-
Any definition expression (function definition,
variable definition, type definition) can be qualified
with public to indicate that the name being defined should
be visible outside the current namespace, and
should be automatically imported. See Namespaces
below for further info.
- protected
-
Any definition expression (function definition,
variable definition, type definition) can be qualified
with protected to indicate that the name being defined should
be visible outside the current namespace, but
should not be made available by import declarations. See Namespaces
below for further info.
Lifetime:
- auto
-
An auto object is local to a particular block: its lifetime
is at least the lifetime of that block.
An auto object with an initializer
will be re-initialized each time it is evaluated.
This is the default lifetime for local objects.
- static
-
A static object is local to a particular function definition:
its lifetime is at least the lifetime of that definition.
A new static object will be created
each time its enclosing function definition is evaluated.
-
In Nickle, the keyword static has to do only
with lifetime (like the use of static inside C functions), not with visibility
(which is handled by separate qualifiers as described
above, not like the use of static in global scope in C).
- global
-
A global object is global to the entire program: its
lifetime is the lifetime of the program. A global object
will be created and initialized when its definition is
first seen. This is the default lifetime for global
objects.
-
The distinction between static and global lifetime in
Nickle is not possible in C, because C functions are
not first class objects with nested scope. When deciding
which to use in a Nickle program, think about what should
happen if a definition is re-evaluated.
OPERATORS
Here are the basic Nickle operators, grouped in order
of decreasing precedence:
- A[E,E,...,E]
-
Refers to the E'th element of the
array expression A,
or the E1'th/E2'th/etc
element of a multi-dimensional array.
Both arrays of arrays ala C and multidimensional
arrays ala NAWK are possible.
- struct.tag
-
Structure dereference.
- struct->tag
-
Structure pointer dereference ala C.
- =============
-
- ++ --
-
Unary increment/decrement. May be either postfix or prefix.
- -
-
Unary negate
- ! E
-
Logical negation.
- E !
-
Factorial. Requires a non-negative integer argument.
- * E
-
Pointer dereference.
- & E
-
Reference construction.
- =============
-
- (U) E
-
Construct a value of union type with tag U and
value E.
- =============
-
- **
-
Exponentiation. Both operands may be fractional.
The left operand must be non-negative unless the right
operand is integer. The result type is the
type of the left operand
if the right operand is integer, and real
otherwise.
-
This is the only known type-unsound feature
of Nickle: an expression like 2 ** -3 will
statically be of type integer, but dynamically
will generate a rational result. This may
cause a runtime type error later on: consider
int x = 2 ** -3;
- =============
-
- * / // %
-
Times, divide, integer divide, and remainder.
The right operand of the last three operators must be nonzero.
The result type of the division operator will
always be at least rational: the result type
of the integer division operator will always be
int. This is a notable departure from C, where integer division is
implied by integer operands.
Integer division is defined by
x // y == y > 0 ? floor (x / y) : ceil(x / y)
The remainder is always non-negative and is defined by:
by
x % y = x - (x // y) * y
- =============
-
- + -
-
Addition and subtraction.
- =============
-
- << >>
-
Bitwise left and right shift with integer
operands. Negative right
operands work as expected. These operators
are defined by
x << y = x * 2 ** y
x >> y = x // 2 ** y
Another way to look at this is that negative
left operands are considered to be in
an infinite twos-complement representation
(i.e., sign-extended to infinity), with
right shift sign-extending its left operand.
- =============
-
- <= >= < >
-
Relational operators.
- =============
-
- == !=
-
Equality operators.
- =============
-
Finally, in order of decreasing precedence:
- &
-
Bitwise AND. Negative
operands are considered to be in
an infinite twos-complement representation
(i.e., sign-extended to infinity).
- ^
-
Bitwise XOR. Negative operands
as in bitwise AND.
- |
-
Bitwise OR. Negative operands
as in bitwise AND.
- &&
-
Short-circuit logical AND.
- ||
-
Short-circuit logical OR.
- E ? E : E
-
Conditional expression: if first expression
is logical true, value is second expression,
else third.
- fork E
-
Create (and return) a thread. See Thread
below for details.
- = += -= *= /= //= %= **= <<= >>= ^= &= |=
-
Assignment operators. Left-hand-side must be
assignable.
x <op>= y
is equivalent to
x = x <op> y
- E , E
-
Returns right-hand expression.
TYPES
The type declaration syntax of Nickle more strongly resembles
the ``left'' variant of the Java syntax than the C syntax.
Essentially, a type consists of:
- poly integer rational real string continuation void
-
A base type of the language. Type void is actually
only usable in certain contexts, notably function returns.
It is currently implemented as a ``unit'' type ala ML,
and thus has slightly different behavior than in C.
Type poly is the supertype of all other types (i.e., it
can be used to inhibit static type checking), and is the
default type in most situations where a type need not appear.
- file semaphore thread
-
Also builtin base types, but integral to
the File and Thread ADTs: see below.
More About Types:
Nickle supports polymorphic data: As an expresion is evaluated, a
data type is chosen to fit the result. Any Nickle object may be
statically typed, in which case bounds violations will be flagged as errors
at compile time.
Polymorphic variables and functions do not place restrictions on the assigned
data type; this is the default type for all objects.
- poly
-
This describes the union of all datatypes. A variable with this type
can contain any data value.
- int
-
Arbitrary precision integers.
- rational
-
Arbitrary precision rational numbers.
- real
-
Arbitrary exponent precision floating point numbers. As
many computations cannot be carried out exactly as rational
numbers, Nickle implements non-precise arithmetic using its
own machine-independent representation for floating point
numbers. The builtin function imprecise(n) generates
a real number with 256 bits of precision from the number
n, while imprecise(n,p) generates a real number with p
bits of precision.
- T[]
-
An array of type T, of one or more dimensions. There are no
zero-dimensional arrays in Nickle.
- T[*]
-
A one-dimensional array of type T. Unlike in C, the dimension of an array
is never part of its type in Nickle. Further, arrays and pointers
are unrelated types in Nickle.
- T[*,*,...,*]
-
A two or more dimensional array of type T. The stars ``*'' are not
optional. As the previous paragraphs
make clear, ``T[]'' is not a zero-dimensional array.
- T[E,E,...,E]
-
In definition contexts, integer values may be given
for each dimension of an array context. These are strictly
for value-creation purposes, and are not part of the type.
An array type is determined only by the base type and number
of dimensions of the array.
- T0() T0(T,T,...,T)
-
A function returning type T0. A function accepts 0
or more arguments.
- T0() T0(T,T,...,T ...)
-
A function accepting zero or more required
arguments, plus an arbitrary number of optional
arguments. The second sequence of three dots (ellipsis) is
syntax, not metasyntax: see the description
of varargs functions for details.
- *T
-
A pointer to a location of type T.
Pointer arithmetic in Nickle operates only
upon pointers to arrays: the pointer must be
of the correct type, and may never stray out
of bounds. A pointer
may either point to some location or be null (0). As
in C, the
precedence of ``*'' is lower than the precedence of
``[]'' or ``()'': use parenthesis as needed.
- struct {T name; T name; ...}
-
A structure with fields of the given name and type.
The types T are optional: in their absence,
the type of the field is poly.
- union {T name; T name; ...}
-
A ``disjoint union'' of the given types. This
is more like the variant record type of Pascal
or the datatype of ML than the C union type: the
names are tags of the given type, exactly one of
which applies to a given value at a given time.
- (T)
-
Parentheses for grouping.
Typedef:
As in C, new type names may be created with the typedef
statement. The syntax is
typedef T typename;
where T is a Nickle type. The resulting typename may
be used anywhere a type is expected.
VALUES
Values of the base types of Nickle are as expected.
See the syntax for constants above. Values of
type file, semaphore, and continuation may currently be
created only by calls to builtin functions: no Nickle constants
of these types exist.
As noted in
TYPES above, Nickle has several kinds of ``structured value'':
arrays, functions, pointers, structures and disjoint unions.
All of these have some common properties.
When created, all of the component values are
uninitialized (unless otherwise specified). Attempts
to use an uninitialized value will result
in either a compile-time error or a runtime exception.
Arrays:
- [E]
-
creates a (zero-based) array with E elements.
E must be non-negative.
- [E]{V,V,...,V}
-
Creates an array with E elements,
initialized to the Vs. If there are
too few initializers, remaining elements
will remain uninitialized.
- [E]{V,V,...,V...}
-
The second ellipsis (three dots) is syntax, not
metasyntax. Create an array with E elements. The
first elements in the array will be initialized
according to the Vs, with any remaining elements
receiving the same value as the last V. This
syntax may be used in the obvious fashion with any of the array
initializers below.
- [*]{V,V,...,V}
-
Creates an initialized array with exactly as
many elements as initializers. There
must be at least one initializer.
- [E,E,...,E] [*,*,...,*]
-
Creates multidimensional arrays.
Integer expressions and "*"
cannot be mixed: an array's dimensions
are entirely either specified or unspecified
by the definition. These arrays may also
be created initialized: see next paragraph for
initializer syntax.
- (T[E]) (T[E,E,...,E]) (T[E]){E,E,...,E}
-
- (T[E,E,...,E]){{E,...},...,{E,...}}
-
Alternate syntax for creating arrays of type T.
The initializers, in curly braces, are optional.
The number of initializers must be less than or equal
to the given number of elements in each dimension.
For multidimensional arrays, the extra
curly braces per dimension in the initializer
are required; this is unlike C, where they are
optional.
- (T[*]){E,E,...,E} (T[*,*,...,*]){{E,...},...,{E,...}}
-
Creates arrays of type T, with each dimension's size given
by the maximum number of initializers in any subarray
in that dimension.
Pointers:
- 0
-
The null pointer, in contexts where a pointer
is required.
- &V &A[E,E,...,E] &S.N
-
Creates a pointer to the given variable, array element,
or structure member. The type of the pointer will
be *T, where T is the type of the object pointed to.
- *P
-
The value pointed to by pointer P. This can
be viewed or modified as in C.
Functions:
- (T func(){S;S;...S;}) (T func(T name,T name,...T name){S;S;...S;})
-
Function expression: denotes a function of zero or more
formal parameters with the given types and names, returning
the given result type. The function body is given by
the curly-brace-enclosed statement list. All types are
optional, and default to poly. As noted above, functions
are strictly call-by-value: in particular, arrays and structures
are copied rather than referenced.
- T function name(T name,T name,...,T name){S;S;...S;}
-
Defines a function of zero or more arguments. Syntactic
sugar for
T(T,T,...T) name = (T func(T name,T name,...T name){S;S;...S;});
- T function name(T name, T name ...)
-
The ellipsis here is syntax, not metasyntax: if
the last formal argument to a function is followed
by three dots, the function may be called with
more actuals than formals. All ``extra'' actuals
are packaged into the array formal of
the given name, and typechecked against the
optional type T of the last argument (default poly).
Structures:
- (struct { T name; T name; ...T name; }){name = E; name = E; ...name=E;}
-
Create a value of a structured type. The named fields
are initialized to the given values, with
the remainder uninitialized. As indicated, initialization is
by label rather than positional as in C.
Unions:
- (union { T name; T name; ...T name; }.name) E
-
Create a value of the given union type, the variant
given by .name, and the value given by E.
E must be type-compatible with name.
STATEMENTS
The statement syntax very closely resembles
that of C. Some additional syntax has been
added to support Nickle's additional functionality.
- E;
-
Evaluates the expression.
- {S ... S}
-
Executes the enclosed statements in order.
- if (E) S
-
Basic conditional.
- if (E) S
-
Conditional execution.
- else S
-
Else is allowed, with the usual syntax and semantics.
In particular, an else binds to the most recent applicable
if() or twixt().
- while (E) S
-
C-style while loop.
- do S while (E);
-
C-style do loop.
- for (opt-E; opt-E; opt-E) S
-
C-style for loop.
- switch (E) { case E: S-list case E: S-list ... default: S-list }
-
C-style case statement. The case expressions
are not required to be constant expressions, but may
be arbitrary. The first case evaluating to the switch
argument is taken, else the default if present, else the switch body
is skipped.
- twixt(opt-E; opt-E) S
-
- twixt(opt-E; opt-E) S else S
-
If first argument expression evaluates to true,
the body of the twixt() and then the second argument expression
will be evaluated. If the first argument expression
evaluates to false, the else statement will be executed
if present. Otherwise, the entire twixt() statement will be skipped.
The twixt() statement guarantees that all of these events
will happen in the specified
order regardless of the manner in which the twixt() is
entered (from outside) or exited, including exceptions,
continuations, and break. (Compare with Java's ``finally'' clause.)
- try S;
-
- try S catch name (T name, ...) { S; ... };
-
- try S catch name (T name, ...) { S; ... } ... ;
-
Execute the first statement S. If an exception
is raised during execution, and the name matches
the name in a catch block, bind the formal parameters in the
catch block to the actual parameters of the exception,
and execute the body of the catch block. There may be
multiple catch blocks per try. Zero catches, while legal,
is relatively useless. After completion of a catch block,
execution continues after the try clause.
As with else, a catch binds to the most recent applicable try-catch
block.
- raise name(name, name, ..., name)
-
Raise the named exception with zero or more arguments.
- ;
-
The null statement
- break;
-
Discontinue execution of the nearest enclosing for/do/while/switch/twixt statement. The leave expression will be executed as the
twixt statement is exited.
- continue;
-
Branch directly to the conditional test of the nearest enclosing
for/do/while statement.
- return E;
-
Return value E from the nearest enclosing function.
Namespaces:
Like Java and C++ Nickle has a notion of
namespace,
a collection of names with partially restricted
visibility. In Nickle, namespaces are created with
the
namespace
command.
- opt-P namespace N { S ... }
-
Places all names defined in the statements S into a namespace
named N. The optional qualifier P may be the
keyword public, but
beware: this merely indicates that the name N
itself is visible elsewhere in the current scope, and has nothing
to do with the visibility of items inside the namespace.
- extend namespace N { S ... }
-
Reopen the given namespace N, and extend it with
the names defined as public in the given statements S.
-
Names defined inside the namespace are invisible outside
the namespace unless they are qualified with the keyword
public. Public names may be referred to using a path notation:
namespace::namespace::...::namespace::name
refers to the given name as defined inside the
given set of namespaces. The double-colon syntax
is unfortunate, as it is slightly different in meaning
than in C++, but all the good symbols were taken, and
it is believed to be a feature that the namespace separator
is syntactically different than the structure operator. In
Java, for example, the phrase
name.name.name
is syntactically ambiguous: the middle name may be either
a structure or a namespace.
- import N;
-
The name N must refer to a namespace: all public names
in this namespace are brought into the current scope
(scoping out conflicting names).
BUILTINS
Nickle has a collection of standard functions built in.
Some of these are written in C, but many are written in Nickle.
Several collections of
functions have associated builtin datatypes: their namespaces,
together with their types, should be viewed as ADTs.
Top-Level Builtins:
- int printf(string fmt, poly args...)
-
Calls File::fprintf(stdout, fmt, args ...) and
returns its result.
- string function gets ()
-
Calls File::fgets(stdin) and returns its result.
- string function scanf (string fmt, *poly args...)
-
Calls File::vfscanf(stdin, fmt, args) and returns its result.
- string function vscanf (string fmt, (*poly)[*] args)
-
Calls File::vfscanf(stdin, fmt, args) and returns its result.
- real imprecise(rational value)
-
See the discussion of type real above.
- real imprecise(rational value, int prec)
-
See the discussion of type real above.
- int string_to_integer(string s)
-
- int atoi(string s)
-
The argument s is a signed digit string, and
the result is the integer it represents.
If the string s is syntactically a hexadecimal,
octal, binary, or explicit base-10 constant,
treat it as such.
- int string_to_integer(string s, int base)
-
- int atoi(string s, int base)
-
Treat s as a string of digits in the given base.
A base of 0 acts as with no base argument.
Otherwise, base specification syntax in the string is ignored.
- int putchar(int c)
-
Place the given character on the standard output
using File::putc(c, stdout), and return its result.
- int sleep(int msecs)
-
Try to suspend the current thread for at least msecs milliseconds.
Return 1 on early return, and 0 otherwise.
- int exit(int status)
-
Exit Nickle with the given status code. Do not return anything.
- int dim(poly[*] a)
-
Given a one-dimensional array a, dim() returns the number
of elements of a.
- int[] dims(poly[] a)
-
Given an arbitrary array a, dims() returns an array
of integers giving the size of each dimension of a.
Thus, dim(dims(a)) is the number of dimensions
of a.
- *poly reference(poly v)
-
Given an arbitrary value v, ``box'' that value
into storage and return a pointer to
the box.
- rational string_to_real(string s)
-
- rational atof(string s)
-
Convert the real constant string s into
its associated real number.
- number abs(real v)
-
Return the absolute value of v. The result type chosen
will match the given context.
- int floor(real v)
-
Return the largest integer less than or equal to v.
This will fail if v is a real and the precision is
too low.
- int ceil(real v)
-
Return the smallest integer greater than or equal to v.
This will fail if v is a real and the precision is
too low.
- int exponent(real v)
-
Return the exponent of the imprecise real v.
- rational mantissa(real v)
-
Return the mantissa of the imprecise real
v, as a rational m with 0 <= m <= 0.5 .
- int numerator(rational v)
-
Return the numerator of the rational
number v: i.e., if v = n/d in reduced form,
return n.
- int denominator(rational v)
-
Return the denominator of the rational
number v: i.e., if v = n/d in reduced form,
return d.
- int precision(real v)
-
Return the number of bits of precision
of the mantissa of the imprecise real number v.
- int sign(real v)
-
Return -1 or 1 as v is negative
or nonnegative.
- int bit_width(int v)
-
Return the number of bits required to represent abs(v)
internally.
- int is_int(poly v)
-
Type predicate.
- int is_rational(poly v)
-
Numeric type predicates are inclusive: e.g., is_rational(1)
returns 1.
- int is_number(poly v)
-
Type predicate.
- int is_string(poly v)
-
Type predicate.
- int is_file(poly v)
-
Type predicate.
- int is_thread(poly v)
-
Type predicate.
- int is_semaphore(poly v)
-
Type predicate.
- int is_continuation(poly v)
-
Type predicate.
- int is_array(poly v)
-
Type predicate.
- int is_ref(poly v)
-
Type predicate: checks for pointer type. This
is arguably a misfeature, and may change.
- int is_struct(poly v)
-
Type predicate.
- int is_func(poly v)
-
Type predicate.
- int is_void(poly v)
-
Type predicate.
- int gcd(int p, int q)
-
Return the GCD of p and q. The result is always positive.
- int xor(int a, int b)
-
Return a ^ b . This is mostly a holdover from before
Nickle had an xor operator.
- poly setjmp(continuation *c, poly retval)
-
The setjmp() and longjmp() primitives together with the continuation type
form an ADT useful for nearly arbitrary transfers of
flow-of-control. The setjmp() and longjmp() builtins
are like those of C, except that the restriction
that longjmp() always jump upwards is removed(!):
a continuation saved via setjmp() never becomes invalid
during the program lifetime.
-
The setjmp() builtin saves the current location and
context into its continuation pointer argument, and
then returns its second argument.
- void longjmp(continuation c, poly retval)
-
The longjmp() builtin
never returns to the call site, but instead returns from
the setjmp() that created the continuation, with
return value equal to the second argument of longjmp().
- string prompt
-
The prompt printed during interactive use when
at top-level. Default "> ".
when waiting for the rest of a statement
or expression, and when debugging, respectively.
Default values are "> ", "+ ", and "- ".
- string prompt2
-
The prompt printed during interactive use when
waiting for the rest of a statement or expression.
Default "+ ".
- string prompt3
-
The prompt printed during interactive use when
debugging.
Default "- ".
- string format
-
The printf() format for printing top-level values. Default "%g".
- string version
-
The version number of the Nickle implementation currently
being executed.
- string build
-
The build date of the Nickle implementation currently
being executed, in the form "yyyy/mm/dd", or "?" if
the build date is unknown for some reason.
- file stdin
-
Bound to the standard input stream.
- file stdout
-
Bound to the standard output stream.
- file stderr
-
Bound to the standard error stream.
Exceptions:
A few standard exceptions are predeclared
and used internally by Nickle.
- exception uninitialized_value(string msg)
-
Attempt to use an uninitialized value.
- exception invalid_argument(string msg, int arg, poly val)
-
The arg-th argument to a builtin function had invalid value
val.
- exception readonly_box(string msg, poly val)
-
Attempt to change the value of a read-only quantity
to val.
- exception invalid_array_bounds(string msg, poly a, poly i)
-
Attempt to access array a at index i is out of bounds.
- exception divide_by_zero(string msg, real num, real den)
-
Attempt to divide num by den with den == 0.
- exception invalid_struct_member(string msg, poly struct, string name)
-
Attempt to refer to member name of the object struct, which does
not exist.
- exception invalid_binop_values(string msg, poly arg1, poly arg2)
-
Attempt to evaluate a binary operator with args arg1 and arg2,
where at least one of these values is invalid.
- exception invalid_unop_values(string msg, poly arg)
-
Attempt to evaluate a unary operator with invalid argument arg.
Builtin Namespaces:
- Math
-
The math functions available in the Math
namespace
are implemented in a fashion
intended to be compatible with the C library.
Please consult the appropriate manuals for further
details.
- real pi
-
Imprecise constant giving the value of the
circumference/diameter ratio of the circle
to the
default precision of 256 bits.
- protected real e
-
Imprecise constant giving the value of the
base of natural logarithms
to the
default precision of 256 bits.
Since e is protected, it must be
referenced via Math::e, in order
to avoid problems with using the
fifth letter of the alphabet at
top level.
- real function sqrt(real v)
-
Returns the square root of v.
- real function cbrt(real v)
-
Returns the cube root of v.
- real function exp(real v)
-
Returns e**v.
- real function log(real a)
-
Returns v such that e**v == a.
Throws an invalid_argument exception if
a is non-positive.
- real function log10(real a)
-
Returns v such that 10**v == a.
Throws an invalid_argument exception if
a is non-positive.
- real function log2(real a)
-
Returns v such that 2**v == a.
Throws an invalid_argument exception if
a is non-positive.
- real function pi_value(int prec)
-
Returns the ratio of the circumference
of a circle to the diameter, with prec
bits of precision.
- real function sin(real a)
-
Returns the ratio of the opposite
side to the hypotenuse of angle a of
a right triangle, given in radians.
- real function cos(real a)
-
Returns the ratio of the adjacent
side to the hypotenuse of angle a of
a right triangle, given in radians.
- void function sin_cos(real a, *real sinp, *real cosp)
-
Returns with sin(a) and cos(a) stored in the locations
pointed to by sinp and cosp respectively. If either
pointer is 0, do not store into that location. May be slightly
faster than calling both trig functions independently.
- real function tan(real a)
-
Returns the ratio of the opposite
side to the adjacent side of angle a of
a right triangle, given in radians.
Note that tan(pi/2) is not currently an error:
it will return a very large number dependent
on the precision of its input.
- real function asin(real v)
-
Returns a such that sin(a) == v.
- real function acos(real v)
-
Returns a such that cos(a) == v.
- real function atan(real v)
-
Returns a such that tan(a) == v.
- real function atan2(real x, y)
-
Returns a such that tan(a) == x / y.
Deals correctly with y == 0.
- real function pow(real a, real b)
-
The implementation of the ** operator.
- File
-
The namespace File provides operations on file values.
- int function fprintf(file f, string s, ....)
-
Print formatted values to a file, as with
UNIX stdio library fprintf().
fprintf() and printf() accept a reasonable sub-set of the stdio
library version: %c, %d, %e, %x, %o, %f, %s, %g work
as expected, as does %v to smart-print a value. Format modifiers
may be placed between the percent-sign and the format letter
to modify formatting. There are a lot of known bugs with
input and output formatting.
-
Format Letters:
- %c
-
Requires a small integer argument (0..255), and formats as
an ASCII character.
- %d
-
Requires an integer argument, and formats as an integer.
- %x
-
Requires an integer argument, and formats as a
base-16 (hexadecimal) integer.
- %o
-
Requires an integer argument, and formats as a
base-8 (octal) integer.
- %e
-
Requires a number argument, and formats in scientific
notation.
- %f
-
Requires a number argument, and formats in fixed-point
notation.
- %s
-
Requires a string argument, and emits the string literally.
- %g
-
Requires a number, and tries to pick a precise and readable
representation to format it.
Format Modifiers:
- digits
-
All format characters will take an integer format modifier
indicating the number of blanks in the format field for the
data to be formatted. The value will be printed right-justified
in this space.
- digits.digits
-
The real formats will take a pair of integer format modifiers
indicating the field width and precision (number of chars
after decimal point) of the formatted value. Either integer
may be omitted.
- -
-
A precision value indicating infinite
precision.
- *
-
The next argument to fprintf() is an integer indicating
the field width or precision of the formatted value.
- file function string_write()
-
Return a file which collects written values
into a string.
- int function close(file f)
-
Close file f and return an indication of success.
- int function flush(file f)
-
Flush the buffers of file f and return an indication of success.
- int function getc(file f)
-
Get the next character from file f and return it.
- int function end(file f)
-
Returns true if file f is at EOF, else false.
- int function error(file f)
-
Returns true if an error is pending on file f,
else false.
- int function clear_error(file f)
-
Clears pending errors on file f, and
returns an indication of success.
- file function string_read(string s)
-
Returns a virtual file whose contents are the
string s.
- string function string_string(file f)
-
Return the string previously written into the file f,
which should have been created by string_read() or
string_write(). Behavior on other files is
currently undefined.
- file function open(string path, string mode)
-
Open the file at the given path with the given
mode string, ala UNIX stdio fopen(). Permissible
modes are as in stdio: "r", "w", "x", "r+", "w+"
and "x+".
- integer function fputc(integer c, file f)
-
Output the character c to the output file f, and return
an indication of success.
- integer function ungetc(integer c, file f)
-
Push the character c back onto the input file f, and return
an indication of success.
- integer function setbuf(file f, integer n)
-
Set the size of the buffer associated with file f to
n, and return n.
- string function fgets (file f)
-
Get a line of input from file f, and return the
resulting string.
- file function pipe(string path, string[*] argv, string mode)
-
Start up the program at the given path, returning a file
which is one end of a "pipe" to the given process. The
mode argument can be "r" to read from the pipe or
"w" to write to the pipe. The argv argument is an array
of strings giving the arguments to be passed to the program,
with argv[0] conventionally being the program name.
- int function print (file f, poly v, string fmt, int base, int width, int prec, string fill)
-
Print value v to file f in format fmt with the given base, width,
prec, and fill. Used internally by File::fprintf();
- int function fscanf(file f, string fmt, *poly args...)
-
Fill the locations pointed to by the array args with values
taken from file f according to string fmt. The format specifiers
are much as in UNIX stdio scanf(): the "%d", "%e", "%f",
"%c" and "%s" specifiers are supported with the expected
modifiers.
- int function vfscanf (file f, string fmt, (*poly)[*] args)
-
Given the file f, the format fmt, and the array of arguments args,
fscanf() appropriately.
- Thread
-
The namespace Thread supports various operations
useful for programming with
threads,
which provide concurrent flow of control in the shared
address space. There is one piece of special
syntax associated with threads.
-
- fork(E)
-
Accepts an arbitrary expression, and evaluates it
in a new child thread. The parent thread receives
the thread as the value of the fork expression.
-
The remainder of the Thread functions are fairly standard.
- int function kill(thread list...)
-
Kills every running thread in the array list. With
no arguments, kills the currently running thread.
Returns the number of threads killed.
- int function trace(poly list...)
-
Shows the state of
every running thread in the array list. With
no arguments, traces the default continuation.
Returns the number of threads traced.
- int function cont()
-
Continues execution of any interrupted threads,
and returns the number of continued threads.
- thread function current()
-
Return the current thread.
- int function list()
-
Reports the currently running thread to stdout.
- int function get_priority(thread t)
-
Reports the priority of the given thread.
- thread function id_to_thread(int id)
-
Returns the thread with the given id,
if found, and 0 otherwise.
- poly function join(thread t)
-
Waits for thread t to terminate, and returns whatever
it returns.
- int function set_priority(thread t, int i)
-
Attempts to set the priority of thread t to level i,
and returns the new priority. Larger priorities
mean more runtime: a task with higher priority will
always run instead of a lower priority task. Threads
of equal highest priority will be pre-emptively multitasked.
- Semaphore
-
The Semaphore namespace encapsulates operations on the
semaphore built-in ADT. A semaphore is used
for thread synchronization. Each signal() operation
on the semaphore awakens the least-recent thread to
wait() on that semaphore. The ``count'' of waiting
processes may be set at semaphore creation time.
- semaphore function new(int c)
-
Create a new semaphore with an initial count c of waiting
processes. If c is positive, it means that c threads
may wait on the semaphore before one blocks. If c is
negative, it sets a count of threads which must be
waiting on the semaphore before further waits will
not block.
- semaphore function new()
-
Call semaphore(0) and return its result.
- int signal(semaphore s)
-
Increment semaphore s. If s is non-positive, and
some thread is blocked on s, release the least-recently-blocked
thread. Return 1 on success.
- int wait(semaphore s)
-
Decrement semaphore s. If s is negative, block until released.
Return 1 on success.
- int test(semaphore s)
-
Test whether wait() on semaphore s would cause the current
thread to block. If so, return 0. Otherwise,
attempt to decrement s, and return 1 if successful.
- String
-
The String namespace contains a few basic operations
on the string ADT.
- int function length(string s)
-
Returns the number of characters in s.
- string function new(int c)
-
Returns as a string the single character c.
- string function new(int cv[*])
-
Returns a string comprised of the characters of cv.
- int function index(string t, string p)
-
Returns the integer index of the pattern string p in
the target string t, or -1 if p is not a substring of
t.
- string function substr(string s, int i, int l)
-
Returns the substring of string s starting with the
character at offset i (zero-based) and continuing
for a total of l characters. If l is negative,
the substring will consist of characters preceding
rather than succeeding i.
- PRNG
-
The PRNG namespace provides pseudo-random number generation
and manipulation. The core generator is the RC4 stream
cipher generator, properly bootstrapped. This provide a stream of
cryptographically-secure pseudo-random bits at reasonable amortized cost.
(But beware, initialization is somewhat expensive.)
- void function srandom(int s)
-
Initialize the generator, using the (arbitrarily-large) integer as
a seed.
- void function dev_srandom(int nbits)
-
Initialize the generator, using nbits bits of entropy obtained
from some reasonable entropy source. On UNIX systems, this
source is /dev/urandom. Asking for more initial entropy than
the system has may lead either to bootstrapping (as on UNIX) or to
hanging, so use cautiously.
- int function randbits(int n)
-
Returns an n-bit pseudo-random number, in
the range 0..(2**n)-1. Useful for things
like RSA.
- int function randint(int n)
-
Returns a pseudo-random number in the range 0..n-1.
- void function shuffle(*(poly[*]) a)
-
Performs an efficient in-place true shuffle (c.f. Knuth) of
the array a.
- Command
-
The Command namespace is used by the top-level commands
as described below. It is also occasionally useful in
its own right.
- string library_path
-
Contains the current library search path, a colon-separated
list of directories to be searched for library files.
- int function undefine(string name)
-
Implements the top-level undefine
command. Remove the name denoted by string name from the
namespace. This removes all visible definitions of
the name.
- int function undefine(string[*] names)
-
Remove each of the names in the array names from the
namespace. This removes all visible definitions of
each name.
- int function delete(string name)
-
Attempt to remove the command with the given string name from the top-level
command list, and return 1 if successful.
- int function lex_file(string path)
-
Attempt to make the file at the given path the current source of
Nickle code, and return 1 if successful. Note that this
effectively ``includes'' the file by pushing it onto a stack
of files to be processed.
- int function lex_library(string filename)
-
Like lex_file(), but searches the directories given by the
library_path
variable for the first file with the given filename.
- int function lex_string(string code)
-
Attempt to make the Nickle code contained in the string code be
the next input.
- int function edit(string[*] names)
-
Implements the top-level edit command. The names in the
array are a path of namespace names leading to the symbol
name, which is last.
- int function new(string name, poly func)
-
Binds function func to the top-level command
string name: i.e., makes it part of the
top-level command vocabulary.
- int function new_names(string name, poly func)
-
Binds function func to the top-level command
string name: i.e., makes it part of the
top-level command vocabulary. Unlike new(),
the string names given to func at the top
level are passed unevaluated as an array of
string names
or as a single string name.
- int function pretty_print(file f, string[*] names)
-
Implements the top-level print command. Each
of the passed name strings is looked up and the
corresponding code printed to file f.
- int function display(string fmt, poly val)
-
Uses printf() to display the value val in
format fmt.
- History
-
Nickle maintains a top-level value history, useful as an adjunct
to command-line editing when calculating. The
History namespace contains functions to access this history.
- int function show(string fmt)
-
Implements the history top-level command with no arguments.
Show the most recent history values with format fmt.
- int function show(string fmt, int count)
-
Implements the history top-level command with one argument.
Show the last count history values with format fmt.
- int function show(string fmt, int first, int last)
-
Implements the history top-level command with two arguments.
- poly function insert(poly val)
-
Insert val in the history list, and return it.
- Environ
-
Many operating systems have some notion of ``environment variables.''
The Environ namespace contains functions to manipulate these.
- int function check(string name)
-
Returns 1 if the variable with the given name is
in the environment, and 0 otherwise.
- string function get(string name)
-
Attempts to retrieve and return the value of
the environment variable with the given
name. Throws an invalid_argument exception if
the variable is not available.
- int function unset(string name)
-
Attempts to unset the environment variable with the given
name, and returns an indication of success.
- string function set(string name, string value)
-
Attempts to set the environment variable with the given
name to the given value, and returns an indication of success.
COMMANDS
Nickle has a set of commands which may be
given at the top level.
- quit
-
Exit Nickle.
- quit E
-
Exit Nickle with integer status code E.
- undefine NAME {,NAME}
-
Remove these names from the system.
- load E
-
Load a file given by the string name E.
- library E
-
Load a library given by the string name E. See the discussion of the
NICKLEPATH environment variable in ENVIRONMENT
below, and the discussion of Command::library_path above.
- E # E
-
Print expr1 in base expr2 .
- print NAME
-
Display a formatted version of the object denoted by NAME.
Comments and original formating are lost.
If NAME is a variable, print the type as well as the value.
- edit NAME
-
Invoke $EDITOR on the named object, and
re-incorporate the results of the edit. This is most
useful with functions.
- history
-
Display the 10 most recently printed values. They can be accessed
with $n where n is the number displayed to the
right of the value in this list.
- history E
-
Display the E
most recent history values.
- history E,E
-
Display history values from the first integer E through
the second.
DEBUGGER
When an unhandled exception reaches top level during
execution, the user receives a dash prompt, indicating
that debug mode is active. In this mode, the command-line
environment is that in which the unhandled exception was raised.
In addition a number
of debugging commands are available to the user:
- trace
-
Get a stack backtrace showing the current state,
as with the GDB where command.
- up
-
Move up the stack (i.e., toward the top-level expression) ala GDB.
- down
-
Move down the stack (i.e., toward the current context) ala GDB.
- done
-
Leave debugging mode,
abandoning execution.
-
In addition, the Debug namespace is scoped in in
debugging mode. This is primarily of
use in debugging Nickle itself.
- collect()
-
Run the garbage collector.
- dump(function)
-
Print the compiled byte code for function.
ENVIRONMENT
- EDITOR
-
The editor used by the edit command,
described in COMMANDS above.
- NICKLERC
-
The location of the user's .nicklerc
file, which will be loaded at the beginning
of nickle execution if possible.
- HOME
-
Used to find the user's .nicklerc
if NICKLERC is not set.
- NICKLEPATH
-
A colon-separated path whose elements are directories
containing Nickle code. The library command and the -l flag,
described above, search this path for a filename matching the
given file. The default library path in the
absence of this variable is /usr/share/nickle.
- NICKLESTART
-
The filename of the file that should be loaded as a bootstrap
on Nickle startup. The default in the absence of this variable
is to load /usr/share/nickle/builtin.5c.
EXAMPLES
An example (taken from the bc manual:
real function exponent(real x) {
real a = 1;
int b = 1;
real s = 1;
int i = 1;
while (1) {
a = a * x;
b = b * i;
real c = a / b;
if (abs(c) < 1e-6)
return s;
s = s + c;
i++;
}
}
defines a function to compute an approximate value of the exponential
function e ** x and
for (i = 1; i < 10; i++)
printf ("%g\n", exponent (i));
prints approximate values of the exponential function of the first
ten integers.
VERSION
This document describes version 1.99.2 of nickle,
as well as some newer features. It
was distributed with version 2.69 of nickle.
BUGS
See the discussion of the type of the exponentiation
operator ** above.
Due to a difficult-to-remove grammar ambiguity,
it is not possible to use a bare assignment expression
in an array initializer: it is confused with a structure
initializer. For example:
> int x = 0;
> (int[*]){x = 1}
-> (int[*]) { x = 1 }
Non array initializer
The workaround is to parenthesize the assignment expression:
> (int[*]){(x = 1)}
[1]{1}
Because this is so rare, so hard to fix, and so easy to work around, this
bug is unlikely to be fixed anytime soon.
There are a lot of known bugs with input and output formatting.
The obvious stuff works, other stuff does not.
The semantics of division are unfortunately different from
those of C. This is arguably because C is broken in this
area: we cannot currently see any obvious fix.
C allows automatic implicit coercion of floating to
integral types, but we consider this a misfeature.
The implementation has not been thoroughly tested.
AUTHOR
Nickle is the work of Keith Packard <keithp [at] keithp.com>
and Bart Massey <bart_massey [at] iname.com>.
Nickle is
Copyright 1988-2006 Keith Packard and Bart Massey. All
Rights Reserved.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall
be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the authors
or their institutions shall not be used in advertising or
otherwise to promote the sale, use or other dealings in this
Software without prior written authorization from the
authors.