Expression parser
The relation function uses an expression parser which is designed from the ground, eg. without use of an eval() function which would be a security risk.
The expression parser (swExpression in inc-expression.php) transforms algebraic expressions and evaluates them with a series of given values.
The expression parser accepts algebraic expressions with values and inline operators
- 4 +3
- 4 * 3 + 5
- 4 * (3 + 5)
The expression usually has variables (starting with a letter) and pointers (indirect variables, starting with a ^)
- 4 * 3 + a
- 4 * 3 + ^a
The expression can have functions
- max(4, 3)
The values can be numbers or strings. The context defines if a value is considered as number or string because each operator or function only accepts either numbers or strings
- replace("old","new",text)
All operators are documented in https://www.belle-nuit.com/relation/expressions
The expression parsers works in 3 steps: tokenize, compile, evaluate. Tokenize and compile happen only once, evaluate for each row.
Tokenize
The expression string is transformed in an array with tokens.
Numbers, symbolic operators and names are tokenised literally.
"4 * 3 + a" becomes {"4", "*", "3", "+", "a"}
Strings are transformed to a hex representation of the string and are preceded by #.
""ab" . "c"" becomes {"#6162",".","#63"}
Function names are preceded by @
"sin(5)" becomes {"@(sin","5",")"}
Compile
The tokenised array is transformed to an array in RPN notation (reverse polish notation, like HP calculators). It uses the shunting-yard algorithm that keeps to running stacks and orders the tokens by operator precedence. It interpreted the tokens and replaces operators with their name.
{"4", "*", "3", "+", "a"} becomes {"4","3",":mul","a","::add"}
{"#6162",".","#63"} becomes {"#6162","#63",":concat"}
{"@(sin","5",")"} becomes {"5", ":sin")
Evaluate
The RPN stack is evaluated using given values for the variables. For the variables, there is a cascading precedence row value over local value over global value.