[NEXT] [PREV]    HANDBOOK / CASE STUDY / The Compiler /

Translating Procedures


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.


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:

   Code of body
   Code of local procedure
The code for the body is generated by the predicate Statement, the code for the local procedures is generated by LocalProcedures.


LocalProcedures(Decls) invokes LocalProcedure for each element of the declaration list( Decls).


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.