For this assignment, you are to complete an interpreter for a subset of the SILLY (Simple, Interpreted, Limited Language for
You) programming language. Recall that the syntax rules for SILLY v. 21 were provided in HW1 (with one minor change to the format of expressions).
To keep the interpreter simple, it assumed that there is whitespace (spaces, tabs and/or blank lines) between individual tokens in the language. There can be no spaces between the characters in an identifier, integer, or string, however. The SILLY language is case-sensitive, so variables a
and A
are considered unique.
There are three data types in SILLY: integer, string, and Boolean. Variables are dynamically bound to values and types, but attempting to use a variable in an expression before it has been assigned a value will result in a runtime error.
There are a number of operators in SILLY for building expressions, as listed below:
DESCRIPTION OPERATOR(S) OPERAND(S) EXAMPLE ------------------------ ----------- ------------------------------- ---------------------------- standard math operations + - * / % applied to 2 integers ( 4 * 7 ) → 28 string concatenation + applied to 2 strings ( "foo" + "bar" ) → "foobar" string length # applied to a string ( # "foo" ) → 3 string indexing @ applied to a string and integer ( "foo" @ 0 ) → "f" Boolean negation not applied to a Boolean ( not true ) → false Boolean connectives and or applied to 2 Booleans ( true or false ) → true comparison operators == != < > <= >= applied to two value of same type ( 3 <= 4 ) → true4>
Note that the '+' operator can be applied to two numbers (addition) or to two strings (concatenation). The comparison operators 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"); and Booleans are ordered truthfully (e.g., false < true). Any type mismatch within an expression (e.g., applying the '*' operator to two string values or comparing values of different types) should result in a run-time error with a descriptive message.
SILLY provides a number of different statement types, including assignment, output, if, while, and repeat. Later assignments will add additional statements and features to the language.
SAMPLE CODE (output in red) >>> num = 99 >>> output ( num ) 99 >>> expr1 = ( 10 * 2 ) >>> expr2 = ( 1 + expr1 ) >>> output ( expr1 expr2 ( expr1 == expr2 ) ) 20 21 false >>> w1 = "foo" >>> output ( w1 ( w1 + "bar" ) ) foo foobar >>> flag = true >>> output ( flag ( flag or flag ) ) true true >>> count = 4 while ( count > 0 ) output ( count ) count = ( count - 1 ) end 4 3 2 1 >>> num = 5 >>> while ( num != 1 ) rem = ( num % 2 ) if ( rem == 0 ) num = ( num / 2 ) else triple = ( 3 * num ) num = ( triple + 1 ) end output ( num ) end 5 16 8 4 2 1 >>> gt = ( "foo" > "bar" ) >>> output ( gt ( not gt ) ) true false >>> word = "banana" >>> reverse = "" >>> i = 0 >>> len = ( # word ) >>> while ( i < len ) ch = ( word @ i ) reverse = ( ch + reverse ) i = ( i + 1 ) end >>> output ( reverse ) ananab >>> repeat 3 output ( "Hello" ) end Hello Hello Hello >>> grade = 85 >>> if ( grade >= 90 ) letter = "A" elseif ( grade >= 80 ) letter = "B" elseif ( grade >= 70 ) letter = "C" elseif ( grade >= 60 ) letter = "D" else letter = "F" end >>> output ( grade letter ) 85 B >>> const final = 100 >>> output ( final ( final + 1 ) ) 100 101 >>> final = 101 RUNTIME ERROR: cannot reassign a constant.
An incomplete version of the SILLY interpreter is provided for you via the following classes/files:
Token.java
,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, which runs an infinite loop to read and execute statements entered at the keyboard.MemorySpace.java
: This class defines the memory space for storing variables and their values.Statement.java
: This abstract class provides the framework for all types of statements and includes a general-purpose method for reading a statement.Assignment.java
,Output.java
,If.java
,While.java
: These classes, derived fromStatement
, define specific statements of the SILLY language.DataValue.java
,IntegerValue.java
,StringValue.java
,BooleanValue.java
: This interface and implementing classes define the types of values that can be stored in SILLY.Expression.java
,Term.java
: These interacting classes define an expression, which is either a simple term (integer, string, Boolean, or identifier) or a parenthesized expression involving operators.
As provided, the interpreter runs a subset of the SILLY language. Assignments, output statements, and while loops are fully implemented. If statements and expressions are partially implemented. Note that statements in the left column above will execute given the existing code; statements in the right column depend on language features that you will be implementing in this assignment.
For this assignment, you will need to make the following modifications/additions:
Expression
class, all of the binary operators are implemented. However, the two unary operators (not
and #
) are not. Modify the Expression
constructor so that expressions involving these two unary operators can be read in and stored. Then, modify the evaluate
method so that the operators are evaluated as specified. Finally, modify the toString
method so that expressions involving the unary operators are displayed correctly.Repeat
. This class should be very similar to the While
class, both in form and functionality. Note, however, that the test for a repeat statement must be an integer. When executed, a repeat statement executes the enclosed statements the specified number of times. Be sure to implement all the required methods of the class, including toString
.
If
class so that it can also handle an arbitrary number of elseif
cases. This will require adding fields and modifying the constructor to be able to read and store an arbitrary number of elseif
test expressions and the statement sequences that go with each case. The execute
method will need to be modified so that the elseif tests are evaluated and the corresponding case statements executed appropriately. Warning: this may get messy, so be careful in your design, coding and testing. Be sure to update the toString
method so that it accommodates the full format. ConstantDeclaration
class that defines a constant declaration. A constant declaration is simply an assignment preceded by "const", e.g., const x = 0
. A constant can be used in an expression just like a normal variable, but any attempt to reassign its value should result in a runtime error. Hint: since a constant declaration contains an assignment, it can simplify your class considerably if you have a field that is an Assignment
object. In addition to defining your ConstantDeclaration
class, you will need to make changes to the Assignment
and MemorySpace
classes in order to identify illegal attempts to reassign a constant. In all of these modifications, any syntax errors (e.g., malformed expressions) and runtime errors (e.g., type mismatches) must be caught and result in a meaningful error message. To make testing your code easier, you can enter your test statements into a text file then execute them using the provided (Batch.java
) class. When executed, the batch interpreter prompts the user for a file name, reads SILLY statements from the file, and executes them. By default, the text file is assumed to be in the top-level directory of the project.