The ELAM Syntax

This page uses the example in demo to explain syntactic rules. Actual operators, types, and functions may differ significantly when used with different syntax libraries.

ELAM has the following syntactic elements:

Expressions

Expressions are what ELAM interprets. They can be as simple as the number "1", or very complex:
ExpressionExplanation
1a simple literal number
1+2simple operation using two literals
2*asimple operation using a literal and a variable
1+2*3two operations with precedence (* is evaluated before +)
(1+2)*3two operations with precedence changed through parentheses
a=3+4operation with the result assigned to a variable
b=a=3+4operation with the result assigned to two variables
Expressions can be used recursively. For example the expression "1+2+3" consists of the two expressions "1+2" and "(1+2)+3". Expressions return the result of their evaluation, assignment expressions return the value that has been stored in the variable to the left.

Literals

Literals are directly encoded values like "1" or "0.5".

The default library knows numeric literals:
ExampleCompositionDescription
123starts with 1..9, contains any number of 0..9decimal integer value
012starts with 0, contains 0..7octal integer value
0x12starts with 0x, contains 0..9 and a..f/A..Fhexadecimal integer value
1.8, .8, 1. 1e34starts with digit or dot, contains digits, optionally a dot and/or "e" and more digitsfloating point value

If the string library is loaded you can also formulate strings enclosed in "..." or '...'.

Types

ELAM can handle arbitrary value types. The default library brings integer numbers, floating point numbers, and optionally strings. For some functions and operators it can cast values into different types automatically, for others cast-functions must be called.

Variables and Constants

Variables are named values (e.g. "a" or "myVar2") that can be set by assignments and then be used instead of literal values. In the default implementation variable names must start with a letter and may contain letters, digits and underscores. Variable names are case sensitive (e.g. "myVar" is different from "MyVar").

Constants are variables that have been marked as immutable, they can be of any type.

Operators

There are two types of operators: unary and binary.

Unary operators precede an expression and change it, returning the result. For example the unary "-" operator in the default library negates its numeric argument (e.g. if "a" is 12, then "-a" returns -12).

Binary operators operate on two expressions, one to the left and one to the right of the operator.

If operators follow each other (e.g. "a != -b") then the operators must be separated by spaces.

Parentheses group operations and may alter the order in which they are executed. Parentheses are evaluated before any other operation.

Operator Precedence

Operators are interpreted in a specific order of precedence. First the highest precedence operators are evaluated, then the next lower precedence level, etc. with assignments being executed last. Consecutive binary operations with the same precedence level are executed from left to right. Consecutive unary operations are executed from right (nearest to the argument of the operator) to left (farthest to the argument).

The default library has the following precedence order:
Operator ClassOperatorsPrecedence Value
Parentheses(parentheses), functions(...)1000
All Unary Operators ~, !, -, +100
Maximum usable Precedence 99
Multiplicative *, /, %90
Additive +, -80
Shift <<, >>70
compare <, >, ==, !=, <=, >=60
bitwise AND &50
bitwise XOR ^45
bitwise OR |40
logical AND &&30
logical XOR^^25
logical OR||20
Lowest usable Precedence 1
assignments=, +=, -=, ...0

This means for example that in "a=9+1+2*(3-1)" these operations are executed in this order:

  1. "(3-1)" yields "2"
  2. "2*2" yields "4"
  3. "9+1" yields "10"
  4. "10+4" yields "14"
  5. the variable "a" is assigned the value "14"
  6. the expression returns the result of the last operation (the assignment) to the calling context

Parentheses

Parentheses are used to change the order in which operations are executed by grouping part of the expression into a unit that is calculated before the remaining operation surrounding it is executed. Inside the parentheses the normal precedence order applies again.

For example: in "2*(3-1*5)/4" the expression "3-1*5" inside the parentheses is resolved before the remaining multiplication and division around it are executed. While calculating the content of the parentheses the normal precedence applies, so the multiplication is executed before the subtraction.

Assignments

The equals sign ("=") has a special meaning when used in operators. In the normal mode the direct assignment operator "=" cannot be overloaded with a user specific function. If an operator ends in "=" and there is no overloaded operator, then the remainder is interpreted as a binary operator and the result assigned to the left side of the operator, for example "a+=b" is interpreted as a short form of "a=a+b".

In other words: if ELAM encounters an operator that equals its notion of the assignment operator (normally "="), then it is always interpreted as assignment - even if another operator with the same name exists. If ELAM encounters an operator that contains the assignment syntax (normally: one that ends in "="), then it first checks whether there is a more specific operator (above, e.g. "==") and uses it if found, if there is none, then it checks whether this could be a compound operation (e.g. "+=", which first adds and then assigns the result back to the left argument).

Assignment syntax can be changed by changing the character class for the assignment operator.

Functions

Functions take values of any kind as arguments and return exactly one value. Function names follow the same syntactic rules as variable names. Functions and variables share their namespace - no variable can have the same name as a function. Function arguments are separated by commas.

The default library knows the following functions:
FunctionDescription
int(value)converts value to integer, rounding towards zero
float(value)converts value to a floating point number
string(value)converts value to string
concat(v1,v2,...)concatenates strings

Character Classes

There are several classes of characters that make up the language itself: operators, names, special, whitespace, literals, and noise.

The "whitespace" class contains any character that can be ignored. Whitespaces can be used to separate tokens and to adjust expressions for readability. In the default library these are the normal space, the tab chars (\t, \v), and line endings (\n, \r).

The "operators" character class contains all characters that make up operators, in the default library these are "~!@#$%^&*-+=:<>?/". Operator class characters can be used to formulate unary and binary operators. This class also contains the assignment operator.

The "names" character class contains all characters that make up variable and function names. In the default library these are English letters (a-z and A-Z), digits (0-9), and underscores (_).

The "operators" and "names" classes must not overlap. While parsing the engine will recognize if the next character in a line is a different class (e.g. "a+b" is equivalent to "a + b"), but inside a class spaces have to be used to separate tokens (e.g. "+-" is different from "+ -").

The class of "literals" is comprised of rules that define what a literal looks like. Literals have a start character (which may overlap with the "names" class), a rule how to recognize the end of the literal and a routine to convert it to an actual value. The characters making up a literal can come from any class, although it is recommended to not use any operator characters. The start characters of literals may overlap, in this case they have a built-in precendence in which they are tried out. For example the class of integer numbers in the default library start with digits (0-9) and may contain digits and an optional "x" in second position (as in 0x12), any non-digit ends the literal.

The "special" characters are those with a specific built-in meaning to the parser. In the default library those are:
CharactersDescriptionRules
Parentheses "(", ")"change the order of evaluation by grouping the inner operations to be performed before the outer operations, or by enclosing the arguments of a functionthe two parentheses characters must differ and must not match any other class
Comma ","separates the arguments of a functionsingle character that must not be contained in any other class
Equals "="denotes assignments, the character itself cannot be overridden as operator, combinations with other operators can be overriddenone or two characters: prefix and postfix, they must differ, they both must be part of the operator class

Any other character falls in the "noise" class and produces a parser error.