| Package Name: | PrsParser |
| Package Coordinator: | Andy Salnikov (salnikov@slac.stanford.edu) |
| Creation Date: | April 2000 |
| Last Modification: | See History file |
This package contains a generic parser class for C++-like (or maybe even Python-like) expressions. The complete grammar is in the prs_parser.y.
Parser supports operation in three basic types - bool, int and double, and one complex type - list. List is basically a heterogeneous sequence which can contain basic types or other lists. Bool and int types are called integral types, integral types and double make arithmetic types.
Parser understands literals ot these types:
| bool | `true' or `false' |
| int | decimal (100), octal (0100), hex (0x100), bit (0b100) |
| double | standard notations |
| list | '[' ... ']' |
Inside the brackets in list literal there can be arbitrary number of expressions or literals, separated by commas, for example these are the valid list literals:
[] [ 1, 2 ] [ a, b, c ] [ 1, 0.1234, true, [ x, y, [] ], z ] [ [], [ [] ], [ [ [] ] ], [ [ [ [] ] ] ] ]
Type conversion works as in C++ between arithmetic types. The list can be converted to bool only, empty lists are converted to 'false', non-empty to 'true'. No conversions from arithmetic typed to lists are defined.
Parser understands identifiers - sequence of letters, digits or underscores starting with letter or underscore. The type and value of each identifier is determined by something external to the parser (see "Using Parser" below). There may be also "dotted" identifiers - a pair of the identifiers with a `.' between (dotted ids cannot be assigned.) Exmples of good identifiers:
a a_1 someNotSoLongIdentifier thisIdentifierIsSomewhatLonger.AndHasADotInItSoLooksLikeObjectWithMember part.energy
All supported expressions are listed in the order of their priorities.
Functions usualy take some parameters and return result. The number of parameters can be fixed or variable. The type of parameters can be restricted for some functions. Usual type promotion works in most cases.
Many ordinary functions, such as abs(x), can take a list as argument too. For the list they work by applying the same function for each element and returning resulting l;ist of the same shape. For example, the call
abs ( [-1, 1, [-2, [2, 3], -3]] )
will return [1, 1, [2, [2, 3], 3]]. Such functions are marked as "**" in the table below.
Here is the list of functions supported by parser n alphabetic order:
| Name | arg # | arg types | ret type | Description | |
|---|---|---|---|---|---|
| Notes: | |||||
| *) min/max functions when take few arguments evaluate minimum/maximum value of all arguments. When there is only one argument, it must be a list and returned value is a minumum/maximum value of elements in the list. Returned type is determined by the most promoted type of the arguments or the list elements. [each argument or list element must have scalar type] | |||||
| **) function can take a list as argument and is applied to each element in the list | |||||
| abs(x) | 1 | any | same | absolute value of argument | |
| acos(x) | 1 | double,** | double | arccosine of argument | |
| asin(x) | 1 | double,** | double | arcsine of argument | |
| atan(x) | 1 | double,** | double | arctangent of argument | |
| atan2(y,x) | 2 | double,** | double | arctangent of y/x | |
| ceil(x) | 1 | double,** | double | nearest int not less than x | |
| cos(x) | 1 | double,** | double | cosine of argument | |
| cosh(x) | 1 | double,** | double | hyperbolic cosine of argument | |
| exp(x) | 1 | double,** | double | exponentiation of argument | |
| fabs(x) | 1 | double,** | double | absolute value as a double | |
| floor(x) | 1 | double,** | double | neares int not greater than x | |
| fmod(x,y) | 2 | double,** | double | remainder of x/y | |
| hypot(x,y) | 2 | double,** | double | sqrt(x*x + y*y) | |
| index(x,y) | 2 | 1: list 2: any |
int | index of first y inside list x, or -1 | |
| log(x) | 1 | double,** | double | base E logarithm of argument | |
| log10(x) | 1 | double,** | double | base 10 logarithm of argument | |
| len(l) | 1 | list | int | length of the list | |
| max(...) * | var | any | scalar | max element | |
| min(...) * | var | any | scalar | min element | |
| pow(x,y) | 2 | double,** | double | x ** y | |
| rindex(x,y) | 2 | 1: list 2: any |
int | index of last y inside list x, or -1 | |
| sin(x) | 1 | double,** | double | sine of argument | |
| sinh(x) | 1 | double,** | double | hyperbolic sine of argument | |
| sqrt(x) | 1 | double,** | double | square root of argument | |
| tan(x) | 1 | double,** | double | tangent of argument | |
| tanh(x) | 1 | double,** | double | hyperbolic tangent of argument | |
There are two main classes which define user interface of the package: PrsParser and PrsResult. PrsParser is the class which performs expression parsing, every PrsParser object "serves" exactly one expression, which is supplied to the parser in its constructor. After construction the parser object holds the pointer to the expression tree, which is returned by the tree() method of PrsParser. If parsing generated errors that pointer is zero. The pointer has type PrsNode*. To evaluate the expression one needs to call the method eval() for this pointer, which returns an object of type PrsResult. PrsResult encapsulates both the type and the value of the result. In the case the evaluation was unsuccessfull the type and the value of the result is undefined. To check that the evaluation was successful one can use ok() method of PrsResult.
To evaluate the expression parser has to know the "meaning" of the identifiers used in expressions. This meaning is communicated to the parser through another object which user has to provide in PrsParser constructor, this object has to inherit from the class PrsAttrAccessorFactory. This object is used to created "getters" and "setters" objects (objects of the classes PrsAttrGetter and PrsAttrSetter) which are used by the parser. "Setter" objects are called for the identifiers which appear on the left side of the assignment operator, "getters" are called for all other identifiers.
More or less complete example of PrsParser usage can be found in the test program testPrsParser.cc. Note that factory/getter/setter interface is very flexible, you can do whatever you want with this, not just simple dictionary lookup as in the example above.