CSC 533: Programming Languages
Spring 2022

HW2: Implementing a Simple Interpreter


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 ) → true
 

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:

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:

  1. Within the 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.
  2. Implement the repeat statement in a class named 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.
  3. The current definition of the if statement is incomplete in that it only supports if and else cases. Modify the 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.
  4. Implement the 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.