(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