For logical expressions 0 means false
and anything else means true
.
The division is integer. All intermediate results should be between -231 and 231 - 1.
E := (E)
| E < E | E > E | E = E | E <= E | E >= E
(these result in true / false expression)
| E + E | E - E | E * E | E / E
| if E then E else E
| funcName(args, ...)
| NUM | ID
Function declarations have the form fun funcName(args, ...) = E;
all in one line.
The parameters names are consisted of one letter.
The function names have two or more letters.
A function can be called from anywhere in the program as long as it is defined somewhere else in the same file.
If one line of the source file contains E;
the expression is evaluated numerically and printed on the standard output.
LL(1) parser is used. LR was expected to produce too many states.
Removing left-recursion grammar refactoring leads to:
Nonterminal | Rule | Rule | Rule | Rule | Rule | Rule | |
---|---|---|---|---|---|---|---|
E | := | E1E'1 | |||||
E'1 | := | < E1 | > E1 | <= E1 | >= E1 | = E1 | ε |
E1 | := | E2E'2 | |||||
E'2 | := | + E2E'2 | - E2E'2 | ε | |||
E2 | := | E3E'3 | |||||
E'3 | := | * E3E'3 | / E3E'3 | ε | |||
E3 | := | ID | NUM | (E) | if E then E else E |
java -jar Villie.jar [--argument] <source.code>
where --argument
can be one of --recursive
or --stackBased
.
The default abstract machine is stack based since the recursive one is prone to StackOverflow errors.
The direcrory tests
contains a bunch of tests. More tests can be added and they can be ran by executing run_tests.py
.
Courtesy goes to Georgi Gyurchev for assembling the task and the test cases back in 2012.
I would like to thank Dr Timothy Griffin for teaching the Compiler Construction course in my Part IB year in Cambridge and Alex Chadwick for supervising me for this course (and a couple more) and encouraging me to complete this long-pending toy project.
I don't pretend that the implementation is perfect or the most efficient possible at all. In fact, by choosing Java as a main development language it must be clear that the level of abstraction is (much) higher than usual for a standard compiler/interpreter. However, the goal to implement a stack based interpreter that deals with simple expressions and recursive functions was successfully accomplished.