Imperative Core Language Interpreter

The Imperative Core Language (ImpCore) extends Expression Language 1 by adding assignment, while, write, and block expressions. The source code is linked to the Files subsection below.

As exercises, we will extend use ImpCore and extend it in various ways.

Assignment #2

Assignment #2 is built around this case study. The assignment requires use and extension of the interpreter whose source code is linked into the Files section below.

ImpCore Syntax

For convenience in parsing, we choose a (Lisp-like) parenthesized prefix syntax relatively close to the abstract syntax used by our family of interpreters. The grammar for ImpCore extends the prefix grammar we used for Expression Language 1 by adding the four new types of expressions.

In the following BNF grammar, all words beginning with capital letters are nonterminals. The BNF metasymbols are ::= to show derivation rules for nonterminals, | for alternatives, { and } enclosing optional items, ^* for zero or more repetitions, and ^+ for one or more repetitions. All other words (e.g., while) and symbols (e.g., the left and right parentheses and operators such as +) are literals.

    Exp      ::=  Value | (Op1 Exp) | (Op2 Exp Exp) 
                | ( := Variable Exp ) 
                | ( if Exp Exp Exp)
                | ( while Exp Exp ) 
                | ( write Exp ) 
                | ( block Exp^* ) 
    Value    ::=  Number | Variable
    Op1      ::=  neg
    Op2      ::=  + | - | * | / | == | ~= | < | > | <= | >= 
    Variable ::=  Leading alphabetic or underscore followed by zero or
                  more alphabetic, numeric, or underscore characters 
    Number   ::=  One or more decimal digits with optional leading -

Variables cannot be keywords in the grammar (neg, if, while, write, block, etc.) or REPL command interface (quit). Command quit typed to the REPL's prompt terminates the program.

Also, a semicolon ; causes the rest of that line to be ignored by the parser (i.e., is an end-of-line comment).

ImpCore Semantics

The semantics of ImpCore expressions builds on the semantics of the Expression Language 1 expressions by adding assignment (:=), while, write, and block expressions. (Expression Language 1 consists of the language from Assignment #1 including all four arithmetic operations, all six relational expression, and if. It does not include the min and max operations from that assignment.)

As with Expression Language 1, the value space consists of the integers. (Of course, Lua 5.2 and earlier represents all numbers in double precision floating point, but with most hardware platforms, integers are exact to 53 bits.)

The interpreter represents the Boolean value "false" by integer 0 and "true" by nonzero values, canonically by the value 1.

The semantics (meaning) of the various ImpCore expressions are as follows. Unless otherwise noted, an expresion has the same meaning as in Expression Language 1.

Examples

To print the first n positive integers:

    (block ; print first n integers
       (:= n 10) 
       (:= x 1)
       (while (<= x n)
          (block
             (write x) 
             (:= x (+ x 1)))
       )
    )

To print the factorial of the first n positive integers:

    (block ; compute first n factorials
       (:= n 16)
       (:= i 1)
       (:= f 1)
       (while (<= i n)
          (block
             (write f)
             (:= i (+ i 1))
             (:= f (* f i))
          )
       )
    )

To print m modulo n:

    (block ; compute m modulo n
       (:= m 16)
       (:= n 3)
       (:= mm (- m (* (/ m n) n)))
       (write mm)
    )

Note: / yields the integer result from the division.

To print the positive integers whose squares are less than n:

    (block
       (:= n 1000) ; upper bound
       (:= i 1)    ; integer
       (:= s 1)    ; its square
       (while (< s n)
          (block
             (write i)
             (:= i (+ i 1))
             (:= s (* i i))
          )
       )
    )

To compute the logical "and" and "or" of two boolean values b and c:

    (if b c 0)  ; and
    (if b 1 c)  ; or

Of course, we can substitute expressions for b and c as needed. (These expression are the same for Expression Language 1.)

Interpreter Modification Highlights

In comparison to the modularized Expression Language 1 interpreter, the Imperative Core interpreter makes the following changes.

Exercises

The instructor will add the needed features in the parser to support read and for below.

  1. Add a read expression to the ImpCore language. The is a no-argument operation that reads a number from the terminal and returns it to the evaluating ImpCore program.

  2. Add a new for expression to the ImpCore language. It has the syntax

        ( for Variable Exp Exp Exp ) 

    Evaluating (for x e1 e2 e3) first evaluates e1 to a value v1 and stores v1 into x. It then repeats the following steps:

    1. evaluate e2 to a value v2
    2. retrieve the value of x
    3. if x > v2, then exit the for and return the value 0
    4. evaluate e3 and discard the result
    5. add 1 to x and store the result back in x (then repeat steps)

    For example, (for i 1 10 (write i)) prints the integers from 1 to 10 in order.

    Make sure you get the order of evaluation correct. For example, the odd program

    (for n 0 (block (:= n (+ n 2)) 10) (block (write n) (:= n (+ n 3))))

    prints the numbers 2, 8 and returns 0.

  3. The exclusive-or (xor) of boolean values b and c is true when exactly one of the two values is true and is false otherwise. Write an ImpCore expression that computes the exclusive-or of b and c.

  4. The Fibonacci sequence is defined by the function fib where fib(0) = 0, fib(1) = 1, and, for m > 1, fib(m) = fib(m-1) + fib(m-2). Implement an Imperative Core language program that writes the Fibonacci sequence for some positive integer n. (Use the ImpCore interpreter to test the program.)

  5. Write a version of the factorial program from the notes above using the for expression you added to ImpCore.

  6. Challenge: As an extension to the for loop, add an expression that gives the increment value (instead of just 1).

  7. Challenge: Extend ImpCore with a repeat-until expression with the usual semantics. You will need to extend the parser to do so.

  8. Challenge: Design an infix syntax for ImpCore and implement a parser (using LPEG).

  9. Challenge: Implement a compiler back-end for ImpCore that compiles for a stack machine. (Talk to the instructor.)

  10. Challenge: Consider how to add function definitions and calls, local variables, different data types, etc. We will do some of this in the future. (Talk to the instructor.)

Files

Modules

Test and execution scripts