Assignment 3 Implementing Environments

 

Goal

To understand how an environment works as a map from identifiers to locations, and how nested regions of scope can be implemented in an interpreter as a stack of such environments.

Language L2

Language L2 has a syntax based on Modula 2. Your task is to take the existing JavaCC grammar file, to generate skeleton Abstract Syntax Tree classes from it using jjtree, and to augment the classes with code that implements an interpreter for the language. The grammar, in abstract form, is:

 

Program = Block .

Block =  begin ( Declaration )* StatementSeq end

Declaration = int Id ; | bool Id ;

StatementSeq = Statement ( ; Statement )*

Statement = Assign | IfThenElse | WhileLoop | Block

Assign = Id := Expression

IfThenElse = if BooleanExp then Statement OptElse

OptElse = {} | else Statement

WhileLoop = while BooleanExp do Statement

Expression = ArithExp | BooleanExp

ArithExp = Factor ( (+|-) Factor )*

Factor = SimpleExp ( (*|/) SimpleExp )*

SimpleExp = Id | Number | true | false | '(' Expression ')'

BooleanExp = ArithExp [ (=|>|<) ArithExp | not BooleanExp ]

 

Note that a BooleanExp can be just an ArithExp to include the constants true and false and a simple identifier, but also something like x+1 which should be semantically disallowed. Avoiding this problem with syntax rules would have meant a much more complex grammar. A sample program is:

begin

   int x; bool b;

   x := 1;

   b := true;

   if not b then

      x := 2

   else begin

      int y;

      y := x + 1;

      b := false

   end

end.

The Environment and the Store

In order to handle re-use of names in inner, nested blocks, the store in language L1 must be split into a part that handles local versus non-local variables, and a global part that handles binding of values. The environment will map identifiers to locations, which will be just integers, starting from zero. Each block will get its own environment but environments will be pushed on a stack so that nested environments can be handled. E.g. in the example above, the outer block declares a variable x, so its environment will contain the mapping x -> location 0. The inner block redeclares x, so its enviroment will contain the mapping x -> location 1. This environment will be pushed on a stack of environments, so that using a variable becomes a search backwards from the top of the stack to find the environment where it was declared. Using b in the inner block means looking in the outer environment for its declaration. The store can remain a global data structure as it was in L1.

When a block is exited, its environment is popped from the stack, and any locations used in it can be re-used for another block at the same nesting level. So, in the example below, the other x has location 0, the first inner x has location 1 and so does the second inner x, since its environment takes the place of the first inner block's environment:

 

begin

   int x;    <- location 0

   …

   begin

      int x;  <- location 1

      …

   end;

   …

   begin

      int x;  <- also location 1

      …

   end;

   …

end.

 

Hints

Downloading the files

All you need is the grammar file L2.jjt, and a test file test.l2. Use a separate directory to store the code – don't confuse L1 classes with L2 classes. This sample program is:

 

begin

   int x;

   int p;

   x := 6;

   p := 0;

   begin

      bool b;

      b := true;

      while b do begin

         int pp;

         pp := x * x;

         p := p + pp;

         x := x -1;

         b := x > 0;

      end

   end

end.

Running jjtree, JavaCC and java 1.5

Add the following lines to your .cshrc file and remember to ‘source’ it after the changes.

 

setenv PATH ~rth/public/javacc-3.2/bin:$PATH

setenv PATH ~rth/public/jdk1.5.0_04/bin:$PATH

 

Run jjtree on the .jjt file to generate the .jj file. E.g.:

jjtree l2.jjt

Run javacc on the .jj file to generate the parser classes and the AST classes. E.g.:

javacc l2.jj

Run javac to compile the .java files. E.g.:

javac *.java

Run java with the name of your interpreter class, and the name of the test input file. E.g.:

            java L2Intepreter test.l2

Testing your interpreter

Your interpreter must produce the correct store when given the program in test.l2. Test your interpreter with simpler programs before you give it this one.

What To Turn In

When you are done, make a Java archive with the command ‘jar cvf l2homework.jar *.java l2.jjt’, and submit it through the submission page (accessed from the Homework page).

Due date

Macrh 5th before midnight.