home *** CD-ROM | disk | FTP | other *** search
- @=~
-
- ~A~<Code Generation~>
-
- The purpose of code generation is to translate the concepts of the source
- language into the concepts of the target machine.
- No errors are detected or reported during code generation.
-
- Code generation is an attribution process.
- Given the information provided by type analysis, it
- determines the amount of memory required to store objects of each type,
- allocates storage to parameters and variables,
- and then produces a target implementation of the algorithm.
-
- ~B
-
- Every instruction output by the compiler consists of an operation part
- followed by zero or more operands.
- The operation parts are provided as literal strings by the templates
- described in Chapter 8.
- Each template has a name, and the code corresponding to the template is
- generated by invoking a function whose name is ~{PTG~} followed by the
- template name.
- For example, code for the instruction ~{Variable(Level,Displ)~} is
- generated by the call ~{PTGVariable(Level,Displ)~}.
- The result of ~{PTGVariable(Level,Displ)~} is the generated code in the
- form of a ~{PTGNode~} value that can be used as an argument to other code
- generation functions.
-
- The generated code is not actually emitted by the generation functions, as
- it is by Brinch-Hansen's ~{Emit~} functions.
- Instead, an explicit data structure is constructed that contains the
- generated code.
- This data structure is a tree, and it is actually output by passing its
- root to the function ~{PTGOut~}:
-
- ~$~<Operation parts~>==~{
- SYMBOL Program COMPUTE PTGOut(THIS.Code) END;
- ~}
-
- ~B~<Variable addressing~>
-
- Variable access in the Pascal computer is described in Section 8.1:
- The address generated by the compiler specifies the number of steps that
- must be taken along the static chain to obtain the address of the proper
- activation record, and the relative address of the variable within that
- activation record.
- To compute these two components, the compiler must gather information from
- the program's declarations and store it in the definition table.
- An address can then be generated by combining information about the object
- with information determined from the context.
-
- ~C
-
- The compiler associates a ~/static nesting level~/ with the program and
- with each procedure.
- It is 1 for the program, 2 for each procedure declared in the program, 3
- for each procedure declared in a level-2 procedure, and so forth.
- A ~{Contour~} is is a phrase that has a static nesting level associated
- with it.
- Each variable is then given a property whose value is the static nesting
- level at which that variable was declared.
-
- ~$~<Static nesting level property~>==~{
- Level: int;
- ~}
-
- ~$~<Determination of the static nesting level~>==~{
- ATTR Level: int;
- SYMBOL Contour COMPUTE INH.Level=ADD(INCLUDING Contour.Level,1); END;
-
- SYMBOL Program INHERITS Contour COMPUTE INH.Level=1; END;
- SYMBOL ProcedureBlock INHERITS Contour END;
- ~}
-
- The number of steps that must be taken along the static chain to obtain the
- address of the activation record containing a variable is the difference
- between the static nesting level of the procedure containing the reference
- and the static nesting level of the procedure in which the variable was
- declared.
-
- ~$~<Static chain steps to find the proper activation record address~>~M==~{
- PTGNumb(SUB(INCLUDING Contour.Level,GetLevel(VariableNameUse.Key,0)))
- ~}
-
- There are two kinds of PTG functions: those that create data leaves and
- those that create nodes without data.
- Data can be stored only at data leaves, and a single data leaf can store
- an arbitrary number of data items of arbitrary types.
- The number of static chain steps to find the proper activation record
- address is an integer datum that must be stored at a data leaf, and
- ~{PTGNumb~} is a library function that creates a data leaf holding a
- single integer value.
- This function is obtained by instantiating the generic library module
- ~{$/Tool/lib/Tech/LeafPtg.gnrc~}.
-
- ~C
-
- In order to compute relative addresses within an activation record,
- the compiler needs to know the size of each variable.
- Brinch-Hansen, in his Algorithm 9.3, computes the size of each declared
- object at the point of declaration from the definition of its type.
- Thus the size of objects of a particular type is computed once for every
- object declared to be of that type.
- A better approach is to compute an appropriate size when a type is defined,
- and then use a property of the type to make that size available
- when the declaration of a new object of that type is encountered.
-
- ~$~<Storage requirement property~>==~{
- Space: StorageRequired;
- ~}
-
- Because all symbols must be defined before they are used in Pascal-,
- storage requirements can be computed in textual order.
- The sizes of the standard types ~{Boolean~} and ~{integer~} are determined
- by the specification, while the sizes of user-defined types are determined
- by the compiler.
-
- ~$~<Determination of storage requirements~>+=~{
- CHAIN Storage: VOID;
-
- SYMBOL StandardBlock COMPUTE
- CHAINSTART HEAD.Storage=
- ORDER(
- SetSpace(IntegerKey,NewStorage(1,1,0),NoStorage),
- SetSpace(BooleanKey,NewStorage(1,1,0),NoStorage));
- END;
- ~}
-
- In the Pascal computer, each value of standard type occupies one memory
- location.
-
- An array type requires storage equal to the number of elements times the
- storage requirement of a single element.
-
- ~$~<Determination of storage requirements~>+=~{
- RULE ArrayDef: NewArrayType ::= 'array' '[' IndexRange ']' 'of' TypeNameUse
- COMPUTE
- NewArrayType.Storage=
- SetSpace(
- INCLUDING NewType.Key,
- ArrayStorage(
- ADD(SUB(IndexRange.UpperBound,IndexRange.LowerBound),1),
- GetSpace(TypeNameUse.Type,NoStorage)),
- NoStorage)
- DEPENDS_ON NewArrayType.Storage;
- END;
- ~}
-
- ~{ArrayStorage~} is an operation exported by the data mapping module of the
- Eli library.
- It computes the storage requirements for an array of objects whose
- individual storage requirements are known.
- The first argument of ~{ArrayStorage~} must be the number of elements in
- the array, and the second must be the storage requirements of the element
- type.
-
- The data mapping module is an abstract data type, not a generic module.
- Therefore it need not be instantiated, but
- its interface must be made available:
-
- ~$~<Data mapping module interface~>==~{
- #include "storage.h"
- ~}
-
- Record types are more complex, because in addition to determining the total
- storage requirement of the record, the compiler must assign a relative
- address to each field.
- The compiler begins by establishing an empty storage area for the record.
- It then processes the field definitions in textual order, concatenating the
- storage required by each field to the record's storage area.
- The concatenation operation ~{Concatenate~} is exported by the data mapping
- module.
- It takes two arguments: the storage requirements of the area to which the
- field must be added and the storage requirements of the field type.
- The function returns the address of the field relative to
- the beginning of the record, and updates the storage requirement of the
- area to reflect the addition of the field.
-
- The relative address returned by ~{Concatenate~} is stored as the ~{Displ~}
- property of the field object (see the next section).
-
- ~$~<Determination of storage requirements~>+=~{
- SYMBOL NewRecordType: Area: StorageRequired;
-
- RULE RecordDef: NewRecordType ::= 'record' FieldList 'end'
- COMPUTE
- NewRecordType.Area=NewStorage(0,1,0) DEPENDS_ON NewRecordType.Storage;
- NewRecordType.Storage=
- SetSpace(INCLUDING NewType.Key,NewRecordType.Area,NoStorage);
- END;
-
- SYMBOL FieldNameDef COMPUTE
- THIS.Storage=
- SetDispl(
- THIS.Key,
- Concatenate(INCLUDING NewRecordType.Area,INCLUDING Group.Space),
- 0)
- DEPENDS_ON THIS.Storage;
- END;
- ~}
-
- Objects (variables, parameters, fields) are declared in groups in Pascal-:
- If several objects of the same type are being declared, the type is only
- stated once.
- This mechanism requires that the storage requirement of the type be made
- the value of an attribute of the phrase representing the group of objects,
- so that it will be available at all of the object declarations:
-
- ~$~<Distributing a storage requirement~>==~{
- ATTR Space: StorageRequired;
-
- SYMBOL Group COMPUTE
- SYNT.Space=
- GetSpace(CONSTITUENT TypeNameUse.Type,NoStorage)
- DEPENDS_ON THIS.Storage;
- END;
-
- SYMBOL VariableDefinition INHERITS Group END;
- SYMBOL ParameterDefinition INHERITS Group END;
- SYMBOL RecordSection INHERITS Group END;
- ~}
-
- ~C
-
- The relative address of an object within its storage area (a record for
- fields, an activation record for parameters and variables)
- is a property of that object.
-
- ~$~<Relative address property~>==~{
- Displ: int;
- ~}
-
- A relative address is computed from an object's declaration,
- in the process of allocating space in a storage area.
- Allocation for field objects was specified in the last section,
- and allocation for objects in activation records is similar.
- The major difference is that an activation record has more structure than a
- record type.
-
- Three kinds of information are stored in an activation record:
- parameters, local variables, and ~/overhead~/ (information like the static
- chain, needed to maintain the relationships among activation records).
- Parameter and local variable storage is determined by the declarations for
- the ~{Contour~}, but storage for the overhead is determined by the target
- computer.
- Overhead information is maintained as a side effect of executing the
- instructions of the Pascal computer, and hence its size and placement
- depend on the implementation of those instructions.
- Brinch-Hansen, in Section 8.2 of his book, defines the overhead information
- to be three storage locations at the beginning of the storage allocated for
- variables.
- The first location is the static chain, holding the address of the
- activation record of the enclosing procedure, the second location is the
- ~/dynamic chain~/, holding the contents of the base register during
- execution of the caller, and the third location is the ~/return address~/,
- holding the location of the instruction at which execution should resume
- when the current procedure terminates.
- In the C implementation of the Pascal computer that accompanies this
- specification, there is no explicit return address.
- The third location of the overhead information is therefore free to hold
- the address of the parameter portion of the activation record.
-
- ~$~<Storage allocation~>+=~{
- SYMBOL Contour: Parameters, Variables: StorageRequired;
- SYMBOL Contour COMPUTE
- INH.Parameters=NewStorage(0,1,0);
- INH.Variables=NewStorage(3,1,0);
- END;
- ~}
-
- Parameter and variable objects have the ~{Displ~} property, just like field
- objects, but they also have the ~{Level~} property to record the static
- nesting level of the contour in which they are declared.
- Also, the storage requirement for a variable parameter is independent of
- its type because only the address of the parameter's value is stored.
- An address occupies one storage unit of the Pascal computer.
-
- ~$~<Storage allocation~>+=~{
- RULE VarParmDef:
- ParameterDefinition ::= 'var' ParameterNameDefList ':' TypeNameUse
- COMPUTE
- ParameterDefinition.Space=NewStorage(1,1,0);
- END;
-
- SYMBOL VariableNameDef COMPUTE
- THIS.Storage=
- ORDER(
- SetDispl(
- THIS.Key,
- Concatenate(INCLUDING Contour.Variables,INCLUDING Group.Space),
- 0),
- SetLevel(THIS.Key,INCLUDING Contour.Level,0))
- DEPENDS_ON THIS.Storage;
- END;
-
- SYMBOL ParameterNameDef COMPUTE
- THIS.Storage=
- ORDER(
- SetDispl(
- THIS.Key,
- Concatenate(INCLUDING Contour.Parameters,INCLUDING Group.Space),
- 0),
- SetLevel(THIS.Key,INCLUDING Contour.Level,0))
- DEPENDS_ON THIS.Storage;
- END;
- ~}
-
- ~C
-
- Object access code pushes the address of the desired object onto the
- processor's stack in the Pascal computer.
- Access to an object of one of the standard types is specified in Pascal- by
- giving the name of the object, while access to an object of a user-defined
- type may involve subscripting or field selection.
- In that case the address of the object (array or record) containing the
- desired object is placed on the stack and then the appropriate selection
- operations are executed.
-
- Section 8.1 pointed out the differences among the accessing operations for
- variables, value parameters and variable parameters.
- In addition, as noted in Section 2.3.2, a ~{VariableNameUse~} may actually
- be a constant name.
- Since constants are not stored in memory, the code generated for a constant
- name must push the constant itself, not the address of the constant, onto
- the processor's stack.
-
- ~$~<Accessing an object~>==~{
- RULE VarIdn: VariableAccess ::= VariableNameUse
- COMPUTE
- VariableAccess.Code=
- IF(EQ(VariableAccess.Kind,Constantx),
- PTGConstant(PTGNumb(GetValue(VariableNameUse.Key,0))),
- IF(EQ(VariableAccess.Kind,ValueParameter),
- PTGValParam(
- ~<Static chain steps to find the proper activation record address~>,
- PTGNumb(GetDispl(VariableNameUse.Key,0))),
- IF(EQ(VariableAccess.Kind,VarParameter),
- PTGVarParam(
- ~<Static chain steps to find the proper activation record address~>,
- PTGNumb(GetDispl(VariableNameUse.Key,0))),
- PTGVariable(
- ~<Static chain steps to find the proper activation record address~>,
- PTGNumb(GetDispl(VariableNameUse.Key,0))))));
- END;
-
- RULE Index: VariableAccess ::= VariableAccess '[' Expression ']'
- COMPUTE
- VariableAccess[1].Code=
- PTGIndex(
- VariableAccess[2].Code,
- Expression.Code,
- PTGNumb(GetLowerBound(VariableAccess[2].Type,0)),
- PTGNumb(GetUpperBound(VariableAccess[2].Type,0)),
- PTGNumb(
- StorageSize(
- GetSpace(GetElementType(VariableAccess[2].Type,NoKey),NoStorage))),
- PTGNumb(LINE));
- END;
-
- RULE Select: VariableAccess ::= VariableAccess '.' FieldNameUse
- COMPUTE
- VariableAccess[1].Code=
- PTGField(
- VariableAccess[2].Code,
- PTGNumb(GetDispl(FieldNameUse.Key,0)));
- END;
- ~}
-
- ~B
-
- Code for an expression always leaves the value of the expression at the top
- of the processor's stack.
- If the expression is a ~{Numeral~} or a ~{VariableAccess~} then that
- value is obtained from either an operation or memory, respectively.
- Because a ~{VariableAccess~} may actually be a reference to a constant, the
- compiler must check its ~{Kind~} to determine whether the value at the top of
- the processor's stack is a value or an address at which a value can be found.
- When the top element of the processor's stack is an address, the compiler
- must emit a ~{Value~} operation to obtain the contents of that address if
- the context demands a value.
-
- ~$~<Expression code~>+=~{
- RULE Denotation: Expression ::= Numeral
- COMPUTE
- Expression.Code=PTGConstant(PTGNumb(Numeral.Value));
- END;
-
- RULE VariableExpr: Expression ::= VariableAccess
- COMPUTE
- Expression.Code=
- IF(OR(Expression.ExpectedVar,EQ(VariableAccess.Kind,Constantx)),
- VariableAccess.Code,
- PTGValue(
- VariableAccess.Code,
- PTGNumb(StorageSize(GetSpace(VariableAccess.Type,NoStorage)))));
- END;
- ~}
-
- If the expression is neither a ~{Numeral~} nor a ~{VariableAccess~} then
- its value is obtained by applying the appropriate operator to one or two
- operands.
- The code generation process is independent of the particular operator,
- which is supplied by the operator child of the expression,
- although it does depend on the number of operands.
- LIDO does not allow an attribute to be applied as a function, however, so a
- circumlocution is necessary:
-
- ~$~<Expression code~>+=~{
- ATTR Op: PtgFunc;
-
- RULE Monadic: Expression ::= Unop Expression
- COMPUTE
- Expression[1].Code=Apply1(Unop.Op,Expression[2].Code);
- END;
-
- RULE Dyadic: Expression ::= Expression Binop Expression
- COMPUTE
- Expression[1].Code=Apply2(Binop.Op,Expression[2].Code,Expression[3].Code);
- END;
- ~}
-
- ~{PtgFunc~}, ~{Apply1~} and ~{Apply2~} are defined in C:
-
- ~$~<PTG functions as attributes~>==~{
- typedef PTGNode (*PtgFunc)();
- #define Apply1(f,x) ((*f)(x))
- #define Apply2(f,x,y) ((*f)(x,y))
- ~}
-
- These definitions say that ~{PtgFunc~} objects are functions that return
- PTG nodes, ~{Apply1~} applies its first argument to its second, and
- ~{Apply2~} applies its first argument to its second and third.
-
- All of the operator rules have exactly the same form, defining the ~{Op~}
- attribute of the left-hand side as the appropriate PTG function:
-
- ~$~<Operator encoding~>~(~3~)~M==~{
- RULE r~1: ~2 ::= ~3 COMPUTE ~2.Op=PTG~1 END;
- ~}
-
- ~$~<Expression code~>+=~{
- ~<Operator encoding~>~(Lss~,Binop~,'<'~)
- ~<Operator encoding~>~(Leq~,Binop~,'<='~)
- ~<Operator encoding~>~(Gtr~,Binop~,'>'~)
- ~<Operator encoding~>~(Geq~,Binop~,'>='~)
- ~<Operator encoding~>~(Equ~,Binop~,'='~)
- ~<Operator encoding~>~(Neq~,Binop~,'<>'~)
-
- ~<Operator encoding~>~(Add~,Binop~,'+'~)
- ~<Operator encoding~>~(Sub~,Binop~,'-'~)
- ~<Operator encoding~>~(Mul~,Binop~,'*'~)
- ~<Operator encoding~>~(Div~,Binop~,'div'~)
- ~<Operator encoding~>~(Mod~,Binop~,'mod'~)
-
- ~<Operator encoding~>~(Neg~,Unop~,'-'~)
- ~<Operator encoding~>~(Nop~,Unop~,'+'~)
-
- ~<Operator encoding~>~(And~,Binop~,'and'~)
- ~<Operator encoding~>~(Or~,Binop~,'or'~)
- ~<Operator encoding~>~(Not~,Unop~,'not'~)
- ~}
-
- ~B
-
- A ~{Statement~} is a sequence of operations, which may be empty.
- The processor's stack is always empty before the operations of a statement
- are executed and after their execution is complete.
- Thus a statement may affect the state of the memory or external devices,
- but it neither expects nor yields a value.
- For example, the assignment statement consists of a sequence of operations
- that push the address of the variable to be assigned onto the processor's
- stack, push the value to be assigned, and then carry out the assignment
- removing both elements from the processor's stack.
-
- ~$~<Statement code~>+=~{
- RULE Empty: Statement ::=
- COMPUTE
- Statement.Code=PTGNULL;
- END;
-
- RULE Assign: Statement ::= VariableAccess ':=' Expression
- COMPUTE
- Statement.Code=
- PTGAssignmentStatement(
- VariableAccess.Code,
- Expression.Code,
- PTGNumb(StorageSize(GetSpace(VariableAccess.Type,NoStorage))));
- END;
-
- RULE Compound: Statement ::= CompoundStatement
- COMPUTE
- Statement.Code=CompoundStatement.Code;
- END;
-
- SYMBOL CompoundStatement COMPUTE
- SYNT.Code=
- CONSTITUENTS Statement.Code
- SHIELD Statement
- WITH (PTGNode, PTGSequence, IDENTICAL, PTGNull);
- END;
- ~}
-
- The ~{CONSTITUENTS~} construct gathers all of the ~{Code~} attributes of
- component ~{Statement~} nodes, using ~{PTGSequence~} to combine them
- pairwise.
- Note, however, that many ~{Statement~} nodes are actually the roots of
- subtrees that contain ~{Statement~} nodes themselves.
- The ~{SHIELD~} clause prevents the ~{CONSTITUENTS~} construct from
- gathering the ~{Code~} attributes of the ~{Statement~} nodes within such
- subtrees.
-
- Statements that alter the normal sequence of operations must be able to
- nominate a successor to the current operation.
- Section 8.3 described how operations can be named via the ~{DefAddr~}
- pseudo-operation.
- The compiler must generate these names; it does so by obtaining a sequence
- of unique integers from the ~{NewInteger~} module:
-
- ~$~<Unique integers~>==~{
- static int Next = 1; /* Next integer to be delivered */
-
- int NewInteger() { return Next++; }
- ~}
-
- The number of labels needed by the statement depends on its internal
- structure, described in Section 8.3.
-
- ~$~<Statement code~>+=~{
- RULE While: Statement ::= 'while' Expression 'do' Statement
- COMPUTE
- Statement[1].Code=
- PTGWhileStatement(
- PTGNumb(NewInteger()),
- Expression.Code,
- Statement[2].Code,
- PTGNumb(NewInteger()));
- END;
-
- RULE OneSided: Statement ::= 'if' Expression 'then' Statement
- COMPUTE
- Statement[1].Code=
- PTGOneSided(
- Expression.Code,
- Statement[2].Code,
- PTGNumb(NewInteger()));
- END;
-
- RULE TwoSided: Statement ::= 'if' Expression 'then' Statement 'else' Statement
- COMPUTE
- Statement[1].Code=
- PTGTwoSided(
- Expression.Code,
- Statement[2].Code,
- PTGNumb(NewInteger()),
- Statement[3].Code,
- PTGNumb(NewInteger()));
- END;
- ~}
-
- ~B
-
- Most of the code for a procedure definition is generated by its children.
- The storage requirements must be summarized and a label generated so that
- invocations can refer to the procedure.
-
- ~$~<Procedure code~>+=~{
- ATTR Label: int;
-
- RULE ProcDef:
- ProcedureDefinition ::= 'procedure' ProcedureNameDef ProcedureBlock ';'
- COMPUTE
- .Label=NewInteger();
- ProcedureDefinition.Code=
- PTGProcedureDefinition(
- PTGNumb(StorageSize(ProcedureBlock.Parameters)),
- PTGNumb(StorageSize(ProcedureBlock.Variables)),
- PTGNumb(0), /*Temp size*/
- PTGNumb(.Label),
- PTGNumb(LINE),
- CONSTITUENTS ProcedureDefinition.Code
- SHIELD ProcedureDefinition
- WITH (PTGNode, PTGSequence, IDENTICAL, PTGNull),
- CONSTITUENTS CompoundStatement.Code
- SHIELD (ProcedureDefinition, CompoundStatement)
- WITH (PTGNode, PTGSequence, IDENTICAL, PTGNull))
- DEPENDS_ON ProcedureBlock.Storage;
- ProcedureBlock.Storage=
- ORDER(
- SetLevel(ProcedureNameDef.Key,ProcedureBlock.Level,0),
- SetLabel(ProcedureNameDef.Key,.Label,0))
- DEPENDS_ON ProcedureDefinition.Storage;
- END;
- ~}
-
- The ~{SHIELD~} clauses in this rule avoid duplication of code:
- ~{CONSTITUENTS CompoundStatement.Code~} would gather the bodies of nested
- procedures if it could penetrate the subtrees rooted in
- ~{ProcedureDefinition~} nodes.
-
- In addition to the ~{Level~} property that it shares with other objects, a
- procedure name must have the procedure's label as a property.
-
- ~$~<Label property~>==~{
- Label: int;
- ~}
-
- The label property is accessed at the procedure call.
-
- Read and write statements in Pascal- have the form of procedure calls, but
- they are implemented by distinct operations of the Pascal computer.
- They must therefore be recognized specially during code generation.
-
- When a user-defined procedure is invoked, it must be provided with the
- address of the activation record of the procedure in which it was declared.
- That address can be found by stepping along the static chain, exactly as in
- the case of variable addressing.
- There is a small difference, however:
- The number of steps is one larger than the difference between the current
- static nesting level and the static nesting level of the procedure being
- called.
- The reason is that that address sought is the activation record address for
- the procedure in which the called procedure was declared; the called
- procedure itself has no activation record until the ~{ProcCall~} operation
- (Section 8.4) has been executed.
-
- ~$~<Steps to find the called procedure's environment~>==~{
- PTGNumb(
- ADD(
- SUB(INCLUDING Contour.Level,GetLevel(ProcedureNameUse.Key,0)),
- 1))
- ~}
-
- ~$~<Procedure code~>+=~{
- RULE Call: Statement ::= ProcedureNameUse ActualParameterList
- COMPUTE
- .Code=CONSTITUENTS Expression.Code SHIELD Expression
- WITH (PTGNode, PTGSequence, IDENTICAL, PTGNull);
- Statement.Code=
- IF(EQ(ProcedureNameUse.Key,ReadKey),
- PTGReadStatement(.Code),
- IF(EQ(ProcedureNameUse.Key,WriteKey),
- PTGWriteStatement(.Code),
- PTGProcedureStatement(
- .Code,
- ~<Steps to find the called procedure's environment~>,
- PTGNumb(GetLabel(ProcedureNameUse.Key,0)))))
- DEPENDS_ON Statement.Storage;
- END;
- ~}
-
- The ~{SHIELD~} clause forces the ~{CONSTITUENTS~} construct to gather the
- ~{Code~} attributes only from the argument expressions, and not from any of
- their components.
-
- ~B
-
- The code for the program definition is almost identical to the code for a
- procedure definition.
- There are no parameters for the program, and since the program is not
- invoked there is no need for a ~{Label~} property.
-
- ~$~<Program code~>==~{
- RULE Source: Program ::= 'program' ProgramName ';' BlockBody '.'
- COMPUTE
- Program.Code=
- PTGText(
- PTGProgram(
- PTGNumb(StorageSize(Program.Variables)),
- PTGNumb(0), /*Temp size*/
- PTGNumb(LINE),
- CONSTITUENTS CompoundStatement.Code
- SHIELD (ProcedureDefinition,CompoundStatement)
- WITH (PTGNode, PTGSequence, IDENTICAL, PTGNull)),
- CONSTITUENTS ProcedureDefinition.Code
- SHIELD ProcedureDefinition
- WITH (PTGNode, PTGSequence, IDENTICAL, PTGNull));
- END;
- ~}
-
- The ~{SHIELD~} clauses prevent duplicate code:
- ~{CONSTITUENTS CompoundStatement.Code~} would gather the bodies of all
- nested procedures as well as the body of the program if it were allowed to
- penetrate the subtrees rooted in ~{ProcedureDefinition~} nodes.
-
- ~B~<Specification files for code generation~>
-
- Five kinds of specifications are needed to define the Pascal- code
- generation problem to Eli.
-
- ~C
-
- A type-~{lido~} file describes the attribution needed to gather the
- information and relate the generated code fragments.
- Eli will merge these attributions with others specified in this document
- and create a tree traversal algorithm.
-
- ~O~<code.lido~>~{
- ATTR Code: PTGNode;
- ~<Operation parts~>
- ~<Determination of the static nesting level~>
- ~<Determination of storage requirements~>
- ~<Distributing a storage requirement~>
- ~<Storage allocation~>
- ~<Accessing an object~>
- ~<Expression code~>
- ~<Statement code~>
- ~<Procedure code~>
- ~<Program code~>
- ~}
-
- ~C
-
- A type-~{c~} file describes a problem by giving its solution.
- In the case of the code generation, the problem was that of generating
- unique labels.
-
- ~O~<code.c~>~{
- #include "code.h"
- ~<Unique integers~>
- ~}
-
- ~C
-
- A type-~{h~} file gives the interface for the module described by the
- type-~{c~} file.
- By convention, an interface file is included if it is needed explicitly.
- This can lead to multiple inclusions, so every interface file must protect
- itself against this possibility as indicated.
- Conventionally, the symbol used is the upper-case version of the file name,
- with ``.'' replaced by ``_''.
-
- ~O~<code.h~>~{
- #ifndef CODE_H
- #define CODE_H
- extern int NewInteger();
- #endif
- ~}
-
- ~C
-
- A type-~{head~} file places CPP directives into the generated attribution
- routine.
- The specification of the PTG functions as attributes needs
- the definition of ~{PTGNode~}, which is given by ~{ptg_gen.h~}.
-
- ~O~<code.head~>~{
- #include "code.h"
- ~<Data mapping module interface~>
- #include "ptg_gen.h"
- ~<PTG functions as attributes~>
- ~}
-
- ~C
-
- A type-~{pdl~} file defines properties.
- If any of the properties are objects whose types are not basic data types
- of C, the type-~{pdl~} file must contain a string naming an interface file
- where the properties' types are defined.
- Some of the properties defined here are of type ~{StorageRequirement~},
- which is defined in the file ~{storage.h~}.
-
- ~O~<code.pdl~>~{
- ~<Static nesting level property~>
- ~<Relative address property~>
- "storage.h"
- ~<Storage requirement property~>
- ~<Label property~>
- ~}
-