Computer Science 301 - 2006

Tutorial for week 26 - Code generation

(a) Many languages provide for a ForStatement in one or other form. In the practical you have been asked to add a simple Pascal-style for loop to Parva, to allow statements with concrete syntax defined by

       ForStatement = "for" Identifier "=" Expression ("to" | "downto") Expression Statement .

for example

       for i = 1 to 10 write(i);          // forwards  1 2 3 4 5 6 7 8 9 10
       for i = 10 downto 1 write(i);      // backwards 10 9 8 7 6 5 4 3 2 1
       for i = 10 to 5 write(i);          // no effect
       for b = false to true write(b);    // writes "false true"
       for i = i - 1 to i + 6 write(i);   // what does this do?

As discussed in class early last Friday morning, the semantics and implementation of a ForStatement is quite tricky. Here is one suggested way that overcomes some of the problems we discussed. If you were not at the class, tough. Revenge will be sweet in a few weeks time!

Many of these issues can be overcome by a fairly dramatic process. We arrange that the code generation for the generic loops

        for Variable = Expression1 to Expression2 Statement 
        for Variable = Expression1 downto Expression2 Statement 

must yield lower level code of the form

         Temp1 := Expression1                             Temp1 := Expression1
         Temp2 := Expression2                             Temp2 := Expression2
         IF Temp1 > Temp2 THEN GOTO EXIT                  IF Temp1 < Temp2 THEN GOTO EXIT
         Variable := Temp1;                               Variable := Temp1;
  BODY:  Statement                                 BODY:  Statement
         IF Variable = Temp2 THEN GOTO EXIT               IF Variable = Temp2 THEN GOTO EXIT
         Variable := Variable + 1                         Variable := Variable - 1
         GOTO BODY                                        GOTO BODY
  EXIT:                                            EXIT:

The simplest way of handling all these issues in the PVM system is to note that the obvious calls to the parsing routines

           Designator
           Expression
           Expression

will ensure that code to push the address of the control variable and the values of the temporary variables will have been generated by the time the auxiliary Statement is encountered. At this point code must be generated for the initial test, and if we avail ourselves of the ability to define extensions to the opcode set of the PVM we can generate a special opcode at this point that will leave these three values on the stack so that they can be used again later. Similarly, after generating the code for the Statement we can generate a second special opcode that can be responsible for the final test and possible increment of the control variable. One last complication is that once the for loop has completed execution we have to discard these three elements from the stack, which suggests the introduction of yet another special opcode.

Develop these ideas in detail.

(b) The PVM has opcodes LDL N and STL N, as you will recall from an earlier practical. And our CodeGen class has methods for generating these. But the attributed parser does not do so - all code for loading and storing variables only makes use of the LDA, LDV and STO opcodes.

How would you change the parser routines to generate LDL and STL opcodes where it can?

         Temp1 := Expression1                             Temp1 := Expression1
         Temp2 := Expression2                             Temp2 := Expression2
         IF Temp1 > Temp2 THEN GOTO EXIT                  IF Temp1 < Temp2 THEN GOTO EXIT
         Variable := Temp1;                               Variable := Temp1;
  BODY:  Statement                                 BODY:  Statement
         IF Variable = Temp2 THEN GOTO EXIT               IF Variable = Temp2 THEN GOTO EXIT
         Variable := Variable + 1                         Variable := Variable - 1
         GOTO BODY                                        GOTO BODY
  EXIT:                                            EXIT:

  ForStatement<StackFrame frame>





  =  "for" Ident<out name>







     "=" Expression<out expType>




     ( "to" | "downto"
     )




     Expression<out expType>





     Statement<frame>


  .
    class DesType {
    // Objects of this type are associated with l-value and r-value designators
      public Entry entry;          // the identifier properties
      public int type;             // designator type (not always the entry type)



      public DesType(Entry entry) {
        this.entry = entry;
        this.type = entry.type;

      }
    } // end DesType



  Designator<out DesType des>           (. String name;
                                           int indexType; .)
  =  Ident<out name>                    (. Entry entry = Table.find(name);
                                           if (!entry.declared)
                                             SemError("undeclared identifier");
                                           des = new DesType(entry);

                                           if (entry.kind == Entry.Var) CodeGen.loadAddress(entry); .)


     [  "["                             (. if (isRef(des.type)) des.type--;
                                           else SemError("unexpected subscript");
                                           if (entry.kind != Entry.Var)
                                             SemError("unexpected subscript");

                                           CodeGen.dereference(); .)

            Expression<out indexType>   (. if (!isArith(indexType)) SemError("invalid subscript type");
                                           CodeGen.index(); .)
        "]"

     ] .




  OneVar<StackFrame frame, int type>    (. int expType; .)
  =                                     (. Entry var = new Entry(); .)
     Ident<out var.name>                (. var.kind = Entry.Var;
                                           var.type = type;
                                           var.offset = frame.size;
                                           frame.size++; .)

     [ AssignOp                         (. CodeGen.loadAddress(var); .)
       Expression<out expType>          (. if (!compatible(var.type, expType))
                                             SemError("incompatible types in assignment");

                                           CodeGen.assign(var.type); .)

     ]                                  (. Table.insert(var); .)

  .


  Assignment                            (. int expType;
                                           DesType des; .)
  =  Designator<out des>                (. if (des.entry.kind != Entry.Var)
                                             SemError("invalid assignment"); .)

     AssignOp

     Expression<out expType>            (. if (!compatible(des.type, expType))
                                             SemError("incompatible types in assignment");

                                           CodeGen.assign(des.type); .)

     WEAK ";" .



  ReadElement                           (. String str;
                                           DesType des; .)
  =   StringConst<out str>              (. CodeGen.writeString(str); .)

    | Designator<out des>               (. if (des.entry.kind != Entry.Var)
                                             SemError("wrong kind of identifier");


                                           switch (des.type) {
                                             case Entry.intType:
                                             case Entry.boolType:
                                               CodeGen.read(des.type); break;
                                             default:
                                               SemError("cannot read this type"); break;
                                           } .) .


  Factor<out int type>                  (. int value = 0;
                                           type = Entry.noType;
                                           int size;
                                           DesType des;
                                           ConstRec con; .)
  =    Designator<out des>              (. type = des.type;

                                           switch (des.entry.kind) {
                                             case Entry.Var:

                                               CodeGen.dereference();
                                               break;

                                             case Entry.Con:
                                               CodeGen.loadConstant(des.entry.value);
                                               break;

                                             default:
                                               SemError("wrong kind of identifier");
                                               break;
                                           } .)

     | Constant<out con>                (. type = con.type;
                                           CodeGen.loadConstant(con.value); .)
     ...
  .



Home  © P.D. Terry