- SPEEDTRAP ALERT for Android
- Simple geo calculations
- Expression parser and evaluator (.NET, C#)
- Start - simple example
- Variables, properties, arrays and collections
- Functions and methods
- Operators
- Reference
- Something about iterating through UTF-16 Unicode strings (.NET, C#)
- Few words about toolkit:ExpanderView (XAML, .NET, C#, Windows Phone)
Using parser - variables, properties, arrays and collections
Name of variable or property in expression must start with letter or '_' character and may have any Unicode alphanumeric character (including surrogates) optionally modified by diacritical marks or '_' character. Elements of arrays or collections are accessed by indexes or keys written in square brackets. Example of expression: "MyVar + myClass.SomeProperty + MyArray[0,1]". Here MyVar, myClass, MyArray are variables, SomeProperty is a property, MyArray[0,1] is an array element.
There are two actions with variables, properties and array/collection elements that may occur during evaluation: retrieving value and assigning value. These actions take place in delegates passed to the AleTerm.Evaluate method. Full syntax of AleTerm.Evaluate method is:
public bool Evaluate(out AleTermResult result, TermEvaluate userEvaluate = null, TermAssign userAssign = null)
Retrieving value takes place in userEvaluate delegate. Syntax of this delegate is:
public delegate void TermEvaluate(AleTerm term, AleTermEvaluateArgs e);
where term is AleTerm instance which has executed delegate. e parameter contains information about the object whose value is retrieved.
using AleProjects.AleLexer.AleParser; using AleProjects.AleLexer; ... string myVar = "some value"; int[,] matrix = new int[,] { { 10, 11, 12, 13 }, { 14, 15, 16, 20 }, { 27, 28, 29, 40 } }; private class MyClass { public string SomeProperty { get; set; } } MyClass myClass = new MyClass() { SomeProperty = "property value"; }; private void OnEvaluate(AleTerm term, AleTermEvaluateArgs e) { /* VARIABLES * e.Instance is null * e.Name - name of variable (in uppercase when we ignore case) * e.NameHash - hash of e.Name (obtained by GetHashCode()) * e.Indexes is null when we evaluate variable * e.Result - stores value of variable on exit */ if (e.Instance == null) { if (e.NameHash == -1770187129 && e.Name == "MYVAR") e.Result = myVar; else if (e.NameHash == -413117458 && e.Name == "MYCLASS") e.Result = myClass; else if (e.NameHash == 614904363 && e.Name == "MYARRAY")) e.Result = matrix; else { // error - no variable with such name e.SetError(AleTermResult.ERROR_UNKNOWNVARIABLE, term.Token.StartInOrigin); } return; } /* MEMBERS OF CLASSES (class operator '.') * e.Instance - instance of class. * e.Name - name of class property (in uppercase when we ignore case) * e.NameHash - hash of e.Name (obtained by GetHashCode()) * e.Indexes is null when we evaluate class property * e.Result - stores value of property or result of method */ if (!String.IsNullOrEmpty(e.Name)) { if (e.Instance is MyClass) { MyClass _myClass = e.Instance as MyClass; if (e.NameHash = 1760601946 && e.Name == "SOMEPROPERTY") e.Result = _myClass.SomeProperty; else e.SetError(AleTermResult.ERROR_UNKNOWNPROPERTY, term.Token.StartInOrigin); } else e.SetError(AleTermResult.ERROR_UNKNOWNVARIABLE, term.Token.StartInOrigin); return; } /* ELEMENTS OF ARRAYS AND COLLECTIONS (index operator) * e.Instance - instance of array or collection. * e.Name == "" * e.NameHash == 0 * e.Indexes is List<object> with indexes of array or keys of collection * e.Result - stores value of member */ Type typ = e.Instance.GetType(); if (typ.IsArray && typ.FullName == "System.Int32[,]") { if (e.Indexes.Count != 2 && e.SetError(AleTermResult.ERROR_INVALIDINDEXES, term.Token.StartInOrigin)) return; int[,] _matrix = e.Instance as int[,]; try { e.Result = _matrix[Convert.ToInt32(e.Indexes[0]), Convert.ToInt32(e.Indexes[1])]; } catch { e.SetError(AleTermResult.ERROR_INVALIDINDEXES, term.Token.StartInOrigin); } } else e.SetError(AleTermResult.ERROR_UNKNOWNVARIABLE, term.Token.StartInOrigin); } ... AleExpressionParser AP = new AleExpressionParser(); AP.Options = AleExpressionParser.OPTION_IGNORECASE; AP.InitOperations(AleExpressionParser.OPERATIONS_STANDARDSET); AP.Text = "MyVar + myClass.SomeProperty + MyArray[0,1]"; AleTerm term = AP.Parse(); AleTermResult result; if (term.Evaluate(out result, OnEvaluate)) ..... ...
Assigning is initiated by assignment operators (=, +=, -=, ++, etc) and takes place in userAssign delegate. Syntax of this delegate is:
public delegate void TermAssign(AleTerm term, AleTermAssignArgs e);
where term is AleTerm instance which has executed delegate. e parameter contains information about the object the value is assigned to.
using AleProjects.AleLexer.AleParser; using AleProjects.AleLexer; ... string myVar = "some value"; int[,] matrix = new int[,] { { 10, 11, 12, 13 }, { 14, 15, 16, 20 }, { 27, 28, 29, 40 } }; private class MyClass { public string SomeProperty { get; set; } } MyClass myClass = new MyClass() { SomeProperty = "property value"; }; private void OnEvaluate(AleTerm term, AleTermEvaluateArgs e) { // the same code as in example above } private void OnAssign(AleTerm term, AleTermAssignArgs e) { /* VARIABLES * e.Instance is null. * e.Name - name of variable (in uppercase when we ignore case) * e.NameHash - hash of e.Name (obtained by GetHashCode()) * e.Indexes is null * e.Value - value that we assign */ if (e.Instance == null) { if (e.NameHash == -1770187129 && e.Name == "MYVAR") myVar = e.Value.ToString(); else if (e.NameHash == -413117458 && e.Name == "MYCLASS") myClass = e.Value as MyClass; else if (e.NameHash == 614904363 && e.Name == "MYARRAY")) matrix = e.Value as int[,]; else { // error - no variable with such name e.SetError(AleTermResult.ERROR_UNKNOWNVARIABLE, term.Token.StartInOrigin); } return; } /* MEMBERS OF CLASSES (class operator '.') * e.Instance - instance of class. * e.Name - name of class property (in uppercase when we ignore case) * e.NameHash - hash of e.Name (obtained by GetHashCode()) * e.Indexes is null * e.Value - value that we assign */ if (!String.IsNullOrEmpty(e.Name)) { if (e.Instance is MyClass) { MyClass _myClass = e.Instance as MyClass; if (e.NameHash = 1760601946 && e.Name == "SOMEPROPERTY") _myClass.SomeProperty = e.Value.ToString(); else e.SetError(AleTermResult.ERROR_UNKNOWNPROPERTY, term.Token.StartInOrigin); } else e.SetError(AleTermResult.ERROR_UNKNOWNELEMENT, term.Token.StartInOrigin); return; } /* ELEMENTS OF ARRAYS AND COLLECTIONS (index operator) * e.Instance - instance of array or collection. * e.Name == "" * e.NameHash == 0 * e.Indexes - list<object> with indexes or keys * e.Value - value that we assign */ Type typ = e.Instance.GetType(); if (typ.IsArray && typ.FullName == "System.Int32[,]") { if (e.Indexes.Count != 2 && e.SetError(AleTermResult.ERROR_INVALIDINDEXES, term.Token.StartInOrigin)) return; int[,] _matrix = e.Instance as int[,]; try { _matrix[Convert.ToInt32(e.Indexes[0]), Convert.ToInt32(e.Indexes[1])] = Convert.ToInt32(e.Value); } catch { e.SetError(AleTermResult.ERROR_INVALIDINDEXES, term.Token.StartInOrigin); } } else e.SetError(AleTermResult.ERROR_UNKNOWNELEMENT, term.Token.StartInOrigin); } ... AleExpressionParser AP = new AleExpressionParser(); AP.Options = AleExpressionParser.OPTION_IGNORECASE; AP.InitOperations(AleExpressionParser.OPERATIONS_STANDARDSET); AP.Text = "myClass.SomeProperty = \"text \" + (MyVar = \"value=\" + (MyArray[0,1] = 2))"; AleTerm term = AP.Parse(); AleTermResult result; if (term.Evaluate(out result, OnEvaluate, OnAssign)) ..... ...
Associative arrays and object constants
The syntax of associative array constant is: {key1=>value1, key2=>value2, ... }. Internally associative array is stored in the instance of Dictionary<object, object> type.
The syntax of object constant is: {"propertyName1": value1, "propertyName2": value2, ... }. Internally object is stored in the instance of Dictionary<string, object> type.
To disable associative array constants and object constants, set property InitListBrackets of the parser to empty string "" or null. Setting this property to '{}' enables constants. The first character is an opening bracket, the second is a closing one. Combining diacritical marks or surrogate pairs are not allowed.
using AleProjects.AleLexer.AleParser; using AleProjects.AleLexer; ... AleExpressionParser AP = new AleExpressionParser(); AP.InitListBrackets = ""; // disable .. AP.InitListBrackets = "{}"; // enable
How to disable elements access
To disable elements access, set property ArrayBrackets of the parser to empty string "" or null. Setting this property to '[]' enables constants. The first character is an opening bracket, the second is a closing one. Combining diacritical marks or surrogate pairs are not allowed.
using AleProjects.AleLexer.AleParser; using AleProjects.AleLexer; ... AleExpressionParser AP = new AleExpressionParser(); AP.ArrayBrackets = ""; // disable .. AP.ArrayBrackets = "[]"; // enable