Expression Parser

This expression parser was a little pet-project of mine in 2000. It understands expressions (see explanation below). I've been using it for years to generate small reports.

Syntax

[an error occurred while processing this directive]

Download

These are the available binaries:

Development

Below are some ideas that can be added in the future

Additions:
* Logical operators:
  - xor, ^: +-priority
* for() can be extended with the following 2 syntaxes:
  - for(string): The string gets parsed at runtime and should contain an ExpressionList with 3 elements. This can be conveniently used to register iteration as just one variable string.
  - for(item in array): Should this iterate through all elements of array or just the first dimension, so that item is a slice? We could also loop the size() and keys().
* Function definitions (user functions) (for this, the IdentTable probably needs to be scoped).
* Currently, external variables (variable values set by the caller) are readonly. This could be made writable as well (this will need a change in the API). If external variables are writable, they can be used to simulate function calls (much like hardware registers). Writing a value (possibly a concatenation of values) triggers the call and reading it yields the result.
However, a convenient way to register external functions would provide this functionality as well.
These mechanisms can also be used to read/write external arrays.
* In addition to the parsetree() function, also make an xmltree() function that generates the same tree, but in XML form. (In strings, escape all control characters and non-ASCII with &#dddd;)

* When saving the parse-tree in the client, we get a problem with the global IdentTable. This can be solved in different ways, e.g.:
- Make functions that a client can call to enter and exit a scope. One could also make functions to (re-)initialize the global table to the initial state.
- Automatically enter a scope in a compound subexpression. Also the {} could be used for that. This means that the expressions should all be inside a big compound expression (as a block).
- Don't use the global IdentTable, but give a table with each evaluation.
* Take care that the evaluations are serialized (e.g. by mutexes), because results are kept in the parse-tree and should not be shared between threads.

** To overcome the above two points, the best course would be to separate the function (parse-tree) and data (node-value). These node-values can be maintained in an object, which acts like a key-value dictionary. The keys can be ids that identify the nodes in the parse-tree.
The (root-)IdentTable is still global (due to the global scope of the variables), but access to it is provided through this data-object. If necessary, locking must be performed by either the data-object or the IdentTable.
The execution will now be as follows:
1) Parse the expression.
2) Initialize an id generator visitor and send that through the parse-tree.
3) Initialize a data-object with a reference to the IdentTable.
4) Execute the parse-tree with the data-object as input. Each node can access the value of its inputs via their ids in the data-object.
The data-object could contain an hierarchical IdentTable. I.e. a global part and a local part where the local part is local to this data-object and is only used for this evaluation. There are two additional issues with this. Firstly, the update of existing variables. This should always be in the level where the original variable was found. Secondly, the creation of new variables. This could be 'always local' or 'always global' or 'dependent on a keyword, like 'var' (change default global to local) in JavaScript or 'global' (change default local to global) in PHP'.
What about a three-level IdentTable: global, thread and function/block (currently, function/block does not yet exist)?
It might be more convenient to use prefixes, like vim does (g: for global, etc).