# Introduction

I’ve ported from C++ to C# my old expression interpreter. It’s written from scratch without any parser generators like, say, ANTLR. Maybe it isn’t the modern approach but I’m using this code during last twenty years or so.

# Basics

An expression contains parameters, numeric and predefined symbolic constants, predefined functions calls.

All elements type is treated as double. Evaluation result is also double (having, possibly, special values NaN, INF, -INF).

__Samples:__

- (1+2)*5
- 2*sqrt(4)
- if({0}-4,{0}-10,33,{0}+10)

## Usage

Expression class constructor takes an expression string as a parameter and parses it into the tree of operations. Exceptions of some types could be thrown during parsing.

Then the expression could be evaluated multiple times with different parameters set with the Evaluate method. Evaluation is always successful (doesn’t throws exceptions) although the result could be one of the double type special values mentioned above.

## Constants

An expression can contain numeric literals and predefined symbolic constants (like "PI").

The decimal point is used as the separator in literals. Scientific notation ‘e’ or ‘E’ can be used.

### Predefined Constants

The following symbolic constant names are defined:

- Natural logarithm base "e" = 2.71…
- "PI" = 3.14…
- Not-a-number value "NaN".
- Positive infinity "Inf".
- Negative infinity "NInf".

Constant names are case-insensitive.

## Parameters

Expression parameters (variables) are denoted with the placeholder syntax {index} like in the string.Format method format string. The ‘index’ is the parameter position in the array passed to the Evaluate method call. If the parameter at the specified index is missed the NaN value used.

## Operations

Operations priorities are as follows (the top is highest).

- Function calls and parentheses ().
- Unary plus (+) and minus (-).
- Exponentiation (^).
- Multiplication (*), division (/), modulus (%).
- Addition (+) and subtraction (-).

### Parentheses

Any level parentheses used to group the operations.

### Function calls

All functions return double value and can have one or more arguments. Syntax: function(arg1, arg2, …). Argument itself also could be an expression. Some functions can have variable argument count.

### Unary plus and minus

Unary plus is ignored. Unary minus is right associative, i.e. –x means (-(-x)). When Unary minus is applied to an infinity its sign changes to the opposite (e.g. Inf becomes NInf and vice versa).

### Exponentiation

Pow function analog. The operation is right associative, i.e. x^y^z means (x^(y^z)).

Any values except NaN powered to 0 equal to 1. NaN at any power equal to NaN.

### Multiplication, division, modulus

These operations are left associative, i.e. x*y/z means ((x*y)/z).

### Addition and subtraction

These operations are left associative, i.e. x+y-z means ((x+y)-z).

## Functions

Function names are case-insensitive.

### Conditional Functions

Conditional functions allow emulate a branching in the intrinsically linear expression syntax.

First argument value of any conditional function is compared to the branching condition defined by that function. Depending on the comparison result one of the other arguments is calculated.

#### Branching by sign (If)

**If** function has 4 or 5 arguments.

If(cond, var1, var2, var3)

or

If(cond, var1, var2, var3, spec)

**If** function checks the **cond** argument has a special value. If so, two variants are possible:

- If the
**spec** argument exists it’s calculated.
- Otherwise the function returns the value of
**cond**, i.e. NaN, Inf or NInf.

If the cond argument doesn’t have a special value, **If** function calculates and returns the value of one of three arguments.

- var1 on cond < 0
- var2 on cond == 0
- var3 on cond > 0

#### Branching by special value (IfNotFinite)

**IfNotFinite** function has 2 or 3 arguments.

IfNotFinite(cond, spec)

or

IfNotFinite(cond, spec, var)

If the **cond** argument has a special value the function calculates and returns the **spec** argument value. Otherwise, if **var** argument exists the function calculates and returns it. Else it returns the **cond** value.

#### Branching by NaN (IfNaN)

**IfNaN** function has 2 or 3 arguments.

IfNaN(cond, spec)

or

IfNaN(cond, spec, var)

If the **cond** argument value is NaN the function calculates and returns the **spec** argument value. Otherwise, if **var** argument exists the function calculates and returns it. Else it returns the **cond** value.

#### Branching by Infinity (IfInf)

**IfInf** function has 2 or 3 arguments.

IfInf(cond, spec)

or

IfInf(cond, spec, var)

If the **cond** argument value is Inf or NInf the function calculates and returns the **spec** argument value. Otherwise, if **var** argument exists the function calculates and returns it. Else it returns the **cond** value.

#### Branching by Positive Infinity (IfPInf)

**IfPInf** function has 2 or 3 arguments.

IfPInf(cond, spec)

or

IfPInf(cond, spec, var)

If the **cond** argument value is Inf the function calculates and returns the **spec** argument value. Otherwise, if **var** argument exists the function calculates and returns it. Else it returns the **cond** value.

#### Branching by Negative Infinity (IfNInf)

**IfNInf** function has 2 or 3 arguments.

IfNInf(cond, spec)

or

IfNInf(cond, spec, var)

If the **cond** argument value is NInf the function calculates and returns the **spec** argument value. Otherwise, if **var** argument exists the function calculates and returns it. Else it returns the **cond** value.

### Math Functions

#### Absolute value Abs

Abs has one argument and returns its absolute value. The same is applied to the negative infinity: Inf is returned in place of NInf.

#### Square root Sqrt

Sqrt has one argument and returns its square root. The square root of negative number, including negative infinity, and NaN, is NaN. The square root of Inf is Inf.

The Sqrt(x) is the analog of Pow(x, 0.5).

#### Exponentiation Pow

Pow has two arguments and returns the first argument raised to the power of the second argument. It’s the analog of ^ operation.

Any value except NaN at the power of 0 is equal to 1. NaN at any power is equal to NaN.

#### Logarithms

Log and Log10 functions has one argument. Logarithm of 0 is equal to NInf. Logarithm of negative argument is NaN.

#### Thrigonometric functions

Sin, Cos and Tan functions has one argument. If the argument has any special value the result will be NaN.

#### Reverse thrigonometric functions

Asin, Acos and Atan functions has one argument and return the angle value in radians or a special value.

If Asin or Acos argument is outside of [-1,1] or has a special value the result will be NaN.

If Atan argument has a special value the result will be:

- NaN for NaN
- pi/2 for Inf
- -pi/2 for NInf

#### Hyperbolic functions

Sinh, Cosh and Tanh functions has one argument.

# The code

You can download the code here:

http://cid-39d56f0c7a08d703.skydrive.live.com/embedrow.aspx/.Public/Expression/Expression030609.zip

Regards,

Oleg V. Polikarpotchkin