DIKU - Walking through the interpreter
After several hours coding, I am happy to say that the language now has an interpreter!
You can view the implementation here.
In this post, I’ll run through the new classes and logic that makes this possible.
As discussed in chapter 4 of the text, a key requirement for an interpreter is a symbol table, to hold the state of each variable, within each lexical scope.
The symbol table and its methods are absracted away into the SymbolTable
class.
As the language only has a single scope, the symbol table is implemented as a simple string indexed array. To allow for multiple scopes, this implementation would have to be modified.
This class has two methods, SymbolTable->bind()
and SymbolTable->lookup()
, which allow for a variable name to be bound to some data (ie, n = 1
), and for the data associated with a variable to be retrieved.
If a lookup
is performed on a variable that has not been bound
, a warning message is printed - however execution will continue.
All file-handling logic has been moved into Interpreter.php
.
The Interpreter->run()
method itterates through the AST array returned by Parser->run()
, and traverses the tree recursively in postorder:
With the last line of the above snippet calling Interpreter->interpret_{$node['symbol']}
.
To take an explicit example, the operation n < 2
would cause the following method to be called:
Interpreter->interpret_WHILE()
is the only real non-trivial method in this class, recursing on Interpreter->postorderTraversal()
, allowing for nested while
loops, and for the while
logical block to span several new lines.
A variable namednextInstruction
was added to the Node
class to accomplish this, as well as a check in Interpreter->postorderTraversal()
, actioning the execution of any additional while
block instructions.
In the same way, the ASTarray[]
within the Parser
class could be modified to a single AST representation, but for now I’m quite happy with the implementation.
For me, a key takeaway is that the logic in the Interpreter
class is in some ways very similar to the Parser
class, in the same way that the Parser
class is to the Lexer
class - with each dealing with higher and higher levels of abstraction.
Onward!