Previous: general-information Up: ../slides.html Next: about-variables
The parsing package supports input of keywords, switches, integer numbers, floating-point numbers, quoted and unquoted text strings, file names, and special tokens (such as comma). It is desirable to permit arbitrary arithmetic expressions whereever numeric values are expected, and in order to support this with minimal runtime overhead, the convention is adopted that a right parenthesis met where a number is expected will cause input to be collected up to and including a matching left parenthesis, and that parenthesized string will then be passed to a powerful expression parser for evaluation. The expression parser supports a complete FORTRAN 77 numeric and Boolean (LOGICAL) expression grammar, with extensions from the Ada, C, Pascal, and Reduce languages. In addition, it supports vector expressions and named variables. Variable names begin with a letter optionally followed by one or more letters, digits, underscores, or dots. There is no variable name length restriction, and letter case is NOT significant. Names are looked up first in the built-in function name table, and if not found there, then in the variable name table. Thus, all function names are effectively reserved words, and attempts to assign values to them or use them as scalar variables will result in an error return. This reservation of some names is required because size and type declarations of variables are not required; when an unknown name is encountered, it is automatically entered into the symbol table with a flag marking it as undefined. Immediate symbol table installation is necessary because this parser requires no lookahead at all, and the use of a variable on the left-hand side of an assignment cannot be recognized until possibly many more tokens have been parsed (e.g. "V(very_long_subscript_expression) = value"). Thus, variables come into existence when they are assigned values, and disappear only when the symbol table is reinitialized. Operators are applied according to assigned precedences, with those of highest precedence being applied first. For example, since multiply (*) has higher precedence than plus (+), the expression (A + B*C) is evaluated as ((A) + (B*C)), NOT as ((A + B)*C). Unless otherwise noted, operators are left associative, meaning that in a sequence of operators of identical precedence, they are applied in order from left to right; thus (A*B*C*D) is GUARANTEED to be evaluated as (((A*B)*C)*D). Parentheses can always be used to force evaluation of subexpressions first, and are recommended for clarity; operator precedences are not the same in all programming languages, and subtle errors can creep in if one is not careful. The operator precedences are as follows: Level 0 (lowest precedence): Unsigned_Named_Literal, Unsigned_Subscripted_Named_Literal, Unsigned_Integer_Literal, Unsigned_Floating_Literal Level 1: (right associative) Assign_Op = = (lhs becomes rhs) | += (lhs becomes lhs + rhs) | -= (lhs becomes lhs - rhs) | *= (lhs becomes lhs * rhs) | /= (lhs becomes lhs / rhs) Level 2: Equiv_Op = .EQV. | .NEQV. Level 3: Disjunctive_Op = .OR. | .XOR. Level 4: Conjunctive_Op = .AND. Level 5: NOT_Op = .NOT. Level 6: Rel_Op = == (equal) | .EQ. (equal) | <> (not equal) | # (not equal) | .NE. (not equal) | < (less than) | .LT. (less than) | > (greater than) | .GT. (greater than) | >= (greater than or equal) | .GE. (greater than or equal) | <= (less than or equal) | .LE. (less than or equal) Level 7: Add_Op = + (including unary +) | - (including unary -) Level 8: Mul_Op = * | / | >> (binary integer logical shift right) | << (binary integer logical shift left) Level 9: (right associative) Exp_Op = ** Level 10: Function_Op = ABS | ACOS | ACOSH | AINT | ANINT | ASIN | ASINH | ATAN | ATAN2 | ATANH | BINOM | CASE | CEIL | COS | COSD | COSH | COTAN | COTAND | CROSS | DIM | DOT | ENORM | ERF | ERFC | EXP | FLOAT | FLOOR | GAMMA | IF | IFIX | INORM | INT | LGAMMA | LOG | LOG10 | LOG2 | MAX | MIN | MOD | NINT | PROD | REAL | ROUND | SIGN | SIN | SIND | SINH | SIZE | SQRT | SUM | SWITCH | TAN | TAND | TANH | TRUNC | VEC Note that assignment is not a statement, but instead is a legal expression whose value is that of the right-hand side. Thus 3 + (A = 5) sets A to 5 and evalutes to 8. Assigning a scalar or vector to a variable creates it and defines its size; subsequent assignment can change the size. Vector elements are represented in the usual way "name(subscriptexpression)", where the subscript expression ranges in value from 1 up to the number of elements in the vector. Integer division truncates toward 0, for example: +11/5 = +2 -11/5 = -2 MOD is defined for integer division by the relations MOD(A,B) = A - (A/B)*B Note that A MOD B has the sign of A. Some examples are MOD( 13, 5) = 3 MOD(-13, 5) = -3 MOD( 13,-5) = 3 MOD(-13,-5) = -3 The function operators are the same as the real-arithmetic generic functions in FORTRAN 77, with these additions: ACOSH(x) Inverse hyperbolic cosine of x ASINH(x) Inverse hyperbolic sine of x ATANH(x) Inverse hyperbolic tangent of x BINOM(n,m) Binomial coefficient, n!/((n-m)!m!) CASE(n,e1,e2,...,ek,edefault) e1 if n = 1, e2 if n = 2, ..., ek if n = k, and for all other values of n, edefault. CEIL(x) Smallest integer not less than x COSD(x) Cosine for angle x in degrees COTAN(x) Cotangent for angle x in radians COTAND(x) Cotangent for angle x in degrees CROSS(v1,v2) Right-handed cross product of 3-element vectors v1 and v2 DOT(v1,v2) Dot product of vectors v1 and v2 ENORM(e1,e2,...,en) Euclidean norm of n-vector (n > 0), equivalent to SQRT(e1**2 + e2**2 + ... + en**2), but without possibility of destructive overflow or underflow ERF(x) Error function ERFC(x) Complementary error function (1 - ERF(x)) FLOOR(x) Largest integer not greater than x GAMMA(x) Gamma function IF(b,ethen,eelse) Ethen if b is TRUE, and otherwise, eelse. INORM(e1,e2,...,en) Infinity norm of n-vector (n > 0), equivalent to MAX(ABS(e1),ABS(e2),..., ABS(en)) LGAMMA(x) Natural logarithm of absolute value of gamma function LOG2(x) Logarithm of x to base 2 PROD(e1,e2,...,en) Product of arguments, e1*e2*...*en. ROUND(x) Nearest INTEGER to x, and rounding for half integral values is away from zero SIND(x) Sine for angle x in degrees SIZE(v) Number of elements in vector v SUM(e1,e2,...,en) Sum of arguments, e1+e2+...+en SWITCH(b1,e1,b2,e2,...,bk,ek,edefault) Ej, where bj is the first b which is TRUE, and edefault if none of the b's are TRUE. TAND(x) Tangent for angle x in degrees TRUNC(x) Same as FLOOR and INT VEC(e1,e2,...,en) Vector of the concatenation of the elements e1, e2, ..., en. Equivalent to [e1,e2,..., en] Scalar values are treated as vectors of one element. Vectors may be generated by a value list in square brackets (e.g. [1,cosd(60),sqrt(27)]), or by a special function VEC (e.g. VEC(1,cosd(60),sqrt(27))). The latter will be useful primarily for those machines whose character sets lack square brackets. A vector whose components are themselves vectors is not a matrix, but simply a vector formed by the concatenation of elements in its components. Thus, [[1,2],[3,4]] is equivalent to [1,2,3,4]. With the few exceptions noted below, functions operating on vectors apply component-wise, returning a vector of the same size. Thus, SQRT[3,4,5] is equivalent to [SQRT(3),SQRT(4),SQRT(5)]. Binary operators and functions (ATAN2, BINOM, and MOD) apply component-wise as well, with the rule that if the two vector arguments have differing numbers of elements, the shorter one is implicitly extended by its last element. This choice means that no special action need be taken for scalar-vector multiplication; thus, [1,2,3]*10 evaluates to [10,20,30]. The functions ENORM, INORM, MAX, MIN, PROD, SIZE and SUM permit a variable number of arguments (1 or more), and ALWAYS return a scalar result. If the arguments are vectors, they are simply expanded into their components. MAX([1,2],[-7,3]) therefore evaluates to 3. Note that ENORM([1,2],[-7,3]) does not return a vector of 2 Euclidean norm values, but a single value which is the norm of the vector [1,2,-7,3]. To get the former result, one would write [ENORM([1,2]),ENORM([-7,3])]. The function DOT requires exactly two vector arguments, and returns the dot product of the two as a scalar value. ENORM(V) is equivalent to SQRT(DOT(V,V)), but is not subject to destructive overflow or underflow which may occur in the latter form. Similarly, INORM(V) is equivalent to MAX(ABS(V)). The function CROSS requires exactly two vector arguments, each of which MUST have 3 elements, and returns a 3-element vector which is the right-handed cross product of the two vectors. It is the only function for which a size requirement applies to its argument vectors. CASE, IF, and SWITCH are treated specially. The selector values (argument 1 for CASE and IF, arguments 1, 3, 5, ... for SWITCH) use only the first component of their possibly vector values, and return the selected argument as a vector result. For example, CASE(2,[1],[-2,2],[3,-3,3],0) returns the vector [-2,2].