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. 25 were provided in HW1.
There can be no spaces between the characters in an identifier, integer or string. Delimiters (e.g. '{' and '}') and operators (e.g., '=' and '*') do not require spaces to separate them from other tokens, but all others do. The SILLY language is case-sensitive, so variables a and A are considered unique.
There are four data types in SILLY: integer, Boolean, string, and list. The language is dynamically typed, meaning that a variable does not have a set type but is defined by the value assigned to it. Variables must be explicitly declared before they are used, and a run-time error should occur if a variable is used in an expression before being declared. The bodies of control statements and subroutines specify nested scopes. If a variable is declared inside a body, it is local and will not exist outside of that scope.
There are multiple predefined operators in SILLY for building expressions, as listed below. Note that expressions are enclosed in parentheses.
DESCRIPTION OP(S) OPERAND(S) EXAMPLE
------------- ------- ---------------------- ----------------------------
math ops + * / applied to 2 integers (1 + 2) → 3
((1 + 2) + 3) → 6
Boolean ops = \ < > applied to 2 values (3 = 2) → false
of same type (3 > 2) → true
! applied to 1 Boolean (! true) → false
& | applied to 2 Booleans (& true (! true)) → false
(| false (! true) true) → true
sequence ops # applied to 1 string/list (# "foo") → 3
(# [10 20]) → 2
@ applied to 1 string/list ("foo" @ 0) → 'f'
& 1 integer value ([10 20] @ 1) → 20
+ applied to 2 strings/lists ("foo" + "bar") → "foobar"
of same type ([1 2] + [3 4]) → [1 2 3 4]
Note that all data types in SILLY are comparable within their own 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) and lists are ordered by their string values (e.g., ["a", "b"] < ["x", "y"]). You may note that there is no subtraction operator in SILLY. Instead, subtraction can be accomplished by adding a negative integer, e.g., (5 + -1) → 4. Any type mismatch within an expression (e.g., applying the * operator to two non-numeric values or comparing values of different types) should result in a run-time error with a descriptive message.
SILLY provides a variety of statement types, including assignment, print, 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) >>> print "start" "start" >>> var x gets 6 >>> print x 6 >>> var y gets (x + 1) >>> x gets ((2 * x) + y) >>> print x 19 >>> print y 7 >>> print (x > y) true >>> print ((3+2) \ (4+1)) false >>> print (!((3+2) \ (4+1))) true >>> print [(2^3) "foo" (!true) y] [8 "foo" false 7] >>> var num gets 5 >>> while (num > 0) do print num num gets (num + -1) endwhile 5 4 3 2 1 >>> var reps gets 0 >>> var str gets "" >>> while (reps < 3) do str gets (str + "foo") reps gets (reps + 1) endwhile >>> print str "foofoofoo" >>> print (true & false) false >>> print (true | false) true >>> var word gets ("foo" + "bar") >>> var index gets 0 >>> while (index < (# word)) do var letter gets (word @ index) print letter index gets (index + 1) endwhile "f" "o" "o" "b" "a" "r" >>> var nums gets ([1 2] + [3 4]) >>> index gets 0 >>> while (index < (# nums)) do var n gets (nums @ index) print n index gets (index + 1) endwhile 1 2 3 4 >>> var word gets "banana" >>> var reverse gets "" >>> var index gets 0 >>> repeat (# word) times reverse gets ((word @ index) + reverse) index gets (index + 1) endrepeat >>> print reverse "ananab"
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 a loop to read and execute statements. If the user enters a file name at the initial prompt, then statements are read in and executed from that file. If the user simply hits return, then they can enter and execute statements interactively.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,ScopeRecord.java: These classes define how memory is organized and accessed. TheMemorySpaceclass implements a runtime stack ofScopeRecords to store and access variables.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,Var.java,Print.java,While.java,Body.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,BooleanValue.java,StringValue.java,ListValue.java: These classes implement theDataValueinterface to define integer, Boolean, string and list values.Expression.java: This class defines an expression, which is either a data value, an identifier or a parenthesized expression involving operators.
As provided, the interpreter runs a subset of the SILLY language. Variable declarations and assignments, print statements and while loops are fully implemented, and some but not all the operators are defined. 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:
evaluate method of the Expression class so that these two operators are defined for Boolean values. Note: if these operators are applied to non-Boolean values, your code should throw an exception with a meaningful error message. evaluate method of the Expression class so that '+' can be applied to concatenate lists, producing a new list that contains the combined contents of the lists. For example, ([1 2] + ["a" "b"]) should produce [1 2 "a" "b"].evaluate method of the Expression class so that these two operators are defined. Note: as before, any type mismatches should result in an exception with a meaningful error message. var y gets "foo"
while (x < 10) do
var y gets "bar"
print y
var y gets "biz"
print y
x gets (x + -1)
endwhile
The first declaration of y inside the while statement is legal — it creates a local variable that overrides the existing variable (declared outside the while statement). However, the second declaration should be illegal, since a local variable with the same name has already been declared within the while statement. Add a method isLocal to the MemorySpace class that returns true if the specified token is declared within the current scope. Then, modify the execute method in the Var class so that an exception is thrown if the variable is already local. Repeat that inherits from Statement and provides the required methods for a repeat statement. A repeat statement is similar to a while statement, except its expression should evaluate to an integer. The repeat statement executes the code in its compound statement as many times as the expression specifies. Your class should throw an exception if the structure of the statement is invalid (syntax error) or if the test does not evaluate to an integer value (runtime error). Submit a ZIP file of the entire src folder for your project (including files you did not modify).