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 / Structure.fw < prev    next >
Text File  |  1993-01-05  |  48KB  |  1,222 lines

  1. @=~
  2.  
  3. ~A~<A Pascal Subset~>
  4.  
  5. The compiler described here accepts a subset of Pascal known as
  6. ``Pascal-''.
  7. It has enough features to illustrate the basic techniques for specifying
  8. a compiler.
  9. With the exception of coercions, the omitted Pascal features do not require
  10. any techniques beyond those described here.
  11.  
  12. This chapter begins by describing the differences between Pascal- and Pascal,
  13. assuming that you are already familiar with Pascal.
  14. An informal description of the Pascal- vocabulary and a formal description
  15. of the structure of a Pascal- program complete the language overview.
  16.  
  17. ~B~<General description~>
  18.  
  19. Pascal- has only two simple types, Boolean and integer, and two structured
  20. types, array types and record types.
  21. Boolean and integer are predefined, with the names ~{Boolean~} and
  22. ~{integer~} respectively.
  23. Every structured type also has a name, which is introduced by a type
  24. definition:
  25.  
  26. ~$~<Type definition example~>==~{
  27. type
  28.   table = array [1..100] of integer;
  29.   stack = record contents: table; size: integer end;
  30. ~}
  31.  
  32. A type definition always creates a new type; it can never rename an
  33. existing type.
  34. The following type definition is therefore incorrect:
  35.  
  36. ~$~<Incorrect type definition~>==~{
  37. type number = integer;
  38. ~}
  39.  
  40. All variables must be defined and given a type:
  41.  
  42. ~$~<Variable definition example~>==~{
  43. var
  44.   A: table;
  45.   x, y: integer;
  46. ~}
  47.  
  48. The type name must always be used in a variable declaration.
  49. In other words, it is not possible to create an ``anonymous'' type as in
  50. the following incorrect variable definition:
  51.  
  52. ~$~<Incorrect variable definition~>==~{
  53. var A: array [1..100] of integer;
  54. ~}
  55.  
  56. All constants have simple types.
  57. Two predefined identifiers, ~{true~} and ~{false~}, represent the two
  58. possible values of type ~{Boolean~}.
  59. Values of type ~{integer~} are represented in the usual way.
  60. Names for constants can be introduced by constant definitions:
  61.  
  62. ~$~<Constant definition example~>==~{
  63. const max = 100; on = true;
  64. ~}
  65.  
  66. Assignment statements, procedure calls, if statements, while statements
  67. and compound statements are available in Pascal-.
  68. A statement may be empty.
  69. There are no labels or goto statements, case statements, repeat statements,
  70. for statements or with statements.
  71.  
  72. Procedure declarations can be nested, and a procedure may have variable
  73. and/or value parameters of any type.
  74. Procedures cannot be passed to other procedures as parameters, and
  75. functions cannot be defined.
  76. There are two standard procedures, ~{read(x)~} and ~{write(x)~}.
  77. ~{Read~} expects a single variable parameter of type integer, obtains the
  78. next integer from the standard input stream, and assigns the value of that
  79. integer to the variable parameter.
  80. ~{Write~} expects a single value parameter of type integer, and places the
  81. value of that integer onto the standard output stream as a complete line.
  82.  
  83. Here is an algorithm that illustrates most of the features of Pascal-:
  84.  
  85. ~$~<Complete example program~>==~{
  86. Program ProgramExample;
  87. const n=100;
  88. type table=array[1..n] of integer;
  89. var A: table; i,x: integer; yes: Boolean;
  90.  
  91. procedure search(value: integer; var found: Boolean; var index: integer);
  92.   var limit: integer;
  93.   begin index:=1; limit:=n;
  94.   while index<limit do
  95.     if A[index]=value then limit:=index else index:=index+1;
  96.   found:=A[index]=value
  97.   end;
  98.  
  99. begin {input table} i:=1;
  100. while i<=n do
  101.   begin read(A[i]); i:=i+1 end;
  102. {test search} read(x);
  103. while x<>0 do
  104.   begin search(x,yes,i);
  105.   write(x);
  106.   if yes then write(i);
  107.   read(x);
  108.   end
  109. end.
  110. ~}
  111.  
  112. ~B~<Vocabulary~>
  113.  
  114. The vocabulary of a programming language is made up of ~/basic symbols~/
  115. and ~/comments~/.
  116. There are three kinds of basic symbols: identifiers, denotations and
  117. delimiters.
  118. Identifiers are names that are freely chosen by the programmer to represent
  119. entities like constants, types, variables and procedures.
  120. Denotations represent specific values, according to conventions laid down
  121. by the language designer.
  122. Delimiters are used to give the program structure.
  123.  
  124. In Pascal-, an identifier is called a ~{Name~}, and consists of a letter
  125. that may be followed by any sequence of letters and digits:
  126.  
  127. ~$~<Name examples~>==~{
  128. x LongName S100
  129. CaseInsensitive CASEINSENSITIVE caseinsensitive
  130. ~}
  131.  
  132. There is no distinction made between upper and lower case letters in
  133. Pascal-, so the three names on the second line of the example are
  134. indistinguishable from one another.
  135.  
  136. A ~{Numeral~} is the only denotation in the vocabulary of Pascal-.
  137. It consists of a sequence of decimal digits, and denotes an integer value:
  138.  
  139. ~$~<Numeral examples~>==~{
  140. 1 123
  141. ~}
  142.  
  143. There are two kinds of delimiters in Pascal-, ~/word symbols~/ and
  144. ~/special symbols~/:
  145.  
  146. ~$~<Word symbols~>==~{
  147. and array begin const div do else end if mod not
  148. of or procedure program record then type var while
  149. ~}
  150.  
  151. ~$~<Special symbols~>==~{
  152. + - * < = > <= <> >= :=
  153. ( ) [ ] , . : ; ..
  154. ~}
  155.  
  156. A word symbol cannot be used as a ~{Name~} in a Pascal- program.
  157.  
  158. A comment in Pascal- is an arbitrary sequence of characters enclosed in
  159. braces ~{{~} ~{}~}.
  160. Comments may extend over several lines and may be nested to arbitrary
  161. depth:
  162.  
  163. ~$~<Comment examples~>==~{
  164. if x>0 then {reserve resource} x:=x-1;
  165. {This is a {nested} comment
  166. that extends over two lines}
  167. ~}
  168.  
  169. White space (spaces, tabs and new lines) and comments are called
  170. ~/separators~/.
  171. Any basic symbol may be preceded by one or more separators, and the program
  172. may be followed by zero or more separators.
  173.  
  174. Word symbols, names and numerals are called ~/undelimited~/ basic symbols.
  175. Any pair of adjacent undelimited basic symbols must be separated by at
  176. least one separator:
  177.  
  178. ~$~<Example of basic symbol separation~>==~{
  179. {Incorrect}
  180.   ifx>0thenx:=10divx-1;
  181.  
  182. {Correct}
  183.   if x>0
  184. then{Can divide}x:=10    div x-1;
  185. ~}
  186.  
  187. In this example, separators needed between ~{if~} and ~{x~}, ~{0~} and
  188. ~{then~}, ~{then~} and ~{x~}, ~{0~} and ~{div~}, ~{div~} and ~{x~}.
  189. The separators can be white space and/or comments, as indicated.
  190.  
  191. ~B
  192.  
  193. A complete program is called a ~/sentence~/ of the programming language in
  194. which it is written.
  195. The structure of that sentence is described in terms of its component
  196. ~/phrases~/.
  197. Compilation of a program is based on its phrase structure, as defined by
  198. a ~/grammar~/ for the programming language.
  199. The phrase structure must reflect both the way a program is written and
  200. the meaning to be conveyed by that program.
  201.  
  202. It is convenient to divide a grammar into parts that describe coherent
  203. sets of phrases, and then to discuss each part individually.
  204. Here is a breakdown appropriate for Pascal-, with two rules describing the
  205. program structure given explicitly as examples of the notation:
  206.  
  207. ~$~<Grammar~>==~{
  208. Program: 'program' ProgramName ';' BlockBody '.' .
  209.  
  210. BlockBody:
  211.   ConstantDefinitionPart
  212.   TypeDefinitionPart
  213.   VariableDefinitionPart
  214.   ProcedureDefinitions
  215.   CompoundStatement .
  216.  
  217. ~<Constant, type and variable definition grammar~>
  218. ~<Expression grammar~>
  219. ~<Statement grammar~>
  220. ~<Procedure grammar~>
  221. ~}
  222.  
  223. The first grammar rule says that a sentence in Pascal- has
  224. two component phrases, a ~{ProgramName~} and a ~{BlockBody~}.
  225. Delimiters ~{program~}, ~{;~} and ~{.~} are used to separate these phrases
  226. in the program text as written.
  227.  
  228. The ~{BlockBody~} phrase is the description of the algorithm,
  229. and consists of definitions and a statement.
  230. All of the definitions and the statement together constitute the meaning of
  231. the algorithm, while the name of the program does not affect the algorithm
  232. in any way.
  233. A program is written as the sequence of basic symbols ~{program~}, a name,
  234. ~{;~}, a sub-sequence describing the algorithm, and ~{.~}.
  235. Thus these two rules reflect both the way the program is written
  236. and the underlying meaning.
  237.  
  238. The Pascal- grammar given here is taken almost verbatim from Brinch-Hansen's
  239. description in Section 2.4 of ``Brinch-Hansen on Pascal Compilers''.
  240. His grammar does not make some properties of the program clear, however,
  241. and these aspects have been changed.
  242. Each such change is discussed in the appropriate section below.
  243.  
  244. Eli does not permit the extensions to BNF that Brinch-Hansen uses to
  245. describe optional and repeated phrases.
  246. The rules involving these extensions have been re-written to avoid the
  247. extensions.
  248. Finally, Eli uses ~{:~} instead of ~{=~} to separate the left and right
  249. hand sides of a rule, and uses ~{/~} instead of ~{|~} as the separator
  250. for alternative right-hand sides.
  251. These notational changes will not be discussed further.
  252.  
  253. ~C
  254.  
  255. Constant, type and variable definitions have similar forms in a Pascal-
  256. program:
  257. A word symbol describing the kind of definitions to follow, and a list of
  258. the definitions themselves.
  259. In each case, one or more names are defined.
  260. If a particular word symbol is missing, then there are no definitions of
  261. that kind.
  262.  
  263. Notice that the grammar distinguishes between a definition of a name and a
  264. use of that name (e.g ~{ConstantNameDef~} and ~{ConstantNameUse~}).
  265. This distinction reflects the meaning of the program, rather than the way
  266. the program is written.
  267. The constant name ~{max~} is always written in the same way, but when it
  268. appears to the left of ~{=~} in a ~{ConstantDefinition~} that is a
  269. ~/defining occurrence~/ and when it appears to the right of ~{=~} in a
  270. ~{ConstantDefinition~} that is an ~/applied occurrence~/.
  271. All of the properties of a name are deduced from the context of its
  272. defining occurrence; those properties are made available at the applied
  273. occurrences.
  274.  
  275. ~$~<Constant, type and variable definition grammar~>==~{
  276. ConstantDefinitionPart: / 'const' ConstantDefinitions .
  277. ConstantDefinitions:
  278.   ConstantDefinition / ConstantDefinitions ConstantDefinition.
  279. ConstantDefinition: ConstantNameDef '=' Constant ';' .
  280. Constant: Numeral / ConstantNameUse .
  281.  
  282. TypeDefinitionPart: / 'type' TypeDefinitions .
  283. TypeDefinitions:
  284.   TypeDefinition / TypeDefinitions TypeDefinition .
  285. TypeDefinition: TypeNameDef '=' NewType ';' .
  286. NewType: NewArrayType / NewRecordType .
  287.  
  288. NewArrayType: 'array' '[' IndexRange ']' 'of' TypeNameUse .
  289. IndexRange: Constant '..' Constant .
  290.  
  291. NewRecordType: 'record' FieldList 'end' .
  292. FieldList: RecordSection / FieldList ';' RecordSection .
  293. RecordSection: FieldNameDefList ':' TypeNameUse .
  294. FieldNameDefList: FieldNameDef / FieldNameDefList ',' FieldNameDef .
  295.  
  296. VariableDefinitionPart: / 'var' VariableDefinitions .
  297. VariableDefinitions:
  298.   VariableDefinition / VariableDefinitions VariableDefinition .
  299. VariableDefinition: VariableNameDefList ':' TypeNameUse ';' .
  300. VariableNameDefList:
  301.   VariableNameDef / VariableNameDefList ',' VariableNameDef .
  302. ~}
  303.  
  304. Brinch-Hansen does not distinguish between defining and applied occurrences
  305. of names in his grammar.
  306. This distinction is made in the text of Section 6.1 of his book,
  307. where scope rules are discussed.
  308. When one is specifying a language to a compiler generator like Eli,
  309. however, natural language descriptions must be formalized.
  310.  
  311. ~C
  312.  
  313. Like most programming languages, Pascal- defines precedence and association
  314. rules to eliminate the need for explicit parentheses.
  315. For example, the precedence rules ensure that the expression ~{a+b*c~} has
  316. the same meaning as ~{(a+(b*c))~}, ~/not~/ the same meaning as
  317. ~{((a+b)*c)~}.
  318. Similarly, the association rules ensure that ~{a-b-c~} has the same meaning
  319. as ~{((a-b)-c)~}, ~/not~/ the same meaning as ~{(a-(b-c))~}.
  320. These rules are embodied in the phrase structure of an expression.
  321.  
  322. ~$~<Expression grammar~>==~{
  323. Expression:
  324.   SimpleExpression /
  325.   SimpleExpression RelationalOperator SimpleExpression .
  326. RelationalOperator: '<' / '=' / '>' / '<=' / '<>' / '>=' .
  327. SimpleExpression:
  328.   Term / SignOperator Term / SimpleExpression AddingOperator Term .
  329. SignOperator: '+' / '-' .
  330. AddingOperator: '+' / '-' / 'or' .
  331. Term: Factor / Term MultiplyingOperator Factor .
  332. MultiplyingOperator: '*' / 'div' / 'mod' / 'and' .
  333. Factor:
  334.   Numeral /
  335.   VariableAccess /
  336.   '(' Expression ')' /
  337.   NotOperator Factor .
  338.  
  339. NotOperator: 'not' .
  340.  
  341. VariableAccess:
  342.   VariableNameUse /
  343.   VariableAccess '[' Expression ']' /
  344.   VariableAccess '.' FieldNameUse .
  345. ~}
  346.  
  347. Precedence and association rules affect the way the program is written,
  348. determining the phrase structure of an expression.
  349. Once that phrase structure has been determined, however, precedence and
  350. association rules have no further effect on the meaning of the program.
  351. As far as the meaning of the program is concerned, it is sufficient to
  352. distinguish dyadic expressions, monadic expressions, and expressions
  353. without operators.
  354. Each operator or operand should therefore be a distinct phrase in the
  355. sentence.
  356. Brinch-Hansen's grammar does not associate the ~{not~} operator with a
  357. phrase, because it uses that operator literally in a rule: ~{Factor: 'not'
  358. Factor~}.
  359. Here the ~{not~} operator is made a distinct phrase by writing
  360. Brinch-Hansen's single rule as two: ~{Factor: NotOperator Factor .~} and
  361. ~{NotOperator: 'not' .~}.
  362.  
  363. The first alternative for ~{Factor~} in Brinch-Hansen's grammar is
  364. ~{Constant~}.
  365. A ~{Constant~} is defined as being either a ~{Numeral~} or a
  366. ~{ConstantNameUse~} (see Section 2.3.1).
  367. But notice that a ~{VariableAccess~}, another alternative for ~{Factor~},
  368. could be a ~{VariableNameUse~}.
  369. When presented with the ~{Factor~} ``~{x~}'', how can the compiler decide
  370. whether this name represents a constant or a variable?
  371. The distinction is irrelevant as far as the structure of the program is
  372. concerned, and the attempt to make it leads to an ambiguous grammar.
  373. Brinch-Hansen discusses this ambiguity in Section 5.5 of his book,
  374. and resolves it by altering the grammar to the one given here.
  375.  
  376. ~C
  377.  
  378. Statements in Pascal- are separated by semicolons, but the fact that a
  379. statement can also be empty means that semicolon can be considered to be a
  380. terminator.
  381.  
  382. ~$~<Statement grammar~>==~{
  383. Statement:
  384.   AssignmentStatement /
  385.   ProcedureStatement /
  386.   IfStatement /
  387.   WhileStatement /
  388.   CompoundStatement /
  389.   Empty .
  390.  
  391. AssignmentStatement: VariableAccess ':=' Expression .
  392.  
  393. ProcedureStatement: ProcedureNameUse ActualParameterList .
  394. ActualParameterList: / '(' ActualParameters ')' .
  395. ActualParameters: ActualParameter / ActualParameters ',' ActualParameter .
  396. ActualParameter: Expression .
  397.  
  398. IfStatement:
  399.   'if' Expression 'then' Statement $'else' /
  400.   'if' Expression 'then' Statement 'else' Statement .
  401.  
  402. WhileStatement: 'while' Expression 'do' Statement .
  403.  
  404. CompoundStatement: 'begin' Statements 'end' .
  405. Statements: Statement / Statements ';' Statement .
  406. ~}
  407.  
  408. Brinch-Hansen's grammar contains the rule ~{ActualParameter: Expression |
  409. VariableAccess .~}.
  410. This rule is ambiguous, because a ~{VariableAccess~} is one form of an
  411. ~{Expression~}.
  412. He is trying to distinguish a context in which a value parameter is
  413. required from that in which a variable parameter is required.
  414. These contexts can only be distinguished on the basis of information drawn
  415. from the definitions, and therefore do not affect the structure of the
  416. program.
  417. In Section 5.5 of his book, Brinch-Hansen alters the grammar to use the
  418. rule listed here.
  419.  
  420. The sequence ~{$'else'~} is used in the definition of an ~{IfStatement~} to
  421. avoid another ambiguity:
  422. What is the meaning of the phrase ~{if a then if b then x:=1 else x:=2~}?
  423. If ~{a~} is ~{false~}, does ~{x~} remain unaltered or is it set to ~{2~}?
  424. The rules of Pascal require it to remain unaltered, because an else clause
  425. is associated with the closest if.
  426. Brinch-Hansen's grammar for Pascal- is ambiguous, and there is no mention
  427. of the ambiguity in his book.
  428. In the absence of specific guidance, the rules of Pascal are assumed here.
  429.  
  430. This decision is made explicit in the grammar by the inclusion of the
  431. sequence ~{$'else'~}.
  432. It specifies that the alternative of which it is a part is only valid if
  433. ~/not~/ followed by the basic symbol ~{else~}.
  434.  
  435. ~C
  436.  
  437. Like a ~{Program~}, a ~{ProcedureDefinition~} has two constituent phrases.
  438. The ~{ProcedureBlock~} defines the algorithm abstracted by the procedure,
  439. and the ~{ProcedureNameDef~} defines the name by which that algorithm will
  440. be known.
  441.  
  442. Formal parameters are a part of the abstraction, not a part of the name.
  443. Their names are local to the procedure body, whereas the procedure name is
  444. defined in the surrounding context.
  445.  
  446. ~$~<Procedure grammar~>==~{
  447. ProcedureDefinitions: / ProcedureDefinitions ProcedureDefinition .
  448. ProcedureDefinition: 'procedure' ProcedureNameDef ProcedureBlock ';' .
  449.  
  450. ProcedureBlock: FormalParameterList ';' BlockBody .
  451.  
  452. FormalParameterList: / '(' ParameterDefinitions ')' .
  453. ParameterDefinitions:
  454.   ParameterDefinition / ParameterDefinitions ';' ParameterDefinition .
  455. ParameterDefinition:
  456.   'var' ParameterNameDefList ':' TypeNameUse /
  457.   ParameterNameDefList ':' TypeNameUse .
  458. ParameterNameDefList:
  459.   ParameterNameDef / ParameterNameDefList ',' ParameterNameDef .
  460. ~}
  461.  
  462. ~B
  463.  
  464. Here is a summary of the examples:
  465.  
  466. ~$~<Examples~>~Z~{
  467. ~<Name examples~>
  468. ~<Numeral examples~>
  469. ~<Comment examples~>
  470. ~<Word symbols~>
  471. ~<Special symbols~>
  472. ~<Example of basic symbol separation~>
  473. ~<Constant definition example~>
  474. ~<Type definition example~>
  475. ~<Incorrect type definition~>
  476. ~<Variable definition example~>
  477. ~<Incorrect variable definition~>
  478. ~<Complete example program~>
  479. ~}
  480.  
  481. ~A~<Compiler Organization~>
  482.  
  483. Eli embodies a large fraction of the knowledge required to build a
  484. compiler, providing an overall design that will satisfy the requirements
  485. of almost any translation problem.
  486. It assumes a particular decomposition of translation problems,
  487. supports the solution of the resulting subproblems,
  488. and combines those solutions into a complete program
  489. that carries out the desired translation.
  490.  
  491. The compiler generated by Eli reads a file containing the source program,
  492. examining it character-by-character.
  493. Character sequences are recognized as basic symbols or discarded, and
  494. relationships among the basic symbols are used to build a tree that
  495. reflects the structure of the source program.
  496. Computations are then carried out over the tree, and the results of these
  497. computations output as the target program.
  498. Thus Eli assumes that the original translation problem is decomposed into
  499. the problems of determining which character sequences are basic symbols and
  500. which should be discarded, what tree structure should be imposed on
  501. sequences of basic symbols, what computations should be carried out
  502. over the resulting tree, and how the computed values should be encoded and
  503. output.
  504.  
  505. There is considerable variability in the specific decompositions for
  506. particular translation problems.
  507. For example, operator overloading is very simple in Pascal-.
  508. Only the relational operators are overloaded, and they can be applied only
  509. to Boolean or integer operands.
  510. Because of this simplicity, there is no need to treat overload resolution
  511. as a separate subproblem of the Pascal- translation problem.
  512.  
  513. This chapter describes the decomposition of the Pascal- translation problem
  514. and gives the general framework within which the subproblems are specified.
  515. The complete specifications appear in subsequent chapters.
  516.  
  517. ~B~<Subproblems for Pascal-~>
  518.  
  519. ~/Lexical analysis~/ is the process that examines the source program text,
  520. recognizing basic symbols and discarding separators.
  521. Basic symbols are classified by an integer called a ~/syntax code~/.
  522. Each delimiter has a unique syntax code, and there is one syntax code for
  523. all names and another for all numerals.
  524. A name or numeral is characterized by a single integer value called an
  525. ~/intrinsic attribute~/ in addition to the syntax code.
  526. No intrinsic attribute is computed for a delimiter.
  527. As it recognizes each basic symbol, the lexical analyzer passes the
  528. information characterizing that basic symbol to the ~/syntax analyzer~/.
  529.  
  530. ~/Syntax analysis~/ determines the phrase structure of the source program
  531. and builds a tree to represent it.
  532. Each phrase results in a tree node.
  533. If a phrase has component phrases, the nodes representing those component
  534. phrases are the children of the node representing the composite phrase.
  535. Identifiers and denotations are phrases that have no components, and
  536. therefore represent leaves of the tree.
  537. Every other phrase corresponds to a rule of the grammar.
  538.  
  539. Rules like ~{NotOperator: 'not'.~} correspond to phrases with no
  540. components, because literals are not considered to be phrases.
  541. The phrases corresponding to these rules will therefore result in leaves.
  542.  
  543. Rules like ~{AssignmentStatement: VariableAccess ':=' Expression.~}
  544. correspond to phrases with components.
  545. The phrases corresponding to these rules will therefore result in tree
  546. nodes that have children.
  547. (In the case of ~{AssignmentStatement: VariableAccess ':=' Expression.~}
  548. there are two components, and hence two children,
  549. because names are considered to be phrases and literals are not.)
  550.  
  551. The syntax analyzer uses the syntax codes provided by the lexical analyzer
  552. to define the basic symbols.
  553. When it builds a leaf corresponding to an identifier or a denotation, it
  554. stores the value of the intrinsic attribute supplied by the lexical
  555. analyzer into that node.
  556.  
  557. Once the tree is built, the ~/attribute evaluator~/ establishes a number of
  558. values associated with the tree nodes.
  559. For example, each node representing an expression has a value associated
  560. with it that specifies the type of result yielded by that expression.
  561. Consider a Pascal- expression consisting of an operator and two operands.
  562. The type specification for the result in this case is determined by the
  563. expression's operator.
  564. The type specifications for the two operands are used to verify that the
  565. operands are legal for the expression's operator.
  566.  
  567. Attribute evaluation is the heart of any compiler, where most of the effort
  568. and most of the complexity resides.
  569. For this reason, specifications of attribute evaluation are usually
  570. partitioned by function to make them easier to understand.
  571. The major functions of attribute evaluation in Pascal- are scope analysis
  572. (determining the relationships between name uses and definitions), type
  573. analysis (verifying the context conditions on expressions) and code
  574. generation (producing a target program to implement the source code).
  575. Each of these functions is treated in a separate chapter.
  576.  
  577. One of the values established by the attribute evaluator is a tree that
  578. represents the target code.
  579. The final step in the Pascal- compilation is to linearize
  580. and output this tree.
  581. That process is carried out by a ~/program text generator~/,
  582. invoked on the value produced during attribute evaluation.
  583.  
  584. Some information is associated with specific contexts in the tree, while
  585. other information is associated with specific entities in the program.
  586. For example, the type of result yielded by an expression is a property of
  587. that expression, and is associated with the node representing the
  588. expression in the tree.
  589. The type of value yielded by a variable, however, is a property of that
  590. variable.
  591. Since a particular variable could be used many places in the tree, the
  592. information about its type must be available globally.
  593. The generated compiler includes a ~/definition table~/, in which arbitrary
  594. ~/properties~/ can be stored and accessed via ~/keys~/.
  595. To make the information about a variable's type available globally, the
  596. compiler associates a key with each variable and stores the type
  597. information in the definition via that key.
  598. The key is therefore a unique internal representation of the variable,
  599. and is stored at every use of that variable.
  600. Because the key is available at each use,
  601. the type information can be accessed at each use.
  602.  
  603. ~B~<How a compiler is specified~>
  604.  
  605. Eli focuses the user's attention on the requirements and design decisions
  606. that are unique to the Pascal- compiler, having already provided solutions
  607. to problems common to all compilers.
  608. It accepts descriptions of those requirements and design decisions, and
  609. combines them with its understanding of compiler construction problems to
  610. produce the Pascal- compiler.
  611. Requirements and design decisions can be thought of as specifications of
  612. instances of subproblems of the Pascal- translation problem.
  613. There are three basic ways in which a user might specify an instance of a
  614. subproblem:
  615. by analogy (``this problem is the same as problem X''),
  616. by description (``this is a problem of class Y, and is characterized as
  617. follows...'')
  618. and by solution(``here is a program to solve this problem'').
  619.  
  620. To support specification by analogy, Eli provides a library of solutions to
  621. common compiler subproblems.
  622. A user must have sufficient understanding of these subproblems to recognize
  623. that they have been solved before and to find the solutions in the library.
  624. For example, a Pascal- name is defined in a single procedure.
  625. If the same name is defined in a nested procedure, the outer definition is
  626. ``hidden'' within the inner procedure.
  627. This behavior is common to many programming languages, and a solution for
  628. the problem of associating the definition of a name with each use of that
  629. name can be solved by analogy by instantiating a module from Eli's library:
  630.  
  631. ~$~<Instantiate a module to analyze nested definitions~>==~{
  632. $/Tool/lib/Name/Nest.gnrc :inst
  633. ~}
  634.  
  635. To support specification by description, Eli provides a set of notations
  636. for characterizing common compiler subproblems.
  637. A user must not only be able to recognize the kind of subproblem, but also
  638. understand the notation used to characterize problems of that kind.
  639. The grammar of Section 2.3 is specified in such a notation -- a notation
  640. used to describe the phrase structure of a language and thus characterize
  641. the syntax analysis subproblem for that language.
  642.  
  643. To support specification by solution, Eli accepts arbitrary C code that
  644. solves a unique compiler subproblem, and incorporates it into the generated
  645. translator.
  646. A user must not only be able to recognize such subproblems, but also be
  647. able to solve them completely.
  648. An example of a subproblem of the Pascal- compiler that is specified by
  649. solution is that of scanning a comment (Section 4.3.2).
  650.  
  651. Specifications by analogy and description are two different forms of re-use:
  652. A specification by analogy re-uses a particular solution, while a
  653. specification by description re-uses a problem-solving method.
  654. In each case, re-use simplifies the specification by allowing much to be
  655. omitted.
  656. Eli provides leverage in direct proportion to the set of compiler
  657. subproblems for which it embodies solutions and problem-solving methods.
  658. In addition to this kind of leverage, however, Eli supports a paradigm for
  659. structuring the specification known as ~/literate programming~/.
  660.  
  661. The literate programming paradigm suggests that code (or in this case
  662. specifications) may need to be organized in one way to support human
  663. understanding and in another to support implementation.
  664. To solve this dilemma, the user creates a ~/document~/ whose organization
  665. supports human understanding.
  666. Information describing the organization that supports implementation is
  667. embedded in this document, which can be processed to yield a printed
  668. version for human use or a machine-readable version for implementation.
  669.  
  670. In its simplest form, the literate programming paradigm allows a user to
  671. group together specifications that are related but have different forms.
  672. For example, some subproblems of lexical analysis are specified by analogy,
  673. others by description, and still others by solution.
  674. Literate programming groups all of these specifications together into one
  675. file, organizing them so that their tasks and relationships are clear.
  676.  
  677. The document you are reading is an example of a more sophisticated use of
  678. literate programming:
  679. Not only are the various specifications that define subproblems of the
  680. Pascal- compilation problem organized according to function, but they are
  681. interspersed with explanations and commentary.
  682.  
  683. ~B
  684.  
  685. Eli requires that a complete translation problem be described by a single
  686. file of type ~{specs~}.
  687. A type-~{specs~} file lists all of the specifications for the subproblems
  688. of that translation problem.
  689. Subproblems specified by analogy are represented by library references
  690. (which might be to the Eli library or to some other library).
  691. Subproblems specified either by description or by solution are represented
  692. by file references.
  693. Here is content of ~{pascal-.specs~},
  694. the file that describes the Pascal- translation problem:
  695.  
  696. ~$~<The Pascal- compiler~>~Z==~{
  697.     /* Lexical and Syntax Analysis */
  698.  
  699. Structure.fw
  700. pident.gla :kwd    /* Exclude keywords from the finite-state machine */
  701.  
  702.  
  703.     /* Scope Analysis */
  704.  
  705. Scope.fw
  706. ~<Instantiate a module to analyze nested definitions~>
  707. $/Tool/lib/Name/NoKeyMsg.gnrc :inst
  708. $/Tool/lib/Name/Unique.gnrc :inst
  709.  
  710.  
  711.     /* Type Analysis */
  712.  
  713. Type.fw
  714. $/Tool/lib/Name/Field.gnrc :inst
  715.  
  716.  
  717.     /* A Pascal Computer */
  718.  
  719. Computer.fw
  720. $/Tool/lib/Tech/LeafPtg.gnrc :inst
  721.  
  722.  
  723.     /* Code Generation */
  724.  
  725. Code.fw
  726. ~}
  727.  
  728. Five of the specifications are type-~{fw~} files, which are documents that
  729. follow the literate programming paradigm.
  730. ~{Structure.fw~} contains Chapters 1-5; the other documents contain
  731. one chapter each.
  732. Each of Chapters 4-9 ends with a section that describes the purpose and
  733. contents of the specification files generated from that chapter.
  734.  
  735. Lines that begin with ~{$/Tool/lib/~} extract modules from the Eli library,
  736. specifying subproblems by analogy.
  737. Each of these library modules is described at the appropriate point in this
  738. report.
  739.  
  740. The line ~{pident.gla :kwd~} is an instruction to Eli to produce a lexical
  741. analyzer that behaves in a certain way; it is discussed in Section 4.4.
  742.  
  743. To create a Pascal- compiler from the set of specifications defined by
  744. ~{pascal-.specs~}, one or more of the following requests should be made to
  745. Eli:
  746.  
  747. ~$~<Requests creating a Pascal- compiler~>~Z~{
  748. pascal-.specs +fold +arg=(input) :stdout
  749. pascal-.specs +fold :exe >pascal.exe
  750. pascal-.specs +fold :source >src
  751. ~}
  752.  
  753. The first request asks Eli to create the compiler and run it with the
  754. command-line argument ~{input~}.
  755. Its purpose is to test the generated compiler against a sample Pascal-
  756. program.
  757. The second request also asks Eli to create the compiler, but to write the
  758. executable version into file ~{pascal.exe~} in the current directory.
  759. Its purpose is to create an executable version that can be used
  760. independently of Eli itself.
  761. The third request writes into directory ~{src~} (which must exist before
  762. the request is made) all of the files necessary to create an executable
  763. version of the compiler.
  764. Its purpose is to create a source code version that can be used
  765. independently of both Eli and the computer on which Eli is currently
  766. running.
  767. Directory ~{src~} will contain C files, header files, a Makefile, and a
  768. Configure script that can tailor the other files for specific
  769. machine/operating system combinations.
  770.  
  771. All of the requests specify the parameter ~{+fold~}, which causes Eli to
  772. generate a lexical analyzer that is case-insensitive.
  773. The meaning of this parameter is further elaborated in Section 4.4.
  774.  
  775. ~B~<Errors and Failures~>
  776.  
  777. The compiler must report any errors in the source program.
  778. Lexical errors (character sequences that are neither separators nor basic
  779. symbols) and syntactic errors (sequences of basic symbols that cannot be
  780. built into phrases) are detected automatically by the generated lexical and
  781. syntactic analyzers.
  782. Contextual errors (such as a Boolean operand for an addition operator) must
  783. be detected by tests specified as part of the attribution.
  784. When one of these tests detects an error, it must invoke the error
  785. reporting module with information about the nature of the error and its
  786. location.
  787. The location is determined from coordinate information (source program line
  788. and character position) stored in the node of the tree at which the
  789. computation is being made.
  790. Since the coordinate information is always supplied in exactly the same
  791. way, it is convenient to define a macro to simplify the error reporting:
  792.  
  793. ~O~<report.head~>~{
  794. #define    Message(s,t)     message(s,t,0,COORDREF)
  795. /* Produce a report at the leftmost symbol of the current fragment
  796.  *    On entry-
  797.  *       s=severity (INFO, WARNING, FATAL, DEADLY)
  798.  *       t=report text
  799.  ***/
  800. ~}
  801.  
  802. A type-~{head~} file contains C pre-processor directives that should be
  803. supplied to the generated attribution module.
  804. All type-~{head~} files are collected, in some arbitrary order, into a
  805. single file called ~{HEAD.h~}.
  806. The generated attribution module contains the C pre-processor directive
  807. ~{#include "HEAD.h"~}.
  808.  
  809. ~A~<Lexical Analysis~>
  810.  
  811. The purpose of lexical analysis is to determine the sequence of basic
  812. symbols making up the source program.
  813. Vocabulary errors, such as invalid characters, missing separators and
  814. unterminated comments, are detected and reported during lexical analysis.
  815. An Eli-generated compiler produces a sequence of basic symbols even if
  816. vocabulary errors are found.
  817. That sequence contains only basic symbols that are correct according to the
  818. language definition, and mirrors the program as closely as possible given
  819. the particular errors.
  820.  
  821. The lexical analyzer scans the input text character-by-character,
  822. recognizing basic symbols and discarding separators.
  823. It must determine a syntax code for each basic symbol and an intrinsic
  824. attribute for each ~{Name~} and ~{Numeral~}.
  825.  
  826. ~B~<Source text~>
  827.  
  828. Eli supplies a module for reading the source text and making it available
  829. to the remainder of the system.
  830. No specification is required for this module.
  831. It will be extracted from the Eli library if it is needed, unless the user
  832. supplies a module that defines its operations.
  833.  
  834. The operation ~{initBuf~} initializes the source text module.
  835. It has two arguments, the character form of the name of an open file and
  836. the descriptor for that file.
  837. On return from ~{initBuf~}, ~{TokenEnd~} addresses the first character of the
  838. file.
  839. If the file is empty, ~{TokenEnd~} addresses a null character (ASCII NUL,
  840. with value 0).
  841. Otherwise ~{initBuf~} guarantees that the string addressed by ~{TokenEnd~}
  842. consists of at least one complete line, including its terminating
  843. newline character.
  844. If the character following a terminating newline is not the null
  845. character then the following line, including its terminating newline
  846. character, is also guaranteed to be a part of the string.
  847.  
  848. When the client of the source module has dealt completely with the line or
  849. lines of the input file that are in memory, it invokes the source module
  850. operation ~{refillBuf~}.
  851. The ~{refillBuf~} operation has one argument, a pointer to the null
  852. character terminating the current string.
  853. Upon return from ~{refillBuf~}, the conditions described in the previous
  854. paragraph hold (i.e. ~{refillBuf~} has the same exit condition as
  855. ~{initBuf~}).
  856.  
  857. The lexical analyzer imposes a coordinate system on the text, with each
  858. coordinate consisting of a line number and a column number within the line.
  859. All components of the lexical analyzer that move across line boundaries
  860. must maintain these coordinates.
  861. They are implemented by two variables exported by the source text module
  862. but maintained by its clients: ~{LineNum~} and ~{StartLine~}.
  863. ~{LineNum~} contains the integer line number, while ~{StartLine~} addresses
  864. the character position preceding the first character of the line.
  865. Thus the column number can be computed by taking the difference between the
  866. pointer to the current character and ~{StartLine~}.
  867. Horizontal tab characters, which occupy only one position in the string but
  868. possibly many in the source line are handled by decrementing ~{StartLine~}
  869. appropriately.
  870.  
  871. ~B~<Intermediate code~>
  872.  
  873. The syntax code associated with each basic symbol is relevant only for the
  874. interaction between the lexical and syntactic analyzers.
  875. It is supplied by Eli, and its value is of no concern.
  876. There is no need to specify it.
  877.  
  878. Each distinct Pascal- ~{Name~} must be given a unique intrinsic attribute
  879. value, and instances of the same name must be given the same value.
  880. We will want to use this value to associate definitions and uses, so it
  881. must be compatible with the module we use for that process.
  882. Eli provides a module that can associate definitions with uses, and that
  883. module expects each name to be represented by a unique, small integer.
  884.  
  885. A Pascal- ~{Numeral~} denotes an integer value, and this value will be placed
  886. into the target machine code as an integer.
  887. It is therefore reasonable to make the intrinsic attribute of a ~{Numeral~}
  888. the integer value it denotes.
  889.  
  890. ~B
  891.  
  892. The delimiters of Pascal- are specified by literals in the grammar.
  893. Eli will extract those literals from the grammar, so they need not be
  894. re-specified here.
  895. Pascal- has two non-literal basic symbols, ~{Name~} and ~{Numeral~}.
  896. These must be specified, as must the form of a comment.
  897.  
  898. Because there are only a few basic symbol formats used in most programming
  899. languages, Eli provides a library of ~/canned descriptions~/.
  900. These canned descriptions provide not only the format of the basic symbol,
  901. but also the processors needed to establish the value of an appropriate
  902. intrinsic attribute.
  903. They are another example of specifying a subproblem (in this case scanning
  904. a name) by analogy.
  905.  
  906. The Pascal- definition of a name is the same as the Pascal definition of
  907. an identifier, so the specification of a ~{Name~} can be stated in terms
  908. of a canned description.
  909. Numerals and comments are somewhat more complex, and their specifications
  910. are discussed below.
  911.  
  912. ~$~<Scanning~>==~{
  913. Name:        PASCAL_IDENTIFIER
  914. ~<Scan a numeral~>
  915. ~<Scan a comment~>
  916. ~}
  917.  
  918. This specification defines the basic symbol ~{Name~}, which appears to the
  919. left of a colon (~{:~}), by means of the canned description
  920. ~{PASCAL_IDENTIFIER~}.
  921. ~{PASCAL_IDENTIFIER~} describes a character sequence that begins with a
  922. letter and continues with a (possibly empty) sequence of letters and
  923. digits.
  924. Once this character string has been recognized, the processor ~{mkidn~}
  925. will be used to provide it with an intrinsic attribute.
  926. (The properties of canned descriptions like ~{PASCAL_IDENTIFIER~} are given
  927. in the Eli documentation dealing with lexical analysis.)
  928.  
  929. ~C
  930.  
  931. A Pascal- ~{Numeral~} is defined as a sequence of digits.
  932. If the generated scanner simply accepts a sequence of digits as a numeral,
  933. however, it will decompose the incorrect phrase ~{10div 3~}
  934. into three basic symbols: ~{10~}, ~{div~} and ~{3~}.
  935. Although this is probably the programmer's intent, it is a violation of the
  936. language definition.
  937.  
  938. The generated scanner must therefore accept a sequence of digits and then
  939. verify that the next character is ~/not~/ a letter.
  940. If a letter is found, then the scanner must report a ``missing separator''
  941. error.
  942. Finally, a processor must be invoked to compute the value represented by
  943. the sequence of digits and deliver that value as an intrinsic attribute.
  944. Here is the resulting specification:
  945.  
  946. ~$~<Scan a numeral~>==~{
  947. Numeral:    $[0-9]+    (CheckSep)    [mkint]
  948. ~}
  949.  
  950. This specification defines the basic symbol ~{Numeral~}, which appears to
  951. the  left of a colon (~{:~}), by means of the regular expression
  952. ~{[0-9]+~} that accepts a sequence of one or more decimal digits.
  953. When the generated scanner encounters a character that is not a decimal digit,
  954. it will invoke the auxiliary scanner ~{CheckSep~}, passing a pointer to the
  955. first digit of the sequence and an integer giving the length of the
  956. sequence.
  957. Upon return from ~{CheckSep~}, the processor ~{mkint~} is invoked.
  958. It computes the value of the digit sequence and delivers that value as an
  959. intrinsic attribute.
  960. The processor ~{mkint~} is a library routine, but the auxiliary scanner
  961. ~{CheckSep~} must be defined specially for this task.
  962.  
  963. ~{CheckSep~} is a C routine that uses a table to check the character
  964. following the digit sequence.
  965. It assumes the ISO standard character set:
  966.  
  967. ~$~<Check for a separator~>==~{
  968. static char Letter[] = {
  969.   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  970.   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  971.   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  972.   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  973.   0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  974.   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
  975.   0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  976.   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
  977. };
  978.  
  979. char *
  980. CheckSep(start, length)
  981. char * start;    /* start of characters already recognized */
  982. int length;    /* length of what was already recognized */
  983. {
  984.   POSITION Now;
  985.  
  986.   if (Letter[start[length]]){
  987.     Now = curpos; Now.col += length;
  988.     message(FATAL, "Missing separator", 0, &Now);
  989.     }
  990.   return start+length;    /* First unprocessed character */
  991. }
  992. ~}
  993.  
  994. Verifying the separator that must follow a ~{Numeral~} is an example of a
  995. subproblem specified by solution.
  996. It is solved by the C routine ~{CheckSep~}, which obeys the standard
  997. interface given in the Eli documentation for auxiliary scanners: accept a
  998. pointer to the start of the basic symbol and the number of characters
  999. already recognized, and return a pointer to the first character following
  1000. the basic symbol.
  1001.  
  1002. ~C
  1003.  
  1004. Comments can be nested in Pascal-, and all comments are delimited by
  1005. braces.
  1006. They may span multiple lines.
  1007. This behavior does not correspond to any canned description, so the comment
  1008. scanning subproblem must be specified by solution:
  1009.  
  1010. ~$~<Scan a comment~>==~{
  1011.         $"{"    (Comment)
  1012. ~}
  1013.  
  1014. The auxiliary scanner ~{Comment~} begins with the character following the
  1015. opening brace that was recognized by the specified regular expression,
  1016. and seeks the matching closing brace.
  1017. It invokes itself recursively for a nested comment, handles transitions
  1018. between lines, and detects an unclosed comment:
  1019.  
  1020. ~$~<Comment scanner~>==~{
  1021. char *
  1022. Comment(start, length)
  1023. char * start;    /* start of characters recognized by reg expr */
  1024. int length;    /* length of what was recognized in reg expr */
  1025. {
  1026.   register char c;
  1027.   register char *p = start + length; /* first char not yet processed */
  1028.  
  1029.   for (;;) {
  1030.     while( (c = *p++) && c != '}' && c != '\n' && c != '{' ) ;
  1031.     if(c == '}') return(p);
  1032.     else if (c == '\n'){ LineNum++; StartLine = p-1; }
  1033.     else if (c == '{') p = Comment(start, p-start);
  1034.     else /*if (c == '\0')*/ {    /* end of the current input buffer */
  1035.       refillBuf(p-1); p = TokenEnd; StartLine = p-1;
  1036.       if (*p == '\0'){
  1037.         message(FATAL, "file ends in comment", 0, &curpos);
  1038.         return(p);
  1039.       }
  1040.     }
  1041.   }
  1042. }
  1043. ~}
  1044.  
  1045. ~{Comment~} simply advances ~{p~} until it reaches a ``significant''
  1046. character.
  1047. If that character signals a new line, the line number is incremented;
  1048. if it marks the end of the input, additional input is requested from the
  1049. source module (Section 4.1).
  1050. The value returned by ~{Comment~} is a pointer to the first character
  1051. position beyond the end of the comment, as required by the standard
  1052. auxiliary scanner interface.
  1053.  
  1054. ~B~<Identifier table~>
  1055.  
  1056. The processor ~{mkidn~} assigns a unique integer for each distinct name.
  1057. It uses a hash table to check whether the name has been seen before.
  1058. It stores the string form of each name once in an array of strings,
  1059. returning the index of the stored string.
  1060. That index is then made the value of the intrinsic attribute.
  1061.  
  1062. Pascal- requires that letter case not be distinguished in identifiers and
  1063. keywords.
  1064. Two additional specifications must be provided to obtain this behavior:
  1065. ~{mkidn~} must be specified case-insensitive and the keywords must be
  1066. recognized as though they were identifiers.
  1067. The ~{+fold~} parameter of an Eli request specifies that ~{mkidn~} is to
  1068. ignore letter case.
  1069.  
  1070. Keywords appear as literals in the grammar.
  1071. Normally, a grammar literal is built into the implementation of the lexical
  1072. analyzer.
  1073. To recognize certain literals using the mechanism used to recognize
  1074. identifiers requires that those literals be removed from the set of
  1075. literals passed to the lexical analyzer generator.
  1076. The file ~{keywords.gla~} defines the lexical structure of the Pascal-
  1077. keywords:
  1078.  
  1079. ~$~<keywords.gla~>~Z==~{
  1080. Name:    PASCAL_IDENTIFIER
  1081. ~}
  1082.  
  1083. By adding the line ~{keywords.gla :kwd~} to the type-~{specs~} file that
  1084. defines the Pascal- compiler (Section 3.3), we tell Eli to remove all
  1085. literals having the structure defined by ~{keywords.gla~} from the set
  1086. passed to the lexical analyzer generator.
  1087. It also adds those literals, with their corresponding syntax codes, to the
  1088. table used by ~{mkidn~}.
  1089.  
  1090. ~B~<Specification files for lexical analysis~>
  1091.  
  1092. Three kinds of specifications are needed to define the Pascal- lexical
  1093. analysis problem to Eli.
  1094.  
  1095. ~C
  1096.  
  1097. A type-~{gla~} file describes the lexical structure of the comments and the
  1098. basic symbols that do not appear literally in the grammar.
  1099. Eli uses this information, in conjunction with the descriptions of the
  1100. literal basic symbols derived from the grammar, to construct the scanner.
  1101.  
  1102. ~O~<lexical.gla~>~{
  1103. ~<Scanning~>
  1104. ~}
  1105.  
  1106. ~C
  1107.  
  1108. A type-~{c~} file describes a problem by giving its solution.
  1109. The problems of checking for a missing separator following a digit string
  1110. and scanning a Pascal- comment were described in this way.
  1111.  
  1112. ~O~<lexical.c~>==~{
  1113. #include "err.h"
  1114. #include "source.h"
  1115.  
  1116. ~<Check for a separator~>
  1117. ~<Comment scanner~>
  1118. ~}
  1119.  
  1120. No interface specification is required for this module, because all
  1121. auxiliary scanners and processors obey fixed interface conventions.
  1122. The scanner generator can therefore provide the appropriate ~{extern~}
  1123. declarations, given the routine names.
  1124.  
  1125. ~A~<Syntax Analysis~>
  1126.  
  1127. The purpose of syntax analysis is to determine the phrase structure
  1128. of the source program, and build a tree with one node per phrase.
  1129. Structural errors, such as unbalanced parentheses, are detected and reported
  1130. during syntactic analysis.
  1131. An Eli-generated compiler constructs a tree even if structural errors are
  1132. found.
  1133. That tree's structure is correct according to the language definition, and
  1134. mirrors the source program as closely as possible given the particular errors.
  1135.  
  1136. The source language grammar specifies the phrase structure of any source
  1137. program, and serves as the basic specification for syntax analysis.
  1138. It may be necessary to modify the grammar to ensure that it is complete and
  1139. unambiguous.
  1140. To make this guarantee, it may be necessary to distinguish some phrases
  1141. that have identical meanings and should correspond to identical nodes in
  1142. the tree.
  1143. These two points, and the specifications resulting from them, are the
  1144. subject of this chapter.
  1145.  
  1146. ~B~<Parser construction~>
  1147.  
  1148. Eli generates a particular kind of syntax analyzer, called an ~/LALR(1)
  1149. parser~/, from the grammar.
  1150. This is possible only if the grammar satisfies certain conditions:
  1151. At every point during a left-to-right scan of the source program's basic
  1152. symbols, the parser must be able to tell whether or not it is at the end of
  1153. a phrase and, if so, ~/which~/ phrase it has just completed.
  1154.  
  1155. The Pascal- grammar as defined in Section 2.3 satisfies the LALR(1) condition,
  1156. but it is not compatible with the definition of the vocabulary given in
  1157. Section 2.2.
  1158. This section corrects the incompatibilities.
  1159.  
  1160. ~C
  1161.  
  1162. The Pascal- grammar distinguishes several different kinds of names, such as
  1163. ~{ConstantNameDef~}, ~{ConstantNameUse~} and ~{VariableNameUse~}.
  1164. Symbols like these are not defined in the grammar,
  1165. and they are not specified as basic symbols either.
  1166. A human reader has no difficulty in assuming that they are, in fact, names;
  1167. this correspondence must be made explicit if the grammar is to specify the
  1168. parsing process.
  1169. Each of these symbols (except ~{ProgramName~}) defines a specific context
  1170. that determines the meaning of the name.
  1171. These contexts must be represented by distinct nodes in the tree, because
  1172. of their distinct meanings:
  1173.  
  1174. ~$~<Distinguishing name contexts~>==~{
  1175. ProgramName: Name .
  1176.  
  1177. ConstantNameDef: Name .
  1178. ConstantNameUse: Name .
  1179.  
  1180. TypeNameDef: Name .
  1181. TypeNameUse: Name .
  1182. FieldNameDef: Name .
  1183. FieldNameUse: Name .
  1184.  
  1185. VariableNameDef: Name .
  1186. VariableNameUse: Name .
  1187.  
  1188. ProcedureNameDef: Name .
  1189. ProcedureNameUse: Name .
  1190. ParameterNameDef: Name .
  1191. ~}
  1192.  
  1193. ~C
  1194.  
  1195. The symbol ~{Empty~} is used in the grammar to emphasize that an empty
  1196. statement is allowed, but this symbol is never defined.
  1197. There is no need to define it, because any meaning attributed to the empty
  1198. statement would be associated with the tree node representing that
  1199. statement.
  1200. Therefore the symbol ~{Empty~} should be replaced in the grammar by nothing
  1201. at all:
  1202.  
  1203. ~$~<Deleting the symbol ``Empty''~>==~{
  1204. #define Empty
  1205. ~}
  1206.  
  1207. Grammars are examined by the C pre-processor, as are most Eli specifications.
  1208. Thus pre-processor directives an C-style comments are allowed in grammars,
  1209. as they are in virtually every Eli specification.
  1210.  
  1211. ~B~<Specification files for syntax analysis~>
  1212.  
  1213. A type-~{con~} file specifies the grammar for the source language.
  1214. This information is used to construct the parser and define some of the
  1215. basic symbols.
  1216.  
  1217. ~O~<syntax.con~>~{
  1218. ~<Deleting the symbol ``Empty''~>
  1219. ~<Grammar~>
  1220. ~<Distinguishing name contexts~>
  1221. ~}
  1222.