New Antlr Parser
I'm thinking of implementing the lexer/parser using Antlr. Please join the discussion
ExpressionEvaluator 1.0.2 contains a nasty bug that throws the Exception HRESULT: 0x80131047. If you downloaded the previous release package, please re-download. Alternatively you can rebuild from the latest source or get the latest version from NuGet
ExpressionEvaluator is a lightweight, simple and free library capable of parsing and compiling simple to medium complexity C# expressions. It features a hand-written tokenizer and generates a LINQ Expression tree which is compiled into a function.
Applications for an expression parser and compiler are usually in the form of embedded code or user-defined or runtime expressions that need to be executed against runtime objects. Some uses for this library have been:
- An Experimental Music Compiler for Windows Mobile
- Dynamic data-bound XML templates
- User-defined conditional code stored in configuration files
If you have downloaded and used this library, I'd like to know about it's usage! Feel free to contact me about it.
C# does not include a built-in method to evaluate a string during runtime, like VBScript's Eval(). I wanted to be able to define a condition "x = c" where x was a property of an runtime object that would vary over calls, and c was a constant, and this condition should be defined in an XML file where it could be changed if needed. I also wanted to ensure that any further conditions could also be defined in this manner, without the need to write any code.
One of the options I found around the internet was to compile the code into a class, load it into memory and call the function through reflection, but I immediately rejected this solution as it was clunky and inelegant.
I then came across Pascal Ganaye's Eval3 library
. The library supported passing external variables through a class - just what I needed. It performed well enough (I had to modify the existing code to accommodate the equals operator) but I felt that it was a bit difficult to maintain (had to write a function for each operator-combination type) and I was trying to move away from VB.NET.
I then started working with LINQ and Expression trees and realized I could build my own parser, create an Expression tree and compile it, and even cache the function delegate for optimum speed.
With a bit of help from Wikipedia, I borrowed an implementation of Dijkstra's Shunting-yard algorithm
to handle the parsing, rewrote it in C#, threw in Expressions and had the evaluator up and running.
A NuGet package is now available here
and Sample Expressions
3/2/2014 - Added Call support, hopefully fixed some method resolution issues
2/19/2014 - Bug fix for dynamic boolean short-circuit operators && ||
2/16/2014 - Added a signing key for solutions that require Strong Named Assemblies, Indexed properties for dynamics
2/12/2014 - Improved dynamic detection
2/2/2014 - Support for binding to functions that use params
1/29/2014 - Ternary operator support (?:), support for dynamic objects and ScopeCompile
For more details see Updates
- C# style operators
- Arithmetic operators: +- * / % ^
- Relational operators: == != < > <= >=
- Logical Operators: ! & | (bitwise logic) and && || (short circuit logic)
- Expression grouping with parentheses ( )
- Index accessors [ ]
- Supports calling methods and properties and indexed properties on dynamic objects (such as ExpandoObject)
- Access external variables through a class instance, a global object, or a scope parameter supplied to the compiled function (ScopeCompile)
- Strings: enclosed in 'single quotes' and string concatenation with +
- Shorthand date literals: #any valid date format#, #Now# returns DateTime.Now
- true, false, null literals
- Declarative typing of numbers using d/f/m/l/u/ul suffixes
- Implicit conversion of numerical expressions
- Member access operator (.) for any valid expression. Access properties, fields and methods of types, objects and expressions
- Registry of external types and objects
- Recognizes some default types (bool, int, double, float, char, string, DateTime, Convert, Math)
- Allows nested function calls (x.method(y.method(z.method()), y.method2()))
This is not
a fully C#-compliant compiler, and as such features may be missing and there may be bugs or discrepancies in how the parser and compiler work. If you wish to use this library in production code do so at your own risk.