- 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 - operators

Operator is a symbol specifying operation that applied to one or two operands in an expression. Operator written between its operands is an infix binary operator; the one written before operand is a prefix unary operator, and the one written after is a postfix unary operator. Operator has the precedence and associativity. The precedence defines order of operator application in relation to other operators in expression which is not bracketed. The associativity defines the order of application of two operators with the same precedence in unbracketed expression.

The** AleOperation** class describes operators. Use this constructor to create operator definition:

public AleOperation(string name, int precedence, uint associativity, AleOperationType type = = AleOperationType.Evaluation)

where **name** is an operator symbol. Operator symbol can't start with digit and may have any character except brackets and quotation marks of any kind. Operator symbol may consist of multiple parts separated by whitespaces. In expressions symbol may have any whitespaces in any count between parts, but in description only one space character ('\u0020') must separate parts of operator symbol.

The **precedence** parameters specifies precedence of operator. Higher value means higher precedence.

Operator | Precedence |

=, +=, -=, *=, /=, %=, &=, |=, ^=, >>=, <<= | 10000 |

?? | 9500 |

|| | 9200 |

&& | 9000 |

| | 8200 |

^ | 8100 |

& | 8000 |

==, != | 7500 |

>, >=, <, <= | 7000 |

<<, >> | 6000 |

+, - | 5000 |

*, /, % | 4000 |

++, --, !, ~ | 1000 |

. (class operator) | 20 |

Operator | Precedence |

:= | 10000 |

or, and | 9200 |

xor | 9100 |

=, <> | 7500 |

>, >=, <, <= | 7000 |

+, - | 5000 |

*, /, shl, shr | 4000 |

mod | 3000 |

not | 1000 |

. (class operator) | 20 |

The **associativity** parameter specifies associativity of operator and must be one of the following constants or their combination:

public const uint OPERATOR_FX = 0x00000001; public const uint OPERATOR_FY = 0x00000002; public const uint OPERATOR_YFX = 0x00000004; public const uint OPERATOR_XFY = 0x000000010; public const uint OPERATOR_YF = 0x000000020; public const uint OPERATOR_XF = 0x000000040;

Left associative operators are denoted by constants OPERATOR_YFX, OPERATOR_YF and OPERATOR_FX. The OPERATOR_YFX constant denotes infix binary operator. The OPERATOR_YF constant denotes postfix unary operator. The OPERATOR_XF constant denotes prefix unary operator.

Right associative operators are denoted by constants OPERATOR_XFY, OPERATOR_XF and OPERATOR_FY. The OPERATOR_XFY constant denotes infix binary operator. The OPERATOR_XF constant denotes postfix unary operator. The OPERATOR_FY constant denotes prefix unary operator.

Following combination of constants are allowed: one or less constant denoting prefix operator + one or less constant denoting binary operator + one or less constant denoting postfix operator. Zero value of **associativity** is an error.

The **type** parameter is a member of **AleOperationType** enumeration and specifies that operator is of special kind like assignment, increment or member access (class) operator.

public enum AleOperationType { Evaluation, Assignment, CompoundAssignment, Increment, MemberAccess, ElementAccess, Index, InitList, ObjectConst, KeyValue, PropertyValue }

This information is used for semantic checking of expression. The **type** can be one of the following values: Evaluation, Assignment, CompoundAssignment, Increment, MemberAccess. Other values are not allowed in operator constructor.

The **AleOperation** class has property **Parameters**. For operators this property must be **null**.

## Evaluation of operators

The **AleOperation.Evaluator** property is a delegate that evaluates operator.

public delegate bool EvaluateOperation(AleTerm term, ref OperationEvalParameters parameters, ref AleTermResult result);

The **term** parameter is an expression tree node corresponding to the operator being evaluated. The **AleTerm** class has indexer returning child nodes that are also instances of the **AleTerm** class. For operators there is one or two child nodes, which are operands. Delegate is responsible for evaluation of the operator operands.

protected bool SubstractOperation(AleTerm term, ref OperationEvalParameters parameters, ref AleTermResult result) { AleTerm t1 = term[0]; AleTermResult a; if (!t1.Evaluate(out a, parameters.userEvaluate, parameters.userAssign) && result.SetError(a.ErrorCode, a.ErrorPos)) return false; AleTermResult b; if (term.Count == 2) // binary operator { AleTerm t2 = term[1]; if (!t2.Evaluate(out b, parameters.userEvaluate, parameters.userAssign) && result.SetError(b.ErrorCode, b.ErrorPos)) return false; } else { b = a; a.Value = 0; } TypeCode optype = AleTerm.OperationType(a.Value, b.Value); switch (optype) { case TypeCode.Double: result.Value = Convert.ToDouble(a.Value) - Convert.ToDouble(b.Value); return true; case TypeCode.Decimal: result.Value = Convert.ToDecimal(a.Value) - Convert.ToDecimal(b.Value); return true; case TypeCode.UInt64: result.Value = Convert.ToUInt64(a.Value) - Convert.ToUInt64(b.Value); return true; case TypeCode.Int64: result.Value = Convert.ToInt64(a.Value) - Convert.ToInt64(b.Value); return true; case TypeCode.UInt32: result.Value = Convert.ToUInt32(a.Value) - Convert.ToUInt32(b.Value); return true; case TypeCode.Int32: result.Value = Convert.ToInt32(a.Value) - Convert.ToInt32(b.Value); return true; default: result.SetError(AleTermResult.ERROR_INCOMPATIBLETYPES, term.Token.StartInOrigin); return false; } }

This is an example of delegate that performs substraction operation (minus '-' operator). Minus operator can be unary or binary. When it is unary, **Count** property of the **term** parameter is equal to 1 (only one operand). When it is binary, **Count** property is 2. Operands are evaluated by calling their **Evaluate** methods. Delegates for evaluating user variables and user operations and for assigning values for variables are passed in **userEvaluate** and **userAssign** properties of the **parameters** parameter. Method **SetError** of structure **AleTermResult** sets error status and always returns **true**.

Evaluated values of operands might be of different types. Static method **OperationType** of class **AleTerm** has two parameters of type **object** with values of operands and returns type code to which both operands can be safely typecasted.

As was mentioned before, the result of tokenization is a linear list of tokens that are instances of the **AleToken** class. In fact, the operator in this list is represented by the **AleOperationToken** class that is derived from **AleToken**. The **AleOperationToken** class has property **Associativity** that unambiguously defines associativity and position of operator in its context. Operator token can be accessed by the **Token** property of the **term** parameter.

protected bool MyOperatorEvaluator(AleTerm term, ref OperationEvalParameters parameters, ref AleTermResult result) { AleTerm t1 = term[0]; if (((term.Token as AleOperatorToken).Associativity & (AleOperation.OPERATOR_FX + AleOperation.OPERATOR_FY)) != 0) { // prefix operator } else if (((term.Token as AleOperatorToken).Associativity & (AleOperation.OPERATOR_XF + AleOperation.OPERATOR_YF)) != 0) { // postfix operator } else { // binary operator AleTerm t2 = term[1]; } ... }

To add operator to the parser set of operations, use the **AleExpressionParser.AddOperation** method.

public bool AddOperation(AleOperation operation)

If operator with such symbol already exists, the method replaces it with a new one.

To remove operator from the parser set of operations, use the **AleExpressionParser.RemoveOperation** method.

public void RemoveOperation(string name, int paramCount, bool isClassMethod = false)

The **name** parameters is an operator symbol. The **paramCount** parameter must be -1. The **isClassMethod** parameter is ignored.