Computer Science 301 - 2005

Second tutorial for week 26 - Code generation for "if" statements

The Parva compiler that you were supplied with for Practical 25 contains, among other productions

  Statement<StackFrame frame>
  =  SYNC (   Block<frame>
            | ConstDeclarations
            | VarDeclarations<frame>
            | Assignment
            | IfStatement<frame>
            | WhileStatement<frame>
            | HaltStatement
            | ReturnStatement
            | ReadStatement
            | WriteStatement
            | ";"
            | "stackdump" ";"           (. if (debug) CodeGen.dump(); .)
          ) .

  IfStatement<StackFrame frame>         (. Label falseLabel = new Label(!known); .)
  =  "if" "(" Condition ")"             (. CodeGen.branchFalse(falseLabel); .)
     Statement<frame>                   (. falseLabel.here(); .)
  .

(a) As you will have discovered, extending the IfStatement to allow for an optional "else" clause, on the lines suggested by:

IfStatement = "if" "(" Condition ")" Statement [ "else" Statement ] .

introduces a non-LL(1) feature into the language - which, as it happens is not particularly serious. Statements like

if (a > b) if (c > d) x = y; else x = z;

are handled with the "dangling else" treated as belonging to the most recent if. If one wanted to attach it to an earlier if one would need use a Block to write source code like

    if (a > b) {
      if (c > d) x = y;
    }
    else x = z;

One can remove the dangling else problem in another way - simply forbid the Statement that follows the parenthesized Condition from being another IfStatement.

How would you develop and attribute the Parva grammar if you wanted to limit the Parva language in this way?

  Statement<StackFrame frame>
  =  IfStatement<frame> | ValidInIfStatement<Frame> .

  ValidInIfStatement<StackFrame frame>
  =  SYNC (   Block<frame>
            | ConstDeclarations
            | VarDeclarations<frame>
            | Assignment
            | WhileStatement<frame>
            | HaltStatement
            | ReturnStatement
            | ReadStatement
            | WriteStatement
            | ";"
            | "stackdump" ";"           (. if (debug) CodeGen.dump(); .)
          ) .

  IfStatement<StackFrame frame>         (. Label falseLabel = new Label(!known); .)
  =  "if" "(" Condition ")"             (. CodeGen.branchFalse(falseLabel); .)
     ValidInIfStatement<frame>
     ( "else"                           (. Label outLabel = new Label(!known);
                                           CodeGen.branch(outLabel);
                                           falseLabel.here(); .)
         Statement<frame>               (. outLabel.here(); .)
       | /* no else part */             (. falseLabel.here(); .)
     )

(b) Another form of IfStatement is sometimes suggested:

   IfStatement = "if" "(" Condition ")" Statement
                { "elsif" "(" Condition ")" Statement }
                [ "else" Statement ] .

which would allow a statement like

    if (a < 10) c = 12;
    elsif (a < 20) c = 45;
    elsif (a <= 40) c = 92;
    else write("greater than 40");

How would you attribute the grammar to generate the correct form of code for this extended form of the IfStatement? Does this grammar conform to the LL(1) restrictions? If not, does it matter?

The following production does not generate the best code - one can get unnecessary BRN instructions

  IfStatement<StackFrame frame>         (. Label falseLabel = new Label(!known);
                                           Label outLabel = new Label(!known); .)
  =  "if" "(" Condition ")"             (. CodeGen.branchFalse(falseLabel); .)
       Statement<frame>                 (. CodeGen.branch(outLabel);
                                           falseLabel.here(); .)
     { "elsif" "(" Condition ")"        (. falseLabel = new Label(!known);
                                           CodeGen.branchFalse(falseLabel); .)
       Statement<frame>                 (. CodeGen.branch(outLabel);
                                           falseLabel.here(); .)
     }
     [ "else"  Statement<frame>  ]      (. outLabel.here(); .)
     .

The following is preferable - the BRN instructions are generated only where needed

  IfStatement<StackFrame frame>         (. Label falseLabel = new Label(!known);
                                           Label outLabel = new Label(!known); .)
  =  "if" "(" Condition ")"             (. CodeGen.branchFalse(falseLabel); .)
       Statement<frame>
     {                                  (. CodeGen.branch(outLabel);
                                           falseLabel.here();
                                           falseLabel = new Label(!known); .)
       "elsif" "(" Condition ")"        (. CodeGen.branchFalse(falseLabel); .)
         Statement<frame>
     }
     (   "else"                         (. CodeGen.branch(outLabel);
                                           falseLabel.here(); .)
         Statement<frame>
       | /* no else part */             (. falseLabel.here(); .)
     )                                  (. outLabel.here(); .)
     .


Home  © P.D. Terry