Programming #4: A Partial
Implementation of the Biola Interpreter
Basic Specification:
We want to get a taste of implementing an interpreter for a programming language like our BIOLA language. Instead of the full set of the BIOLA language, we would confine the interpreter to deal with only three kinds of statements: the read statement, the display statement, the assignment statement, the if statement, and the while statement. We would like to develop an Interpreter class that provide a static method for doing this job. We will then add one additional interpreter option into the startMenuService member function of the Interface class. This new option should invoke the static method of the Interpreter class to, statement by statement, check the syntax of the statements stored in the vector of strings lines, and execute the statement if it is syntactically correct, or report error messages if there are syntactic or semantic problems.
Simplifying Assumptions:
To make this programming assignment easier, you can assume the source
programs to be executed by the interpreter are all well formatted in the
following way:
if ( … )
{
…;
…
…;
}
or with the if and the logic expression followed by
a single line a statement like:
if ( … )
…;
while (… )
{
…;
…
…;
}
About the Interpreter class:
You need to utilize the lexScanner class and the expressionEvaluatot class implemented in the previous programming assignments to implement the Interpreter class. The Interpreter class should have at least a static member function for executing a Biola source program in the following form,:
executeProgram( vector<
string > sourceProgram)
or
executeProgram( vector<
string >:: iterator itrBeginOfProgram, vector< string >:: iterator
itrEndOfProgram)
which would do the following things to the lines of source
code represented as a vector of strings and accessible either from vector< string > sourceProgram
or from the beginning to the end by the iterators itrBeginOfProgram and itrEndOfProgram.
Lexical Analysis: By appropriately setting up objects and calling methods of the code implemented in the lexical scanner module, determine and store the tokens and their categories of the lines of source code. We can also build up a string-to-float map as a symbol table to store the names of variables and their values (initialized to 0).
Syntax checking: It should then check whether the statements have syntax errors or not by using the information derived from the lexical analysis. For the three kinds of statements we consider, this is relatively simple given the simplifying assumptions of the formats above.
Semantic checking: Note that all the variables in the Biola languages are of the same numerical float type and variables are declared by (i) using them in the read statement for storing numerical values or (ii) using them in the left hand side of an assignment statement to store numerical values. Type checking is still necessary to ensure that (i) when a variable is used in the arithmetic expression in the right hand side of an assignment statement, that variable mush has appeared before, i.e. it must have been stored in the symbol table and thus has a valid value, and (ii) similarly when a variable is used in the arithmetic expression in an display statement, that variable must have appeared before, i.e. it must have been stored in the symbol table and thus has a valid value.
Execution of statements:
· read : To execute an read statement, get an numerical input from the user and store it appropriately in the corresponding variable in the map as symbol table.
· display: To execute a display statement, look at each segment of the tokens separated by commas following the display keyword. If the segment is simply a string literal, just display it to the screen. If the segment is an expression, use the code in expression evaluator module to evaluate it and then display the result to the screen.
· To execute an assignment statement, you need to evaluate the value of the expression to the right of the assignment operator. Then you just store the value appropriately into the map as a symbol table for the variable corresponding to the first token.
· if:To execute an if statement, first you need to evaluate the value of the logic expression to the right of the if keyword. If the result is true (i.e. with the numerical value 1), then you continue interpreting each of statements inside the pair of curly braces. If the result is false (i.e. with the numerical value 0), then you check to skip the whole block of statements enclosed by a balanced pair of curly braces following the line of containing the if keyword to proceed with the next statement after that.
· while: To execute a while statement, first you need to evaluate the value of the logic expression to the right of the while keyword. If the result is false (i.e. with the numerical value 0), then you check to skip the whole block of statements enclosed by a balanced pair of curly braces following the line of containing the while keyword to proceed with the next statement after that. If the result is true (i.e. with the numerical value 1), then you continue interpreting each of statements inside the pair of curly braces following the line of containing the while keyword and then go back to repeat the whole process with the while statement.
Bonus Points:
Try to extend your interpreter to be able to interpret if statements appearing across multiple lines exactly in the formats like:
if (… )
{
…;
…
…;
}
else
{
…;
…
…;
}
or
if (… )
…;
else
{
…;
…
…;
}
or
if (… )
{
…;
…
…;
}
else
…;
or
if (… )
…;
else
…;