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(); .) .