A Python-like version of the ForStatement has syntax that can be described by
ForStatement = "for" Ident "in" "(" Expression { "," Expression } ")" Statement .
The suggested implementation strategy was as follows:
At run time, just before the Statement is executed, the top elements on the stack could be set up in a manner that is exemplified by the statement
for i in (35, 64, -1, 235) write(i); // loop to be executed 4 times ──────┬───────┬───────┬───────┬───────┬───────┬────────┬───────── ... │ 4 │ 235 │ -1 │ 64 │ 35 │ adr i │ .... ──────┴───────┴───────┴───────┴───────┴───────┴────────┴─────────
In this example the 4 on the top of the stack can then be used as a counter and decremented on each pass of the loop. The values below that can be assigned, one by one on each pass, to the designator whose address is lurking at the bottom of this segment.
The constraints that we must enforce are (a) the identifier denoting the control variable must have been declared and be of the variable kind (b) the expressions in the list must all return a value that is type-compatible with the type of the control variable. The code needed should be familiar by now!
ForStatement<StackFrame frame> (. type = Entry.noType, expType; String name; .) = "for" Ident<out name> (. Entry var = Table.find(name); type = var.type; if (!var.declared) SemError("undeclared identifier"); if (var.kind != Entry.Var) SemError("illegal control variable"); .) "in" "(" Expression<out expType> (. if (!compatible(type, expType)) SemError("type mismatch"); .) { WEAK "," Expression<out expType> (. if (!compatible(type, expType)) SemError("type mismatch"); .) } ")" Statement<frame> .
Adding the code generation is fairly straightforward:
ForStatement<StackFrame frame> (. type = Entry.noType, expType, expCount = 1; String name; .) = "for" Ident<out name> (. Entry var = Table.find(name); type = var.type; if (!var.declared) SemError("undeclared identifier"); if (var.kind != Entry.Var) SemError("illegal control variable"); * CodeGen.loadAddress(var); .) "in" "(" Expression<out expType> (. if (!compatible(type, expType)) SemError("type mismatch"); .) { WEAK "," Expression<out expType> (. if (!compatible(type, expType)) SemError("type mismatch"); expCount++; .) * } ")" (. CodeGen.loadConstant(expCount); * Label loopBody = new Label(known); * CodeGen.nextControl(expCount); .) * Statement<frame> (. CodeGen.testFor(loopBody); * CodeGen.exitFor(expCount); .) .
Notes
public static void nextControl(int count) { // Generates code to set the for loop control on each pass emit(PVM.sfl); emit(count); } public static void testFor(Label startLoop) { // Generates code to decrement the count after each pass through loop // and test to see whether another iteration is needed emit(PVM.tfl); emit(startLoop.address()); } public static void exitFor(int count) { // Generates code to discard the expression list used in the for loop emit(PVM.efl); emit(count); }
for i in (one, two, three) statement
which generates code
LDA i <one> <two> <three> LDC 3 L1 SFL 3 <statement> TFL L1 EFL 3
case sfl: // set up the for loop control variable mem[mem[cpu.sp + next() + 1]] = mem[cpu.sp + mem[cpu.sp]]; break; case tfl: // test for loop continuation target = next(); mem[cpu.sp]--; if (mem[cpu.sp] > 0) cpu.pc = target; break; case efl: // end for loop - clean up stack cpu.sp += next() + 2; break;
ForStatement = "for" Designator "in" "(" Expression { "," Expression } ")" Statement .
and, if so, how the code above would require modification.