1
0
treerack/docs/examples/acalc/acalc.treerack

48 lines
2.3 KiB
Plaintext
Raw Permalink Normal View History

2026-01-18 22:52:27 +01:00
// first define our whitespace chars:
ignore:ws = " " | [\t] | [\r] | [\n];
// define the format of input numbers. With the :nows flag we declare that we don't expect ignored spaces
// between the digits and the delimiters. We support integers, floating point numbers, and floating point
// numbers with their exponential notation. We don't support arbitrary leading zeros to avoid confusion with the
// octal representation of numbers, which is not supported here.
num:nows = "-"? ("0" | [1-9][0-9]*) ("." [0-9]+)? ([eE] [+\-]? [0-9]+)?;
// define the supported operators:
add = "+";
sub = "-";
mul = "*";
div = "/";
// let's define grouping. Any expression can be grouped. The definition of the expression can be found further
// down in the syntax document. This usage of the expression reference is also a good example for recursive
// definitions. Using the :alias flag prevents generating a separate node in the resulting AST.
group:alias = "(" expression ")";
// we group the operators by precedence. This is necessary to parse the expressions like a * b + c in a structure
// that is equivalent to (a * b) + c.
op0:alias = mul | div;
op1:alias = add | sub;
// we also define which operands can be used at which precedence level. Notice, how operand1 also allows binary0
// expressions.
operand0:alias = num | group;
operand1:alias = operand0 | binary0;
// using the prioritized operators, we can define the prioritized binary expressions. We support a + b + c, and
// not only a + b.
binary0 = operand0 (op0 operand0)+;
binary1 = operand1 (op1 operand1)+;
binary:alias = binary0 | binary1;
// let's define, what an expression can be. Notice the recursion along expression and group.
expression:alias = num | group | binary;
// finally, define the root of the parser, the result of the arithmetic expression. It can be any expression,
// but since we used the :alias flag for the expression definition, we need to add a non-alias parser that will
// represent the root of the resulting AST. This also allows us to define an "exit" token, which can be used
// exit from the REPL loop of our application.
//
// Note that we don't need to use the :root flag here, because it is our last definition, and this means that
// the expression is the root parser of the syntax.
result = expression | "exit"