For this assignment, you are to complete an interpreter for a simple, procedural programming language named SILLY (Simple, Interpreted, Limited Language for You). The grammar rules for the SILLY language are as follows:
There are no spaces between the characters in an identifier, integer, or string. Otherwise, tokens in the other rules are all separated by whitespace.
The SILLY language is case sensitive, so variables
considered unique. There are three data types in SILLY: integer, string and Boolean. Variables are not explicitly declared but must be assigned a value before they can be used in an expression or statement. The interpreter relies heavily on run-time type checking when evaluating expressions The math operators ('+', '-', '*', and '/') can only be applied to integers, whereas the Boolean operators ('and', 'or', and 'not') can only be applied to Boolean values. The concatenation operator '.' can be applied to values of any type, with non-strings being converted to strings by placing quotes around them. Comparison operators ('==', '=/=', '>', '>=', '<', and '<=') can be applied to any two values of the same type. Integers are ordered numerically (e.g., 2 < 3); strings are ordered alphabetically (e.g., "bar" < "foo"); Booleans are ordered truthfully (e.g., false < true). In addition, the expression in an if statement or while loop must evaluate to a Boolean value, whereas the expression in a repeat loop must evaluate to an integer. Any type mismatches will result in a runtime error.
SAMPLE CODE (output in red) >>> x = 5 >>> output x 5 >>> y = ( x + 1 ) >>> output y 6 >>> output ( x * y ) 30 >>> word = "foo" >>> longer = ( word . "bar" ) >>> output ( "longer=" . longer ) "longer=foobar" >>> output ( ( y / 2 ) + ( x * 2 ) ) 13 >>> output ( "foo" . ( 3 - 1 ) ) "foo2" >>> repeat 3 output "howdy" end "howdy" "howdy" "howdy" >>> num = 1 >>> N = 5 >>> repeat N output num num = ( num * 2 ) end 1 2 4 8 16 >>> quit BYE >>> flag = true >>> output flag true >>> output ( 3 > 2 ) true >>> output ( "foo" =/= "bar" ) true >>> opposite = ( not flag ) >>> output opposite false >>> output ( flag or ( not flag ) ) true >>> output ( ( not flag ) and flag ) false >>> count = 5 >>> if ( count > 0 ) output "yes" else output "no" end "yes" >>> while ( count > -1 ) output count count = ( count - 1 ) end 5 4 3 2 1 0 >>> quit BYE
An incomplete version of the SILLY interpreter is provided for you via the following classes/files:
TokenStream.java: These classes define the different types of tokens that make up the language, and define an input stream for reading in program tokens.
Interpreter.java: This is the main interpreter class for the language. By default, the interpreter reads statements from and displays output to the console. If you specify a file name as a command line argument, however, the interpreter will read statements directly from the file.
Heap.java: These classes define the memory segments for storing variables and their values, with integer values stored directly on the stack and strings stored on the heap.
Statement.java: This abstract class provides the framework for all types of statements and includes a general-purpose method for reading a statement.
Quit.java: These classes, derived from
Statement, define the specific statements of the SILLY language.
StringValue.java: This interface and implementing classes defines two of the types of values that can be stored in SILLY, integer and string.
Expression.java: This class defines an expression, which is either an integer, a string, an identifier, or a complex expression involving operators.
To produce a fully functional interpreter for the SILLY language, you will need to make the following modifications/additions:
StringValueare implemented. Add the BooleanValue type to the language. In addition to recognizing the tokens
false, you will need to update the
Expressionclass so that a
BooleanValuecan be used in an expression. You will also need to implement the comparison operators ('==', '=/=', '>', '>=', '<', and '<=') which return Boolean values. If any of these operators are applied to values of different types (e.g., a string and an integer), an exception with appropriate runtime error message should be thrown.
end' keyword for an if statement - if there is an else case, the keyword '
else' separates the statements to be executed if the test expression evaluates to true or false.
not. If any of these operators are applied to non-Boolean values, an exception with appropriate runtime error message should be thrown.
Note that in making these additions, the main progam file
Interpreter.java) need not be
modified at all. Instead, you will primarily be making changes to the
classes, with some minor modifications to
Expression. As you add new
features, be sure that syntax and runtime errors result in exceptions being thrown with informative messages.
For extra credit, add a comment feature to the language. A comment can begin at any point on a line, starting with '//', and continues to the end of that line. When executed, a comment does nothing.