We have just described how a source program is translated into an internal representation. We now discuss how to translate the internal representation into a target program.
150 'action' Translate(Program: DECL) 151 'rule' Translate(P): 152 SetCurrentNesting(0) 153 Procedure(P) 154 Emit 155 'action' Procedure(Proc: DECL) 156 'rule' Procedure(dcl(Ident, proc(Formals,Locals,Body), Pos)) : 157 GetCurrentNesting(-> OuterLevel) 158 SetCurrentNesting(OuterLevel+1) 159 DeclareList(Formals, 3 -> SizeFormals) 160 DeclareList(Locals, SizeFormals+3 -> SizeLocals) 161 ENT(SizeLocals) 162 Statement(Body) 163 RET 164 LocalProcedures(Locals) 165 UndeclareList(Locals) 166 UndeclareList(Formals) 167 SetCurrentNesting(OuterLevel) 168 'action' LocalProcedures(Decls: DECLLIST) 169 'rule' LocalProcedures(decllist(Head, Tail)) : 170 LocalProcedure(Head) 171 LocalProcedures(Tail) 172 'rule' LocalProcedures(nil) 173 'action' LocalProcedure(DECL) 174 'rule' LocalProcedure(dcl(Ident, proc(Fs, Ds, S), Pos)) : 175 HasMeaning (Ident -> object(procobj(Start,_),_,_)) 176 LAB(Start) 177 Procedure(dcl(Ident, proc(Fs, Ds, S), Pos)) 178 'rule' LocalProcedure(Decl) : |
|
The predicate Translate(Program) is invoked in the root clause of the specification. The whole program is merely represented as a simple procedure without parameters. Hence, we can simply use Procedure to process the given abstract syntax tree. Before calling Procedure, we initialize the current nesting level of procedures (which is implemented as a global variable). After generating the code, we invoke emit to write it to the target file.
Procedure
The predicate Procedure(Proc) handles a single procedure declaration the abstract syntax of which is
dcl(Ident, proc(Formals, Locals, Body), Pos)The procedure has a name given by Ident; formal parameters and local declarations are given by Formals and Locals; the procedure body is given by Body.
First, the current procedure nesting is updated accordingly. It is reset to its old value at the end of the rule.
During the processing of Body and local procedures, the formal parameters and the local declarations must be accessible. Hence, they are made visible by processing Formals and Locals with the predicate DeclareList. Outside the given procedure, the formal parameters and local declarations cannot be used. Hence, they are made invisible again ( UndeclareList) after processing the body and the local procedures.
DeclareList (to be discussed later) has additional parameters: DeclareList(X, Loc -> Size) indicates that the items in X are stored from location Loc and that they occupy Size units.
The stack frame of the procedure is organized as follows: 3 units for administrative data (static link, dynamic link, return address), SizeFormal units as to store parameters, and SizeLocals units to store local variables.
The target code of the procedure is given as follows:
ENT(SizeLocals) Code of body RET Code of local procedureThe code for the body is generated by the predicate Statement, the code for the local procedures is generated by LocalProcedures.
LocalProcedures
LocalProcedures(Decls) invokes LocalProcedure for each element of the declaration list( Decls).
LocalProcedure
If LocalProcedure(Decl) is invoked with a procedure declaration, it processes this declaration. Otherwise the passed element is skipped. A procedure is processed by Procedure (in the case of a local procedure, we first emit a start label).
We now refine the processing of procedure bodies. We discuss statements, expressions, and designators.