home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / p / pascal-.zip / pascal- / specs / Code.fw next >
Text File  |  1993-01-05  |  27KB  |  770 lines

  1. @=~
  2.  
  3. ~A~<Code Generation~>
  4.  
  5. The purpose of code generation is to translate the concepts of the source
  6. language into the concepts of the target machine.
  7. No errors are detected or reported during code generation.
  8.  
  9. Code generation is an attribution process.
  10. Given the information provided by type analysis, it
  11. determines the amount of memory required to store objects of each type,
  12. allocates storage to parameters and variables,
  13. and then produces a target implementation of the algorithm.
  14.  
  15. ~B
  16.  
  17. Every instruction output by the compiler consists of an operation part
  18. followed by zero or more operands.
  19. The operation parts are provided as literal strings by the templates
  20. described in Chapter 8.
  21. Each template has a name, and the code corresponding to the template is
  22. generated by invoking a function whose name is ~{PTG~} followed by the
  23. template name.
  24. For example, code for the instruction ~{Variable(Level,Displ)~} is
  25. generated by the call ~{PTGVariable(Level,Displ)~}.
  26. The result of ~{PTGVariable(Level,Displ)~} is the generated code in the
  27. form of a ~{PTGNode~} value that can be used as an argument to other code
  28. generation functions.
  29.  
  30. The generated code is not actually emitted by the generation functions, as
  31. it is by Brinch-Hansen's ~{Emit~} functions.
  32. Instead, an explicit data structure is constructed that contains the
  33. generated code.
  34. This data structure is a tree, and it is actually output by passing its
  35. root to the function ~{PTGOut~}:
  36.  
  37. ~$~<Operation parts~>==~{
  38. SYMBOL Program COMPUTE PTGOut(THIS.Code) END;
  39. ~}
  40.  
  41. ~B~<Variable addressing~>
  42.  
  43. Variable access in the Pascal computer is described in Section 8.1:
  44. The address generated by the compiler specifies the number of steps that
  45. must be taken along the static chain to obtain the address of the proper
  46. activation record, and the relative address of the variable within that
  47. activation record.
  48. To compute these two components, the compiler must gather information from
  49. the program's declarations and store it in the definition table.
  50. An address can then be generated by combining information about the object
  51. with information determined from the context.
  52.  
  53. ~C
  54.  
  55. The compiler associates a ~/static nesting level~/ with the program and
  56. with each procedure.
  57. It is 1 for the program, 2 for each procedure declared in the program, 3
  58. for each procedure declared in a level-2 procedure, and so forth.
  59. A ~{Contour~} is is a phrase that has a static nesting level associated
  60. with it.
  61. Each variable is then given a property whose value is the static nesting
  62. level at which that variable was declared.
  63.  
  64. ~$~<Static nesting level property~>==~{
  65. Level: int;
  66. ~}
  67.  
  68. ~$~<Determination of the static nesting level~>==~{
  69. ATTR Level: int;
  70. SYMBOL Contour COMPUTE INH.Level=ADD(INCLUDING Contour.Level,1); END;
  71.  
  72. SYMBOL Program INHERITS Contour COMPUTE INH.Level=1; END;
  73. SYMBOL ProcedureBlock INHERITS Contour END;
  74. ~}
  75.  
  76. The number of steps that must be taken along the static chain to obtain the
  77. address of the activation record containing a variable is the difference
  78. between the static nesting level of the procedure containing the reference
  79. and the static nesting level of the procedure in which the variable was
  80. declared.
  81.  
  82. ~$~<Static chain steps to find the proper activation record address~>~M==~{
  83. PTGNumb(SUB(INCLUDING Contour.Level,GetLevel(VariableNameUse.Key,0)))
  84. ~}
  85.  
  86. There are two kinds of PTG functions: those that create data leaves and
  87. those that create nodes without data.
  88. Data can be stored only at data leaves, and a single data leaf can store
  89. an arbitrary number of data items of arbitrary types.
  90. The number of static chain steps to find the proper activation record
  91. address is an integer datum that must be stored at a data leaf, and
  92. ~{PTGNumb~} is a library function that creates a data leaf holding a
  93. single integer value.
  94. This function is obtained by instantiating the generic library module
  95. ~{$/Tool/lib/Tech/LeafPtg.gnrc~}.
  96.  
  97. ~C
  98.  
  99. In order to compute relative addresses within an activation record,
  100. the compiler needs to know the size of each variable.
  101. Brinch-Hansen, in his Algorithm 9.3, computes the size of each declared
  102. object at the point of declaration from the definition of its type.
  103. Thus the size of objects of a particular type is computed once for every
  104. object declared to be of that type.
  105. A better approach is to compute an appropriate size when a type is defined,
  106. and then use a property of the type to make that size available
  107. when the declaration of a new object of that type is encountered.
  108.  
  109. ~$~<Storage requirement property~>==~{
  110. Space: StorageRequired;
  111. ~}
  112.  
  113. Because all symbols must be defined before they are used in Pascal-,
  114. storage requirements can be computed in textual order.
  115. The sizes of the standard types ~{Boolean~} and ~{integer~} are determined
  116. by the specification, while the sizes of user-defined types are determined
  117. by the compiler.
  118.  
  119. ~$~<Determination of storage requirements~>+=~{
  120. CHAIN Storage: VOID;
  121.  
  122. SYMBOL StandardBlock COMPUTE
  123.   CHAINSTART HEAD.Storage=
  124.     ORDER(
  125.       SetSpace(IntegerKey,NewStorage(1,1,0),NoStorage),
  126.       SetSpace(BooleanKey,NewStorage(1,1,0),NoStorage));
  127. END;
  128. ~}
  129.  
  130. In the Pascal computer, each value of standard type occupies one memory
  131. location.
  132.  
  133. An array type requires storage equal to the number of elements times the
  134. storage requirement of a single element.
  135.  
  136. ~$~<Determination of storage requirements~>+=~{
  137. RULE ArrayDef: NewArrayType ::= 'array' '[' IndexRange ']' 'of' TypeNameUse
  138. COMPUTE
  139.   NewArrayType.Storage=
  140.     SetSpace(
  141.       INCLUDING NewType.Key,
  142.       ArrayStorage(
  143.         ADD(SUB(IndexRange.UpperBound,IndexRange.LowerBound),1),
  144.         GetSpace(TypeNameUse.Type,NoStorage)),
  145.       NoStorage)
  146.     DEPENDS_ON NewArrayType.Storage;
  147. END;
  148. ~}
  149.  
  150. ~{ArrayStorage~} is an operation exported by the data mapping module of the
  151. Eli library.
  152. It computes the storage requirements for an array of objects whose
  153. individual storage requirements are known.
  154. The first argument of ~{ArrayStorage~} must be the number of elements in
  155. the array, and the second must be the storage requirements of the element
  156. type.
  157.  
  158. The data mapping module is an abstract data type, not a generic module.
  159. Therefore it need not be instantiated, but
  160. its interface must be made available:
  161.  
  162. ~$~<Data mapping module interface~>==~{
  163. #include "storage.h"
  164. ~}
  165.  
  166. Record types are more complex, because in addition to determining the total
  167. storage requirement of the record, the compiler must assign a relative
  168. address to each field.
  169. The compiler begins by establishing an empty storage area for the record.
  170. It then processes the field definitions in textual order, concatenating the
  171. storage required by each field to the record's storage area.
  172. The concatenation operation ~{Concatenate~} is exported by the data mapping
  173. module.
  174. It takes two arguments: the storage requirements of the area to which the
  175. field must be added and the storage requirements of the field type.
  176. The function returns the address of the field relative to
  177. the beginning of the record, and updates the storage requirement of the
  178. area to reflect the addition of the field.
  179.  
  180. The relative address returned by ~{Concatenate~} is stored as the ~{Displ~}
  181. property of the field object (see the next section).
  182.  
  183. ~$~<Determination of storage requirements~>+=~{
  184. SYMBOL NewRecordType: Area: StorageRequired;
  185.  
  186. RULE RecordDef: NewRecordType ::= 'record' FieldList 'end'
  187. COMPUTE
  188.   NewRecordType.Area=NewStorage(0,1,0) DEPENDS_ON NewRecordType.Storage;
  189.   NewRecordType.Storage=
  190.     SetSpace(INCLUDING NewType.Key,NewRecordType.Area,NoStorage);
  191. END;
  192.  
  193. SYMBOL FieldNameDef COMPUTE
  194.   THIS.Storage=
  195.     SetDispl(
  196.       THIS.Key,
  197.       Concatenate(INCLUDING NewRecordType.Area,INCLUDING Group.Space),
  198.       0)
  199.     DEPENDS_ON THIS.Storage;
  200. END;
  201. ~}
  202.  
  203. Objects (variables, parameters, fields) are declared in groups in Pascal-:
  204. If several objects of the same type are being declared, the type is only
  205. stated once.
  206. This mechanism requires that the storage requirement of the type be made
  207. the value of an attribute of the phrase representing the group of objects,
  208. so that it will be available at all of the object declarations:
  209.  
  210. ~$~<Distributing a storage requirement~>==~{
  211. ATTR Space: StorageRequired;
  212.  
  213. SYMBOL Group COMPUTE
  214.   SYNT.Space=
  215.     GetSpace(CONSTITUENT TypeNameUse.Type,NoStorage)
  216.     DEPENDS_ON THIS.Storage;
  217. END;
  218.  
  219. SYMBOL VariableDefinition INHERITS Group END;
  220. SYMBOL ParameterDefinition INHERITS Group END;
  221. SYMBOL RecordSection INHERITS Group END;
  222. ~}
  223.  
  224. ~C
  225.  
  226. The relative address of an object within its storage area (a record for
  227. fields, an activation record for parameters and variables)
  228. is a property of that object.
  229.  
  230. ~$~<Relative address property~>==~{
  231. Displ: int;
  232. ~}
  233.  
  234. A relative address is computed from an object's declaration,
  235. in the process of allocating space in a storage area.
  236. Allocation for field objects was specified in the last section,
  237. and allocation for objects in activation records is similar.
  238. The major difference is that an activation record has more structure than a
  239. record type.
  240.  
  241. Three kinds of information are stored in an activation record:
  242. parameters, local variables, and ~/overhead~/ (information like the static
  243. chain, needed to maintain the relationships among activation records).
  244. Parameter and local variable storage is determined by the declarations for
  245. the ~{Contour~}, but storage for the overhead is determined by the target
  246. computer.
  247. Overhead information is maintained as a side effect of executing the
  248. instructions of the Pascal computer, and hence its size and placement
  249. depend on the implementation of those instructions.
  250. Brinch-Hansen, in Section 8.2 of his book, defines the overhead information
  251. to be three storage locations at the beginning of the storage allocated for
  252. variables.
  253. The first location is the static chain, holding the address of the
  254. activation record of the enclosing procedure, the second location is the
  255. ~/dynamic chain~/, holding the contents of the base register during
  256. execution of the caller, and the third location is the ~/return address~/,
  257. holding the location of the instruction at which execution should resume
  258. when the current procedure terminates.
  259. In the C implementation of the Pascal computer that accompanies this
  260. specification, there is no explicit return address.
  261. The third location of the overhead information is therefore free to hold
  262. the address of the parameter portion of the activation record.
  263.  
  264. ~$~<Storage allocation~>+=~{
  265. SYMBOL Contour: Parameters, Variables: StorageRequired;
  266. SYMBOL Contour COMPUTE
  267.   INH.Parameters=NewStorage(0,1,0);
  268.   INH.Variables=NewStorage(3,1,0);
  269. END;
  270. ~}
  271.  
  272. Parameter and variable objects have the ~{Displ~} property, just like field
  273. objects, but they also have the ~{Level~} property to record the static
  274. nesting level of the contour in which they are declared.
  275. Also, the storage requirement for a variable parameter is independent of
  276. its type because only the address of the parameter's value is stored.
  277. An address occupies one storage unit of the Pascal computer.
  278.  
  279. ~$~<Storage allocation~>+=~{
  280. RULE VarParmDef:
  281.   ParameterDefinition ::= 'var' ParameterNameDefList ':' TypeNameUse
  282. COMPUTE
  283.   ParameterDefinition.Space=NewStorage(1,1,0);
  284. END;
  285.  
  286. SYMBOL VariableNameDef COMPUTE
  287.   THIS.Storage=
  288.     ORDER(
  289.       SetDispl(
  290.         THIS.Key,
  291.         Concatenate(INCLUDING Contour.Variables,INCLUDING Group.Space),
  292.         0),
  293.       SetLevel(THIS.Key,INCLUDING Contour.Level,0))
  294.     DEPENDS_ON THIS.Storage;
  295. END;
  296.  
  297. SYMBOL ParameterNameDef COMPUTE
  298.   THIS.Storage=
  299.     ORDER(
  300.       SetDispl(
  301.         THIS.Key,
  302.         Concatenate(INCLUDING Contour.Parameters,INCLUDING Group.Space),
  303.         0),
  304.       SetLevel(THIS.Key,INCLUDING Contour.Level,0))
  305.     DEPENDS_ON THIS.Storage;
  306. END;
  307. ~}
  308.  
  309. ~C
  310.  
  311. Object access code pushes the address of the desired object onto the
  312. processor's stack in the Pascal computer.
  313. Access to an object of one of the standard types is specified in Pascal- by
  314. giving the name of the object, while access to an object of a user-defined
  315. type may involve subscripting or field selection.
  316. In that case the address of the object (array or record) containing the
  317. desired object is placed on the stack and then the appropriate selection
  318. operations are executed.
  319.  
  320. Section 8.1 pointed out the differences among the accessing operations for
  321. variables, value parameters and variable parameters.
  322. In addition, as noted in Section 2.3.2, a ~{VariableNameUse~} may actually
  323. be a constant name.
  324. Since constants are not stored in memory, the code generated for a constant
  325. name must push the constant itself, not the address of the constant, onto
  326. the processor's stack.
  327.  
  328. ~$~<Accessing an object~>==~{
  329. RULE VarIdn: VariableAccess ::= VariableNameUse
  330. COMPUTE
  331.   VariableAccess.Code=
  332.     IF(EQ(VariableAccess.Kind,Constantx),
  333.       PTGConstant(PTGNumb(GetValue(VariableNameUse.Key,0))),
  334.     IF(EQ(VariableAccess.Kind,ValueParameter),
  335.       PTGValParam(
  336.         ~<Static chain steps to find the proper activation record address~>,
  337.         PTGNumb(GetDispl(VariableNameUse.Key,0))),
  338.     IF(EQ(VariableAccess.Kind,VarParameter),
  339.       PTGVarParam(
  340.         ~<Static chain steps to find the proper activation record address~>,
  341.         PTGNumb(GetDispl(VariableNameUse.Key,0))),
  342.     PTGVariable(
  343.       ~<Static chain steps to find the proper activation record address~>,
  344.       PTGNumb(GetDispl(VariableNameUse.Key,0))))));
  345. END;
  346.  
  347. RULE Index: VariableAccess ::= VariableAccess '[' Expression ']'
  348. COMPUTE
  349.   VariableAccess[1].Code=
  350.     PTGIndex(
  351.       VariableAccess[2].Code,
  352.       Expression.Code,
  353.       PTGNumb(GetLowerBound(VariableAccess[2].Type,0)),
  354.       PTGNumb(GetUpperBound(VariableAccess[2].Type,0)),
  355.       PTGNumb(
  356.         StorageSize(
  357.           GetSpace(GetElementType(VariableAccess[2].Type,NoKey),NoStorage))),
  358.       PTGNumb(LINE));
  359. END;
  360.  
  361. RULE Select: VariableAccess ::= VariableAccess '.' FieldNameUse
  362. COMPUTE
  363.   VariableAccess[1].Code=
  364.     PTGField(
  365.       VariableAccess[2].Code,
  366.       PTGNumb(GetDispl(FieldNameUse.Key,0)));
  367. END;
  368. ~}
  369.  
  370. ~B
  371.  
  372. Code for an expression always leaves the value of the expression at the top
  373. of the processor's stack.
  374. If the expression is a ~{Numeral~} or a ~{VariableAccess~} then that
  375. value is obtained from either an operation or memory, respectively.
  376. Because a ~{VariableAccess~} may actually be a reference to a constant, the
  377. compiler must check its ~{Kind~} to determine whether the value at the top of
  378. the processor's stack is a value or an address at which a value can be found.
  379. When the top element of the processor's stack is an address, the compiler
  380. must emit a ~{Value~} operation to obtain the contents of that address if
  381. the context demands a value.
  382.  
  383. ~$~<Expression code~>+=~{
  384. RULE Denotation: Expression ::= Numeral
  385. COMPUTE
  386.   Expression.Code=PTGConstant(PTGNumb(Numeral.Value));
  387. END;
  388.  
  389. RULE VariableExpr: Expression ::= VariableAccess
  390. COMPUTE
  391.   Expression.Code=
  392.     IF(OR(Expression.ExpectedVar,EQ(VariableAccess.Kind,Constantx)),
  393.       VariableAccess.Code,
  394.       PTGValue(
  395.         VariableAccess.Code,
  396.         PTGNumb(StorageSize(GetSpace(VariableAccess.Type,NoStorage)))));
  397. END;
  398. ~}
  399.  
  400. If the expression is neither a ~{Numeral~} nor a ~{VariableAccess~} then
  401. its value is obtained by applying the appropriate operator to one or two
  402. operands.
  403. The code generation process is independent of the particular operator,
  404. which is supplied by the operator child of the expression,
  405. although it does depend on the number of operands.
  406. LIDO does not allow an attribute to be applied as a function, however, so a
  407. circumlocution is necessary:
  408.  
  409. ~$~<Expression code~>+=~{
  410. ATTR Op: PtgFunc;
  411.  
  412. RULE Monadic: Expression ::= Unop Expression
  413. COMPUTE
  414.   Expression[1].Code=Apply1(Unop.Op,Expression[2].Code);
  415. END;
  416.  
  417. RULE Dyadic: Expression ::= Expression Binop Expression
  418. COMPUTE
  419.   Expression[1].Code=Apply2(Binop.Op,Expression[2].Code,Expression[3].Code);
  420. END;
  421. ~}
  422.  
  423. ~{PtgFunc~}, ~{Apply1~} and ~{Apply2~} are defined in C:
  424.  
  425. ~$~<PTG functions as attributes~>==~{
  426. typedef PTGNode (*PtgFunc)();
  427. #define Apply1(f,x) ((*f)(x))
  428. #define Apply2(f,x,y) ((*f)(x,y))
  429. ~}
  430.  
  431. These definitions say that ~{PtgFunc~} objects are functions that return
  432. PTG nodes, ~{Apply1~} applies its first argument to its second, and
  433. ~{Apply2~} applies its first argument to its second and third.
  434.  
  435. All of the operator rules have exactly the same form, defining the ~{Op~}
  436. attribute of the left-hand side as the appropriate PTG function:
  437.  
  438. ~$~<Operator encoding~>~(~3~)~M==~{
  439. RULE r~1: ~2 ::= ~3 COMPUTE ~2.Op=PTG~1 END;
  440. ~}
  441.  
  442. ~$~<Expression code~>+=~{
  443. ~<Operator encoding~>~(Lss~,Binop~,'<'~)
  444. ~<Operator encoding~>~(Leq~,Binop~,'<='~)
  445. ~<Operator encoding~>~(Gtr~,Binop~,'>'~)
  446. ~<Operator encoding~>~(Geq~,Binop~,'>='~)
  447. ~<Operator encoding~>~(Equ~,Binop~,'='~)
  448. ~<Operator encoding~>~(Neq~,Binop~,'<>'~)
  449.  
  450. ~<Operator encoding~>~(Add~,Binop~,'+'~)
  451. ~<Operator encoding~>~(Sub~,Binop~,'-'~)
  452. ~<Operator encoding~>~(Mul~,Binop~,'*'~)
  453. ~<Operator encoding~>~(Div~,Binop~,'div'~)
  454. ~<Operator encoding~>~(Mod~,Binop~,'mod'~)
  455.  
  456. ~<Operator encoding~>~(Neg~,Unop~,'-'~)
  457. ~<Operator encoding~>~(Nop~,Unop~,'+'~)
  458.  
  459. ~<Operator encoding~>~(And~,Binop~,'and'~)
  460. ~<Operator encoding~>~(Or~,Binop~,'or'~)
  461. ~<Operator encoding~>~(Not~,Unop~,'not'~)
  462. ~}
  463.  
  464. ~B
  465.  
  466. A ~{Statement~} is a sequence of operations, which may be empty.
  467. The processor's stack is always empty before the operations of a statement
  468. are executed and after their execution is complete.
  469. Thus a statement may affect the state of the memory or external devices,
  470. but it neither expects nor yields a value.
  471. For example, the assignment statement consists of a sequence of operations
  472. that push the address of the variable to be assigned onto the processor's
  473. stack, push the value to be assigned, and then carry out the assignment
  474. removing both elements from the processor's stack.
  475.  
  476. ~$~<Statement code~>+=~{
  477. RULE Empty: Statement ::=
  478. COMPUTE
  479.   Statement.Code=PTGNULL;
  480. END;
  481.  
  482. RULE Assign: Statement ::=  VariableAccess ':=' Expression
  483. COMPUTE
  484.   Statement.Code=
  485.     PTGAssignmentStatement(
  486.       VariableAccess.Code,
  487.       Expression.Code,
  488.       PTGNumb(StorageSize(GetSpace(VariableAccess.Type,NoStorage))));
  489. END;
  490.  
  491. RULE Compound: Statement ::=  CompoundStatement
  492. COMPUTE
  493.   Statement.Code=CompoundStatement.Code;
  494. END;
  495.  
  496. SYMBOL CompoundStatement COMPUTE
  497.   SYNT.Code=
  498.     CONSTITUENTS Statement.Code
  499.       SHIELD Statement
  500.       WITH (PTGNode, PTGSequence, IDENTICAL, PTGNull);
  501. END;
  502. ~}
  503.  
  504. The ~{CONSTITUENTS~} construct gathers all of the ~{Code~} attributes of
  505. component ~{Statement~} nodes, using ~{PTGSequence~} to combine them
  506. pairwise.
  507. Note, however, that many ~{Statement~} nodes are actually the roots of
  508. subtrees that contain ~{Statement~} nodes themselves.
  509. The ~{SHIELD~} clause prevents the ~{CONSTITUENTS~} construct from
  510. gathering the ~{Code~} attributes of the ~{Statement~} nodes within such
  511. subtrees.
  512.  
  513. Statements that alter the normal sequence of operations must be able to
  514. nominate a successor to the current operation.
  515. Section 8.3 described how operations can be named via the ~{DefAddr~}
  516. pseudo-operation.
  517. The compiler must generate these names; it does so by obtaining a sequence
  518. of unique integers from the ~{NewInteger~} module:
  519.  
  520. ~$~<Unique integers~>==~{
  521. static int Next = 1;    /* Next integer to be delivered */
  522.  
  523. int NewInteger() { return Next++; }
  524. ~}
  525.  
  526. The number of labels needed by the statement depends on its internal
  527. structure, described in Section 8.3.
  528.  
  529. ~$~<Statement code~>+=~{
  530. RULE While: Statement ::=  'while' Expression 'do' Statement
  531. COMPUTE
  532.   Statement[1].Code=
  533.     PTGWhileStatement(
  534.       PTGNumb(NewInteger()),
  535.       Expression.Code,
  536.       Statement[2].Code,
  537.       PTGNumb(NewInteger()));
  538. END;
  539.  
  540. RULE OneSided:  Statement ::=  'if' Expression 'then' Statement
  541. COMPUTE
  542.   Statement[1].Code=
  543.     PTGOneSided(
  544.       Expression.Code,
  545.       Statement[2].Code,
  546.       PTGNumb(NewInteger()));
  547. END;
  548.  
  549. RULE TwoSided: Statement ::=  'if' Expression 'then' Statement 'else' Statement
  550. COMPUTE
  551.   Statement[1].Code=
  552.     PTGTwoSided(
  553.       Expression.Code,
  554.       Statement[2].Code,
  555.       PTGNumb(NewInteger()),
  556.       Statement[3].Code,
  557.       PTGNumb(NewInteger()));
  558. END;
  559. ~}
  560.  
  561. ~B
  562.  
  563. Most of the code for a procedure definition is generated by its children.
  564. The storage requirements must be summarized and a label generated so that
  565. invocations can refer to the procedure.
  566.  
  567. ~$~<Procedure code~>+=~{
  568. ATTR Label: int;
  569.  
  570. RULE ProcDef:
  571.   ProcedureDefinition ::= 'procedure' ProcedureNameDef ProcedureBlock ';'
  572. COMPUTE
  573.   .Label=NewInteger();
  574.   ProcedureDefinition.Code=
  575.     PTGProcedureDefinition(
  576.       PTGNumb(StorageSize(ProcedureBlock.Parameters)),
  577.       PTGNumb(StorageSize(ProcedureBlock.Variables)),
  578.       PTGNumb(0),    /*Temp size*/
  579.       PTGNumb(.Label),
  580.       PTGNumb(LINE),
  581.       CONSTITUENTS ProcedureDefinition.Code
  582.         SHIELD ProcedureDefinition
  583.         WITH (PTGNode, PTGSequence, IDENTICAL, PTGNull),
  584.       CONSTITUENTS CompoundStatement.Code
  585.         SHIELD (ProcedureDefinition, CompoundStatement)
  586.         WITH (PTGNode, PTGSequence, IDENTICAL, PTGNull))
  587.     DEPENDS_ON ProcedureBlock.Storage;
  588.   ProcedureBlock.Storage=
  589.     ORDER(
  590.       SetLevel(ProcedureNameDef.Key,ProcedureBlock.Level,0),
  591.       SetLabel(ProcedureNameDef.Key,.Label,0))
  592.     DEPENDS_ON ProcedureDefinition.Storage;
  593. END;
  594. ~}
  595.  
  596. The ~{SHIELD~} clauses in this rule avoid duplication of code:
  597. ~{CONSTITUENTS CompoundStatement.Code~} would gather the bodies of nested
  598. procedures if it could penetrate the subtrees rooted in
  599. ~{ProcedureDefinition~} nodes.
  600.  
  601. In addition to the ~{Level~} property that it shares with other objects, a
  602. procedure name must have the procedure's label as a property.
  603.  
  604. ~$~<Label property~>==~{
  605. Label: int;
  606. ~}
  607.  
  608. The label property is accessed at the procedure call.
  609.  
  610. Read and write statements in Pascal- have the form of procedure calls, but
  611. they are implemented by distinct operations of the Pascal computer.
  612. They must therefore be recognized specially during code generation.
  613.  
  614. When a user-defined procedure is invoked, it must be provided with the
  615. address of the activation record of the procedure in which it was declared.
  616. That address can be found by stepping along the static chain, exactly as in
  617. the case of variable addressing.
  618. There is a small difference, however:
  619. The number of steps is one larger than the difference between the current
  620. static nesting level and the static nesting level of the procedure being
  621. called.
  622. The reason is that that address sought is the activation record address for
  623. the procedure in which the called procedure was declared; the called
  624. procedure itself has no activation record until the ~{ProcCall~} operation
  625. (Section 8.4) has been executed.
  626.  
  627. ~$~<Steps to find the called procedure's environment~>==~{
  628. PTGNumb(
  629.   ADD(
  630.     SUB(INCLUDING Contour.Level,GetLevel(ProcedureNameUse.Key,0)),
  631.     1))
  632. ~}
  633.  
  634. ~$~<Procedure code~>+=~{
  635. RULE Call: Statement ::=  ProcedureNameUse ActualParameterList
  636. COMPUTE
  637.   .Code=CONSTITUENTS Expression.Code SHIELD Expression
  638.     WITH (PTGNode, PTGSequence, IDENTICAL, PTGNull);
  639.   Statement.Code=
  640.     IF(EQ(ProcedureNameUse.Key,ReadKey),
  641.       PTGReadStatement(.Code),
  642.     IF(EQ(ProcedureNameUse.Key,WriteKey),
  643.       PTGWriteStatement(.Code),
  644.     PTGProcedureStatement(
  645.       .Code,
  646.       ~<Steps to find the called procedure's environment~>,
  647.       PTGNumb(GetLabel(ProcedureNameUse.Key,0)))))
  648.     DEPENDS_ON Statement.Storage;
  649. END;
  650. ~}
  651.  
  652. The ~{SHIELD~} clause forces the ~{CONSTITUENTS~} construct to gather the
  653. ~{Code~} attributes only from the argument expressions, and not from any of
  654. their components.
  655.  
  656. ~B
  657.  
  658. The code for the program definition is almost identical to the code for a
  659. procedure definition.
  660. There are no parameters for the program, and since the program is not
  661. invoked there is no need for a ~{Label~} property.
  662.  
  663. ~$~<Program code~>==~{
  664. RULE Source: Program ::=  'program' ProgramName ';' BlockBody '.'
  665. COMPUTE
  666.   Program.Code=
  667.     PTGText(
  668.       PTGProgram(
  669.         PTGNumb(StorageSize(Program.Variables)),
  670.         PTGNumb(0),  /*Temp size*/
  671.         PTGNumb(LINE),
  672.         CONSTITUENTS CompoundStatement.Code
  673.           SHIELD (ProcedureDefinition,CompoundStatement)
  674.           WITH (PTGNode, PTGSequence, IDENTICAL, PTGNull)),
  675.         CONSTITUENTS ProcedureDefinition.Code
  676.           SHIELD ProcedureDefinition
  677.           WITH (PTGNode, PTGSequence, IDENTICAL, PTGNull));
  678. END;
  679. ~}
  680.  
  681. The ~{SHIELD~} clauses prevent duplicate code:
  682. ~{CONSTITUENTS CompoundStatement.Code~} would gather the bodies of all
  683. nested procedures as well as the body of the program if it were allowed to
  684. penetrate the subtrees rooted in ~{ProcedureDefinition~} nodes.
  685.  
  686. ~B~<Specification files for code generation~>
  687.  
  688. Five kinds of specifications are needed to define the Pascal- code
  689. generation problem to Eli.
  690.  
  691. ~C
  692.  
  693. A type-~{lido~} file describes the attribution needed to gather the
  694. information and relate the generated code fragments.
  695. Eli will merge these attributions with others specified in this document
  696. and create a tree traversal algorithm.
  697.  
  698. ~O~<code.lido~>~{
  699. ATTR Code: PTGNode;
  700. ~<Operation parts~>
  701. ~<Determination of the static nesting level~>
  702. ~<Determination of storage requirements~>
  703. ~<Distributing a storage requirement~>
  704. ~<Storage allocation~>
  705. ~<Accessing an object~>
  706. ~<Expression code~>
  707. ~<Statement code~>
  708. ~<Procedure code~>
  709. ~<Program code~>
  710. ~}
  711.  
  712. ~C
  713.  
  714. A type-~{c~} file describes a problem by giving its solution.
  715. In the case of the code generation, the problem was that of generating
  716. unique labels.
  717.  
  718. ~O~<code.c~>~{
  719. #include "code.h"
  720. ~<Unique integers~>
  721. ~}
  722.  
  723. ~C
  724.  
  725. A type-~{h~} file gives the interface for the module described by the
  726. type-~{c~} file.
  727. By convention, an interface file is included if it is needed explicitly.
  728. This can lead to multiple inclusions, so every interface file must protect
  729. itself against this possibility as indicated.
  730. Conventionally, the symbol used is the upper-case version of the file name,
  731. with ``.'' replaced by ``_''.
  732.  
  733. ~O~<code.h~>~{
  734. #ifndef CODE_H
  735. #define CODE_H
  736. extern int NewInteger();
  737. #endif
  738. ~}
  739.  
  740. ~C
  741.  
  742. A type-~{head~} file places CPP directives into the generated attribution
  743. routine.
  744. The specification of the PTG functions as attributes needs
  745. the definition of ~{PTGNode~}, which is given by ~{ptg_gen.h~}.
  746.  
  747. ~O~<code.head~>~{
  748. #include "code.h"
  749. ~<Data mapping module interface~>
  750. #include "ptg_gen.h"
  751. ~<PTG functions as attributes~>
  752. ~}
  753.  
  754. ~C
  755.  
  756. A type-~{pdl~} file defines properties.
  757. If any of the properties are objects whose types are not basic data types
  758. of C, the type-~{pdl~} file must contain a string naming an interface file
  759. where the properties' types are defined.
  760. Some of the properties defined here are of type ~{StorageRequirement~},
  761. which is defined in the file ~{storage.h~}.
  762.  
  763. ~O~<code.pdl~>~{
  764. ~<Static nesting level property~>
  765. ~<Relative address property~>
  766. "storage.h"
  767. ~<Storage requirement property~>
  768. ~<Label property~>
  769. ~}
  770.