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. 22 were provided in HW1.
There can be no spaces between the characters in an identifier, integer, or string. Otherwise, whitespace is allowed between tokens. 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. The language is strongly typed, with any type mismatches resulting in either syntax or runtime errors. A variable must be declared (with its type) and assigned a value the first time it appears. The type for that variable is then set and cannot be changed.
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 declaration, assignment, output, if and while. Sample interpretations of SILLY code are provided below, with user input prefaced by ">>>" and the interpreter's output highlighted in red:
SAMPLE CODE (output in red) >>> int x = 9 >>> output x 9 >>> int y = (2 * x) >>> output (x + y) 27 >>> str word = "foo" >>> output word foo >>> output ((word + "bar") + (word + "biz")) foobarfoobiz >>> boo flag = true >>> output flag true >>> output (not flag) false >>> if (x < y) then { output "ok" output "still-ok" } noelse ok still-ok >>> if (x > y) then { output "not-ok" output "still-not-ok" } noelse >>> int count = 5 >>> while (count > 0) do { output count count = (count - 1) } 5 4 3 2 1 >>> boo stop = false >>> int num = 2 >>> while (not stop) do { output num num = (2 * num) if (num > 1000) then { stop = true } noelse } 2 4 8 16 32 64 128 256 512 >>> output {1, (15 / 3), (true or false), ("ab" + "cd")} 1 5 true abcd >>> str text = "banana" >>> output {(# text), (text @ 0)} 6 b >>> str reverse = "" >>> int i = 0 >>> while (i < (# text)) do { reverse = ((text @ i) + reverse) i = (i + 1) } >>> output {text, reverse} banana ananab >>> int grade = 88 >>> if (grade >= 90) then { output "excellent" } else { if (grade >= 75) then { output "good" } else { output "needs_work" } } good >>> int current = 5 >>> while (current != 1) do { output current if ((current % 2) == 0) then { current = (current / 2) } else { current = ((3 * current) + 1) } } 5 16 8 4 2 >>> output {1, "STUCK"} 1 STUCK >>> int value = 2 >>> do { output value value = (2 * value) } until (value > 1000) 2 4 8 16 32 64 128 256 512
An incomplete version of the SILLY interpreter is provided for you
via the following classes/files (which are also downloadable as SILLY.zip
):
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.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.MemorySpace.java
,VariableBinding.java
: These classes define how memory is organized and accessed. TheMemorySpace
class implements the stack and heap segments and utilizesVariableBinding
s to associate types and values with variables.Statement.java
: This abstract class provides the framework for all types of statements and includes a general-purpose method for reading a statement.VarDeclaration.java
,Assignment.java
,Output.java
,If.java
,While.java
,Compound.java
: These classes, derived fromStatement
, define specific statements of the SILLY language.DataValue.java
: This interface provides the framework for the different data types in SILLY.IntegerValue.java
,StringValue.java
,BooleanValue.java
: These classes implement theDataValue
interface to define integer, string and Boolean values.Expression.java
: This class defines 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. Variable declarations, assignments, while loops and compound statements are fully implemented. Output statements, 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 the required operators are defined except for two string operators: #
and @
. Modify the Expression
constructor so that expressions involving these two operators can be read in and stored. Then, modify the evaluate
method so that the operators are evaluated as specified. Do
. This class should be very similar to the While
class. Note, however, that the test for a do statement appears at the end of the statement and specifies a stopping condition. As a result, the code in the body of a do statement will always be executed at least once. Be sure to implement all the required methods of the class, including toString
. Output
class so that it also supports multiple output expressions enclosed in curly braces and separated by commas. This will require adding field(s) and modifying the constructor (to be able to read and store an arbitrary number of expressions), the execute
method (to display all the expressions on a single line), and the toString
method (to display all formats). Note: the current format for outputting a single expression should still be supported. If
class so that it can handle this additional case when it appears. This will require adding field(s) and modifying the constructor (to be able to read and store the statements associated with the else case), the execute
method (to execute those statements when the test fails), and the toString
method (to display all formats). Note that these additions/modifications may also require updating other files in the project so that all new operators, keywords and statements are recognized. All syntax errors (e.g., malformed expressions) and runtime errors (e.g., type mismatches) must be caught by your code and result in meaningful error messages. 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.