home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / doc / ipd245.txt < prev    next >
Text File  |  1996-12-09  |  38KB  |  1,189 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.             Variant Translators for Version 9 of Icon
  8.  
  9.               Ralph E. Griswold and Kenneth Walker
  10.     Department of Computer Science, The University of Arizona
  11.  
  12.  
  13.  
  14.  
  15.  
  16. 1.__Introduction
  17.  
  18.    A preprocessor, which translates text from source language A
  19. to source language B,
  20.  
  21.         A -> B
  22.  
  23. is a popular and effective means of implementing A, given an
  24. implementation of B.  B is referred to as the target language.
  25. Ratfor [1] is perhaps the best known and most widely used example
  26. of this technique, although there are many others.
  27.  
  28.    In some cases A is a variant of B.  An example is Cg [2], a
  29. variant of C that includes a generator facility similar to Icon's
  30. [3].  Cg consists of C and some additional syntax that a prepro-
  31. cessor translates into standard C. A run-time system provides the
  32. necessary semantic support for generators. Note that the Cg
  33. preprocessor is a source-to-source translator:
  34.  
  35.         Cg -> C
  36.  
  37. where Cg differs from C only in the addition of a few syntactic
  38. constructs.  This can be viewed as an instance of a more general
  39. paradigm:
  40.  
  41.         A+ -> A
  42.  
  43.  
  44.    The term ``translator'' is used here in the general sense, and
  45. includes both source-to-source translators, such as preproces-
  46. sors, and source-to-object translators, such as compilers.  In
  47. practice, the application of a source-to-source translator
  48. (preprocessor) may be followed by the application of a source-
  49. to-object translator (compiler). The combination is, of course,
  50. also a translator.
  51.  
  52.    The term ``variant translator'' is used here to refer to a
  53. translator that differs in its action, in some respect, from a
  54. standard one for a language. The applications described in this
  55. report relate to source-to-source translators, although the term
  56. ``preprocessor'' is too restrictive to describe all of them.
  57.  
  58.    There are many uses for variant translators. Some of them are:
  59.  
  60.  
  61.  
  62.  
  63.  
  64. IPD245a                       - 1 -              October 25, 1995
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.  
  72.  
  73.      + the addition of syntactic constructions to produce a
  74.        superset of a language, as in the case of Cg
  75.  
  76.      + the deletion of features in order to subset a language
  77.  
  78.      + the translation of one source language into another [4]
  79.  
  80.      + the addition of monitoring code, written in the target
  81.        language
  82.  
  83.      + the insertion of termination code to output monitoring
  84.        data
  85.  
  86.      + the insertion of initialization code to incorporate addi-
  87.        tional run-time facilities
  88.  
  89.      + the insertion of code for debugging and checking purposes
  90.        [5,6]
  91.  
  92. Note that in several cases, the translations can be characterized
  93. by
  94.  
  95.         A -> A
  96.  
  97. The input text and the output text may be different, but they are
  98. both in A.  Both the input and the output of the variant transla-
  99. tor can be processed by a standard translator for the target
  100. language A.
  101.  
  102.    One way to implement a variant translator is to modify a stan-
  103. dard source-to-object translator, avoiding the preprocessor. This
  104. approach may or may not be easy, depending on the translator. In
  105. general, it involves modifying the code generator, which often is
  106. tricky and error prone. Furthermore, if the variant is an experi-
  107. ment, the effort involved may be prohibitive.
  108.  
  109.    The standard way to produce a variant translator is the one
  110. that is most often used for preprocessors in general, including
  111. ones that do not fit the variant translator paradigm - writing a
  112. stand-alone program in any convenient language. In the case of
  113. Ratfor, the preprocessor is written in Ratfor, providing the
  114. advantages of bootstrapping.
  115.  
  116.    This approach presents several problems. In the first place,
  117. writing a complete, efficient, and correct preprocessor is a sub-
  118. stantial undertaking.  In experimental work, this effort may be
  119. unwarranted, and it is common to write the preprocessor in a
  120. high-level language, handling only the variant portion of the
  121. syntax, leaving the detection of errors to the final translator.
  122. Such preprocessors have the virtue of being easy to produce, but
  123. they often are slow, frequently unfaithful to the source
  124. language, and the failure to parse the input language completely
  125. may lead to mysterious results when errors are detected, out of
  126. context, by the final translator.
  127.  
  128.  
  129.  
  130. IPD245a                       - 2 -              October 25, 1995
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137.  
  138.  
  139.    Modern tools such as Lex [7] and Yacc [8], that operate on
  140. grammatical specifications, have made the production of compilers
  141. (and hence translators in general) comparatively easy and have
  142. removed many of the sources of error that are commonly found in
  143. hand-tailored translators. Nonetheless, the construction of a
  144. translator for a large and complicated language is still a sub-
  145. stantial undertaking.
  146.  
  147.    If, however, a translator already exists for a language that
  148. is based on the use of such tools, it may be easy to produce a
  149. variant translator that is efficient and demonstrably correct by
  150. modifying grammatical specifications.  The key is the use of
  151. these tools to produce a source-to-source translator, rather than
  152. producing a source-to-object translator.  This technique was used
  153. in Cg. An existing Yacc specification for the C compiler was
  154. modified to generate C source code instead of object code. The
  155. idea is a simple one, but it has considerable utility and can be
  156. applied to a wide range of situations.
  157.  
  158.    This report describes a system that uses this approach for the
  159. construction of variant translators for Icon.  This system
  160. requires Icon, Yacc, and C.
  161.  
  162.  
  163. 2.__Overview_of_Variant_Translators_for_Icon
  164.  
  165.    The heart of the system for constructing variant translators
  166. for Icon consists of an ``identity translator''.  The output of
  167. this identity translator differs from its input only in the
  168. arrangement of nonsemantic ``white space'' and in the insertion
  169. of semicolons between expressions, which are optional in some
  170. places in Icon programs.
  171.  
  172.    The identity translator uses the same Yacc grammar as the reg-
  173. ular Icon translator, but uses different semantic actions. These
  174. semantic actions are cast as macro definitions in the grammar,
  175. which are expanded before the grammar is translated by Yacc into
  176. a parser. One set of macros is supplied for the regular Icon
  177. translator and another set is supplied for the identity transla-
  178. tor.  The macros used by the identity translator echo the input
  179. text, producing source-code output. In addition to the grammar,
  180. other code is shared between the two translators, insuring a high
  181. degree of consistency between the two systems.
  182.  
  183.    A variant translator is created by first creating an identity
  184. translator and then modifying it. There is a shell script for
  185. producing identity translators and associated support software to
  186. simplify the process of making modifications.  This support
  187. software allows macro definitions to be changed via specification
  188. files, minimizing the clerical work needed to vary the format of
  189. the output. There also is a provision for including user func-
  190. tions in the parser, so that more complicated operations can be
  191. written in C. Finally, the grammar for the identity translator
  192. can be modified in order to make structural changes in the
  193.  
  194.  
  195.  
  196. IPD245a                       - 3 -              October 25, 1995
  197.  
  198.  
  199.  
  200.  
  201.  
  202.  
  203.  
  204.  
  205. syntax.
  206.  
  207.    The following sections describe this system in more detail and
  208. include a number of examples of its use.  The material that fol-
  209. lows is intended for use in conjunction with listings of source
  210. files from the variant translator system.
  211.  
  212.  
  213. 3.__The_Grammar_for_the_Icon_Identity_Translator
  214.  
  215.    The grammar for Icon is in the file h/grammar.h in the direc-
  216. tory in which variant translators are installed.  Many variant
  217. translators can be constructed without modifying this grammar,
  218. and minor modifications can be made to it without a detailed
  219. knowledge of its structure. Knowledge of a few aspects of this
  220. grammar are important, however, for understanding the translation
  221. process.
  222.  
  223.    There are two types of semantic actions. The semantic action
  224. for a declaration outputs text. The semantic action for a com-
  225. ponent of a declaration, such as an identifier list or an expres-
  226. sion, assigns a string to the Yacc attribute for the component.
  227. Declarations are parsed by the production:
  228.  
  229.         decl    : record {Recdcl($1);} ;
  230.                 | proc {Procdcl($1);} ;
  231.                 | global {Globdcl($1);} ;
  232.                 | link {Linkdcl($1);} ;
  233.                 | invocable {Invocdcl($1);} ;
  234.  
  235. The non-terminals record, proc, global, link, and invocable each
  236. produce a string and the corresponding macro Recdcl, Procdcl,
  237. Globdcl, Linkdcl, or Invocdcl prints the string.
  238.  
  239.    Because the grammar is used for both the regular Icon transla-
  240. tor and the variant translator system, the macro calls must be
  241. more general than what is required for either one alone. Consider
  242. the production for global:
  243.  
  244.         global  : GLOBAL {Global0($1);} idlist  {Global1($1, $2, $3);} ;
  245.  
  246. The macro Global0 is needed in the regular translator, but per-
  247. forms no operation in the identity translator. The macro Global1
  248. does the work in the identity translator; it concatenates "global
  249. " with the string produced by idlist, and this new string becomes
  250. the result of this production. The macro Global1 is passed $1,
  251. $2, and $3 even though it only uses $3. This is done for general-
  252. ity.
  253.  
  254.    The rules and the definitions that construct and output
  255. strings are provided as part of the identity translator. When a
  256. variant translator is constructed, changes are necessary only in
  257. situations in which the input is not to be echoed in the output.
  258.  
  259.  
  260.  
  261.  
  262. IPD245a                       - 4 -              October 25, 1995
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269.  
  270.  
  271.    Modifications and additions to the standard grammar require a
  272. more thorough understanding of the structure of the grammar.
  273.  
  274.  
  275. 4.__Macro_Definitions
  276.  
  277.    The purpose of using macro calls in the semantic actions of
  278. the grammar is to separate the structure of the grammar from the
  279. format of the output and to allow the output format to be speci-
  280. fied without modification of the grammar.
  281.  
  282.    The macro definitions for declarations are all the same. For
  283. example the definition of Global for the identity translator is:
  284.  
  285.         #define Globdcl(x) if (!nocode) treeprt(x); treefree(x)
  286.  
  287. The variable nocode is set when an error is detected during pars-
  288. ing.  This helps prevent the variant translator from generating a
  289. program with syntax errors. The reason for doing this is that the
  290. output of a variant translator is usually piped directly into the
  291. regular Icon translator. If syntax errors were propagated, two
  292. error messages would result: one from the variant translator and
  293. one from the Icon translator. The message from the variant trans-
  294. lator is the one that is wanted because it references the line
  295. number of the original source whereas the message from the Icon
  296. translator references the line number of the generated source.
  297.  
  298.    The function treeprt() prints a string and the function tree-
  299. free() reclaims storage. See the Section 5 for details of string
  300. representation.
  301.  
  302. 4.1__Specifications_for_Macros
  303.  
  304.    The macro definitions for expressions produce strings, gen-
  305. erally resulting from the concatenation of strings produced by
  306. other rules.  In order to simplify the definition of macros, a
  307. specification format is provided.  Specifications are processed
  308. by a program that produces the actual definitions.  For example,
  309. the macro While1 is used in the rule
  310.  
  311.         WHILE expr DO expr {While1($1,  $2,  $3,  $4);} ;
  312.  
  313. A specification for this macro to produce an identity translation
  314. is:
  315.  
  316.         While1(w,  x,  y,  z)        "while " x        " do "  z
  317.  
  318. Tabs separate the components of the specification. The first com-
  319. ponent is the prototype for the macro call, which may include
  320. optional arguments enclosed in parentheses as illustrated by the
  321. example above. The remaining components are the strings to be
  322. concatenated with the result being assigned to the Yacc pseudo-
  323. variable $$.
  324.  
  325.  
  326.  
  327.  
  328. IPD245a                       - 5 -              October 25, 1995
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.  
  337.    Specification lines that begin with # or which are empty are
  338. treated as comments.  A set of lines delineated by %{ and %} is
  339. copied unchanged.  The ``braces'' %{ and %} must each occur alone
  340. on a separate line; these two delimiting lines are not copied.
  341. This feature allows the inclusion of actual macro definitions, as
  342. opposed to specifications, and the inclusion of C definitions.
  343. The standard macro definitions supplied for the identity transla-
  344. tor include examples of these features. These definitions are the
  345. file ident.defs.
  346.  
  347.    Definitions can be changed by modifying the standard ones or
  348. by adding new definitions. In the case of duplicate definitions,
  349. the last one holds.  Definitions can be provided in several
  350. files, so variant definitions can be provided in a separate file
  351. that is processed after the standard definitions. See Sec. 8.
  352.  
  353.    Definitions can be deleted by providing a specification that
  354. consists only of a prototype for the call. For example, the
  355. specification
  356.  
  357.         While1()
  358.  
  359. deletes the definition for While1. This is a convenient way to
  360. insure a macro is undefined. It is usually used along with the
  361. copy feature to introduce macro definitions that cannot be gen-
  362. erated by the specification system.  For example, the following
  363. specifications eliminate reclamation of storage, preserving
  364. strings between declarations.
  365.  
  366.         Globdcl()
  367.         Linkdcl()
  368.         Procdcl()
  369.         Recdcl()
  370.         %{
  371.         #define Globdcl(x) if (!nocode) treeprt(x);
  372.         #define Linkdcl(x) if (!nocode) treeprt(x);
  373.         #define Procdcl(x) if (!nocode) treeprt(x);
  374.         #define Recdcl(x) if (!nocode) treeprt(x);
  375.         %}
  376.  
  377.  
  378. 4.2__Macros_for_Icon_Operators
  379.  
  380.    There is a distinct macro name for each Icon operator.  For
  381. example, Blim(x,  y,  z) is the macro for a limitation expres-
  382. sion,
  383.  
  384.         expr1 \ expr2
  385.  
  386. Note that the parameter y is the operator symbol itself.  To
  387. avoid having to know the names of the macros for the operators,
  388. specifications allow the use of operator symbols in prototypes.
  389. The symbols are automatically replaced by the appropriate names.
  390. Thus
  391.  
  392.  
  393.  
  394. IPD245a                       - 6 -              October 25, 1995
  395.  
  396.  
  397.  
  398.  
  399.  
  400.  
  401.  
  402.  
  403.         \(x,  y,  z)
  404.  
  405. can be used in a specification in place of
  406.  
  407.         Blim(x,  y,  z)
  408.  
  409. Unary operators are similar. For example, Uqmark(x, y), which is
  410. the macro for ?expr, can be specified as ?(x, by). In this case
  411. the parameter x is the operator symbol.
  412.  
  413.    In most cases, all operators of the same kind are translated
  414. in the same way. Since Icon has many operators, a generic form of
  415. specification is provided to allow the definition of all opera-
  416. tors in a category to be given by a single specification. In a
  417. specification, a string of the form <type> indicates a category
  418. of operators. The categories are:
  419.  
  420.         <uop>   unary operators, except as follows
  421.         <ucs>   control structures in unary operator format
  422.         <bop>   binary operators, except as follows
  423.         <aop>   assignment operators
  424.         <bcs>   control structures in binary operator format
  425.  
  426. The category <ucs> consists only of |.  The category <bcs> con-
  427. sists of ?, |, !, and \.
  428.  
  429.    For example, the specification for binary operators for iden-
  430. tity translations is
  431.  
  432.         <bop>(x, y, z)      x        " <bop> "         z
  433.  
  434. This specification results in the definition for every binary
  435. operator: +(x, y, z), -(x, y, z), and so on. In such a specifica-
  436. tion, every occurrence of <bop> is replaced by the corresponding
  437. operator symbol. Note that blanks are necessary to separate the
  438. binary operator from its operands. Otherwise,
  439.  
  440.         i * *s
  441.  
  442. would be translated into
  443.  
  444.         i**s
  445.  
  446. which is equivalent to
  447.  
  448.         i ** s
  449.  
  450.  
  451.    The division of operators into categories is based on their
  452. semantic properties. For example, a preprocessor may translate
  453. all unary operators in the same way, but translate the repeated
  454. alternation control structure into a programmer-defined control
  455. operation [9].
  456.  
  457.  
  458.  
  459.  
  460. IPD245a                       - 7 -              October 25, 1995
  461.  
  462.  
  463.  
  464.  
  465.  
  466.  
  467.  
  468.  
  469. 5.__String_Handling
  470.  
  471.    Strings are represented as binary trees in which the leaves
  472. contain pointers to C strings. The building of these trees can be
  473. thought of as doing string concatenation using lazy evaluation.
  474. The concatenation operation just creates a new root node with its
  475. two operands as subtrees.  The real concatenation is only done
  476. when the strings are written out. Another view of this is that
  477. concatenation builds a list of strings with the list implemented
  478. as a binary tree. This view allows ``strings'' to be treated as a
  479. list of tokens. This approach is useful in more complicated
  480. situations where there is a need to distinguish more than just
  481. syntactic structures. For example, the head of the main procedure
  482. can be distinguished from the heads of other procedures by look-
  483. ing at the second string in the list for the procedure declara-
  484. tion.
  485.  
  486.    Strings come from three sources during translation: strings
  487. produced by the lexical analyzer, literal strings, and strings
  488. produced by semantic actions. The lexical analyzer produces
  489. nodes.  The cases where the nodes that are produced by the lexi-
  490. cal analyzer are of interest occur where strings are recognized
  491. for identifiers and literals - the tokens IDENT, STRINGLIT,
  492. INTLIT, REALIT, and CSETLIT.  These nodes contain pointers to the
  493. strings recognized. (The actual strings are stored in a string
  494. space and remain there throughout execution of the translator.)
  495. These nodes can be used directly as a tree (of one node) of
  496. strings. Other nodes produced by the lexical analyzer, for exam-
  497. ple those for operators, do not contain strings. However, all of
  498. these nodes contain line and column numbers referring to the
  499. location of the token in the source text. This line and column
  500. information can be useful in variant translators that need to
  501. produce output that contains position information from the input.
  502.  
  503.    A literal string must be coerced into a tree of one node.
  504. This is done with the C function
  505.  
  506.         q(s)
  507.  
  508. This is handled automatically when macros are produced from
  509. specifications.  For example, the specification
  510.  
  511.         Fail(x) "fail"
  512.  
  513. is translated into the macro
  514.  
  515.         #define Fail(x) $$ = q("fail")
  516.  
  517.  
  518.    Most semantic actions concatenate two or more strings and pro-
  519. duce a string.  They use the C function
  520.  
  521.         cat(n, t1, t2, ..., tn)
  522.  
  523.  
  524.  
  525.  
  526. IPD245a                       - 8 -              October 25, 1995
  527.  
  528.  
  529.  
  530.  
  531.  
  532.  
  533.  
  534.  
  535. which takes a variable number of arguments and returns a pointer
  536. to the concatenated result. The first argument is the number of
  537. strings to be concatenated. The other arguments are the strings
  538. in tree format. The result is also in tree format.
  539.  
  540.    As an example, the specification
  541.  
  542.         While1(w, x, y, z)  "while " x        " do "   z
  543.  
  544. produces the definition
  545.  
  546.         #define While1(w, x, y, z) $$ = cat(4, q("while "), x, q(" do "), z)
  547.  
  548.  
  549.    Another function, item(t, n), returns the nth node in the
  550. ``list'' t.  For example, the name of a procedure is contained in
  551. the second node in the list for the procedure declaration. Thus,
  552. if the procedure heading list is the value of head, item(head, 2)
  553. produces the procedure name.
  554.  
  555.    There are three macros that produce values associated with a
  556. node.  Str0() produces the string.  For example, code conditional
  557. on the main procedure could be written as follows:
  558.  
  559.         if (strcmp(Str0(item(head, 2)), "main") == 0) {
  560.                   .
  561.                   .
  562.                   .
  563.            }
  564.  
  565.  
  566.    As this example illustrates, semantic actions may be too com-
  567. plicated to be represented conveniently by macros. In such cases
  568. parser functions can be used. A file is provided for such func-
  569. tions. See Section 9 for an example.
  570.  
  571.    The macros Line and Col produce the source-file line number
  572. and column, respectively, of the place where the text for the
  573. node begins. The use of these attributes is illustrated in Sec-
  574. tion 9.
  575.  
  576.    In some sophisticated applications, variant translators may
  577. need other capabilities that are available in the translator sys-
  578. tem. For example, if a function produces a string, it may be
  579. necessary place this string in a place that survives the function
  580. call.  The Icon translator has a string allocation facilities
  581. that can be used for this purpose: The macro AppChar(lex_sbuf, c)
  582. appends a character to the lexical analyzer's string buffer and
  583. the function str_install(&lex_sbuf) saves the string in a string
  584. table.  The use of such facilities requires more knowledge of the
  585. translator system than it is practical to provide here. Persons
  586. with special needs should study the translator in more detail.
  587.  
  588.  
  589.  
  590.  
  591.  
  592. IPD245a                       - 9 -              October 25, 1995
  593.  
  594.  
  595.  
  596.  
  597.  
  598.  
  599.  
  600.  
  601. 6.__Modifying_Lexical_Components_of_the_Translator
  602.  
  603.    The lexical analyzer for Icon is written in C rather than in
  604. Lex in order to make it easier to perform semicolon insertion and
  605. other complicated tasks that occur during lexical analysis.
  606. Specification files are used to build portions of the lexical
  607. analyzer, making it easy to modify.  The three kinds of changes
  608. that are needed most often are the addition of new keywords,
  609. reserved words, and operators.
  610.  
  611.    The identity translator accepts any identifier as a keyword,
  612. leaving its resolution to subsequent processing by the Icon
  613. translator. Nothing need be done to add a new keyword except for
  614. processing it properly in the variant translator.
  615.  
  616.    The specification file common/tokens.txt contains a list of
  617. all reserved words and operator symbols.  Each symbol has associ-
  618. ated flags that indicate whether it can begin or end an expres-
  619. sion. These flags are used for semicolon insertion.
  620.  
  621.    To add a new reserved word, insert it in proper alphabetical
  622. order in the list of reserved words in tokens.txt and give it a
  623. new token name.  To add a new operator, insert it in the list of
  624. operators in tokens.txt (order there is not important) and give
  625. it a new token name.  The new token names must be added to the
  626. grammar.
  627.  
  628.    The addition of a new operator also requires modifying the
  629. specification of a finite-state automaton, comon/op.txt.  Its
  630. structure is straightforward.
  631.  
  632.  
  633. 7.__Building_a_Variant_Translator
  634.  
  635.    The steps for setting up the directory structure for a variant
  636. translator are:
  637.  
  638.      +  create a directory for the translator
  639.  
  640.      +  make that directory the current directory
  641.  
  642.      +  execute the shell script icon_vt supplied with Version 8
  643.         of Icon
  644.  
  645. For example, if the variant translator is to be in the directory
  646. xtran and Icon is installed in /usr/icon/bin, the following com-
  647. mands will build the variant translator:
  648.  
  649.         mkdir xtran
  650.         cd xtran
  651.         /usr/icon/bin/icon_vt
  652.  
  653.  
  654.    The shell script icon_vt creates a number of files in the new
  655.  
  656.  
  657.  
  658. IPD245a                      - 10 -              October 25, 1995
  659.  
  660.  
  661.  
  662.  
  663.  
  664.  
  665.  
  666.  
  667. directory and in three sub-directories: common, itran, and h.
  668. Unless changes to the lexical analyzer are needed, at most three
  669. files need to be modified to produce a new translator:
  670.  
  671.         variant.defs  variant macro definitions (initially empty)
  672.         variant.c     parser functions (initially empty)
  673.         h/grammar.h   Yacc grammar for Icon
  674.  
  675. A non-empty variant.c usually requires #include files to provide
  676. needed declarations and definitions. See the example that fol-
  677. lows.
  678.  
  679.    The make file in the main translator directory just insures
  680. that the program define has be compiled and then does a make in
  681. the itran directory.  Performing a make in the itran directory
  682. first combines variant.defs with the standard macro definitions
  683. (in ident.defs) and processes them to produce the definition
  684. file, itran/ident.h. The C preprocessor is then used to expand
  685. the macros in h/grammar.h using these definitions and the result,
  686. after some ``house keeping'', is put in itran/vgram.g. Next, Yacc
  687. uses the grammar in itran/vgram.g to build a new parser,
  688. tparse.c.  There are over 200 shift/reduce conflicts in the iden-
  689. tity translator.  All of these conflicts are resolved properly.
  690. More conflicts should be expected if additions are made to the
  691. grammar.  Reduce/reduce conflicts usually indicate errors in the
  692. grammar.  Finally, all the components of the system are compiled,
  693. including variant.c, and linked to produce vitran, the variant
  694. translator.
  695.  
  696.    Most of the errors that may occur in building a variant trans-
  697. lator are obvious and easily fixed. Erroneous changes to the
  698. grammar, however, may be harder to detect and fix. Error messages
  699. from Yacc or from compiling itran/tparse.c refer to line numbers
  700. in itran/vgram.g. These errors must be related back to
  701. variant.defs or h/grammar.h by inspection of itran/vgram.g.
  702.  
  703.  
  704. 8.__Using_a_Variant_Translator
  705.  
  706.    The translator, vitran, takes an input file on the command
  707. line and translates it.  The specification - in place of an input
  708. file indicates standard input.  The output of vitran is written
  709. to standard output.  For example,
  710.  
  711.         vitran pre.icn >post.icn
  712.  
  713. translates the file pre.icn and produces the output in post.icn.
  714. The suffix .icn on the argument to vitran is optional; the exam-
  715. ple above can be written as:
  716.  
  717.         vitran pre >post.icn
  718.  
  719. Assuming the variant translator produces Icon source language,
  720. post.icn can be translated into object code by
  721.  
  722.  
  723.  
  724. IPD245a                      - 11 -              October 25, 1995
  725.  
  726.  
  727.  
  728.  
  729.  
  730.  
  731.  
  732.  
  733.         icont post.icn
  734.  
  735. where icont is the standard Icon command processor.
  736.  
  737.    Variant translators accept the following options:
  738.  
  739.      -m  process input file with the macro processor m4 before
  740.          translation
  741.  
  742.      -s  suppress informative messages
  743.  
  744.      -P  do not generate #line directives
  745.  
  746. The -P option may be necessary to prevent the insertion of #line
  747. directives at places that result in syntactically erroneous out-
  748. put.
  749.  
  750.  
  751. 9.__An_Example
  752.  
  753.    As an example of the construction of a variant translator,
  754. consider the problem of monitoring string concatenation in Icon
  755. programs, writing out the size of each string constructed by con-
  756. catenation. One way to do this, of course, is to modify Icon
  757. itself, adding the necessary monitoring code to the C function
  758. that performs concatenation.  An alternative approach, which does
  759. not require changes to Icon itself, is to produce a variant
  760. translator that translates concatenation operations into calls of
  761. an Icon procedure, but leaves everything else unchanged:
  762.  
  763.         expr1 || expr2 -> Cat(expr1, expr2)
  764.  
  765. The procedure Cat() might have the form:
  766.  
  767.         procedure Cat(s1, s2)
  768.            write(&errout,"concatenation: ",*s1 + *s2," characters")
  769.            return s1 || s2
  770.         end
  771.  
  772. Such a procedure could be added to a preprocessed program (Cat()
  773. is not preprocessed itself) in order to produce the desired
  774. information when the program is run.
  775.  
  776.    A single definition in variant.defs suffices:
  777.  
  778.         ||(x, y, z)         "Cat("   x        ","      z       ")"
  779.  
  780. Note, however, that Icon also has an augmented assignment opera-
  781. tor for string concatenation:
  782.  
  783.         expr1 ||:= expr2
  784.  
  785. This operation can be handled by the definition
  786.  
  787.  
  788.  
  789.  
  790. IPD245a                      - 12 -              October 25, 1995
  791.  
  792.  
  793.  
  794.  
  795.  
  796.  
  797.  
  798.  
  799.         ||:=(x, y, z)       x        " := Cat("        x       ","z")"
  800.  
  801. Observe that this definition is not precisely faithful to the
  802. semantics of Icon, since it causes expr1 to be evaluated twice,
  803. while expr1 is evaluated only once in the true augmented assign-
  804. ment operation. This problem cannot be avoided here, since all
  805. arguments are passed by value in Icon, but in practice, this
  806. discrepancy is unlikely to cause problems.
  807.  
  808.    In the application of such a monitoring facility, it may be
  809. useful to have a provision whereby concatenation can be performed
  810. without being monitored. This can be accomplished by adding an
  811. alternative operator symbol for concatenation, such as
  812.  
  813.         expr1 ~ expr2 -> expr1 || expr2
  814.  
  815. Adding a new operator to the syntax of Icon requires modifying
  816. the grammar in h/grammar.h. Since this alternative concatenation
  817. operator should have the same precedence and associativity as the
  818. regular concatenation operator, it can be added to the definition
  819. of expr5:
  820.  
  821.         expr5      : expr6 ;
  822.                    | expr5 CONCAT expr6 {Bcat($1,$2,$3);} ;
  823.                    | expr5 TILDE expr6 {Bacat($1,$2,$3);} ;
  824.                    | expr5 LCONCAT expr6 {Blcat($1,$2,$3);} ;
  825.  
  826. where TILDE is the token name for ~ . Then the definition of
  827. Bacat() can be added to variant.defs:
  828.  
  829.         Bacat(x, y, z)      x        " || "   z
  830.  
  831. Such changes to grammar.h usually increase the number of
  832. shift/reduce conflicts encountered by Yacc.
  833.  
  834.    One difficulty with monitoring concatenation as described
  835. above is that the procedure Cat() must be added to the translated
  836. program.  This can be accomplished automatically by arranging to
  837. have the code for Cat() written out when the variant translator
  838. encounters the main procedure.  This is a case where a parser
  839. function, as mentioned in Section 5, is more appropriate than a
  840. macro definition.
  841.  
  842.    The first step is to change the specifications.  The defini-
  843. tion for the macro, Proc1, that produces procedure declarations
  844. is replaced by a call to a parser function. The changes to
  845. variant.defs are:
  846.  
  847.         %{
  848.         nodeptr proc();
  849.         %}
  850.         Proc1(u, v , w, x, y, z)     proc(u, w, x, y)
  851.  
  852. The C declaration for proc() is included in the file vgram.g and
  853.  
  854.  
  855.  
  856. IPD245a                      - 13 -              October 25, 1995
  857.  
  858.  
  859.  
  860.  
  861.  
  862.  
  863.  
  864.  
  865. subsequently incorporated by Yacc into tparse.c where the call to
  866. proc() is compiled. Note that proc() returns a nodeptr.
  867.  
  868.    The C function is placed in variant.c. It might have the form
  869.  
  870.         #include "h/config.h"
  871.         #include "itran/tree.h"
  872.         #include "itran/tproto.h"
  873.  
  874.  
  875.         nodeptr item(), cat(), q();
  876.  
  877.  
  878.         nodeptr proc(u, w, x, y)
  879.         nodeptr u, w, x, y;
  880.            {
  881.            static char *catproc = "procedure Cat(s1, s2)\n\
  882.         write(&errout,\"concatenation:  \", *s1 + *s2,\" characters\")\n\
  883.         return s1 || s2\n\
  884.         end\n";
  885.  
  886.  
  887.            if (strcmp(Str0(item(u, 2)), "main") == 0)
  888.               return cat(7, q(catproc), u, q(";\n"), w, x, y, q("end\n"));
  889.            else
  890.               return cat(6, u, q(";\n"), w, x, y, q("end\n"));
  891.            }
  892.  
  893. Thus, when the main procedure is encountered, the text for Cat()
  894. is written out before the text for the main procedure, but all
  895. other procedures are written out as they would be in the absence
  896. of this function.
  897.  
  898.    One disadvantage of this way of providing the text for Cat()
  899. is that the literal string is long, complicated, and difficult to
  900. change. In addition, it is necessary to rebuild the variant
  901. translator in order to change Cat(). Since monitoring of this
  902. kind is likely to suggest changes to the format or nature of the
  903. data being written, it is useful to be able to change Cat() more
  904. easily. One solution to this problem is to produce a link
  905. declaration for the file containing the translated procedure
  906. rather than the text of the procedure. With this change, the
  907. parser function might have the form
  908.  
  909.         nodeptr proc(u, w, x, y)
  910.         nodeptr u, w, x, y;
  911.            {
  912.  
  913.  
  914.  
  915.  
  916.  
  917.  
  918.  
  919.  
  920.  
  921.  
  922. IPD245a                      - 14 -              October 25, 1995
  923.  
  924.  
  925.  
  926.  
  927.  
  928.  
  929.  
  930.  
  931.            if (strcmp(Str0(item(u, 2)), "main") == 0)
  932.               return cat(7, q("link cat\n\n"), u, q(";\n"), w, x, y, q("end\n"));
  933.            else
  934.               return cat(6, u, q(";\n"), w, x, y, q("end\n"));
  935.            }
  936.  
  937.  
  938.    The monitoring facility described above produces information
  939. about all string concatenation operations, but it is not possible
  940. to distinguish among them. It might be more useful to know the
  941. amount of concatenation performed by each concatenation opera-
  942. tion. This can be done if the location of the operator in the
  943. source program can be identified.  As mentioned in Section 5,
  944. tree nodes contain line and column information provided by the
  945. lexical analyzer.  Thus, the translation for the concatenation
  946. operations could provide this addition information as extra argu-
  947. ments to Cat(), which then could print out the locations along
  948. with information about the amount of concatenation.
  949.  
  950.         procedure Cat(s1, s2, i, j)
  951.            write(&errout,"concatenation: ", *s1 + *s2, " characters at [", i, ",", j, "]")
  952.            return s1 || s2
  953.         end
  954.  
  955. The specifications for the translation of the concatenation
  956. operations might be changed to
  957.  
  958.         %{
  959.         nodeptr proc(), Locargs();
  960.         %}
  961.         Proc1(u, v, w, x, y, z)      proc(u, w, x, y)
  962.         ||(x, y, z)         "Cat("   x        ","      z       Locargs(y)")"
  963.         ||:=(x, y, z)       x        " := Cat("        x       ","zLocargs(y)")"
  964.         Bacat(x, y, z)      x        " || "   z
  965.  
  966. where Locargs() is a parser function that produces a string con-
  967. sisting of the line and column numbers between commas. This func-
  968. tion might have the form
  969.  
  970.         nodeptr Locargs(x)
  971.         nodeptr x;
  972.         {
  973.            char buf[25];
  974.            char *s;
  975.  
  976.            sprintf(buf, ",%d,%d", Col(x), Line(x));
  977.            for (s = buf, s != 0, ++s)
  978.               AppChar(lex_sbuf, *s);
  979.            return q(str_install(&lex_sbuf));
  980.         }
  981.  
  982. The C function sprintf() is used to do the formatting. The
  983. resulting string is copied into the translator's string buffer as
  984. mentioned in Section 5. The string is installed by str_install(),
  985.  
  986.  
  987.  
  988. IPD245a                      - 15 -              October 25, 1995
  989.  
  990.  
  991.  
  992.  
  993.  
  994.  
  995.  
  996.  
  997. which adds '\0' to null-terminate the string.
  998.  
  999.  
  1000. 10.__Conclusions
  1001.  
  1002.    The system described here for producing variant translators
  1003. for Icon has been used successfully to provide support for a
  1004. number of language variants and tools. These include a list scan-
  1005. ning facility [10], a animated display of pattern matching [11],
  1006. An experimental language for manipulating sequences [12,13], a
  1007. SNOBOL4-like language with a syntax similar to Icon [4], an Icon
  1008. program formatter, a tool for monitoring expression evaluation
  1009. events, and a number of simpler tools.
  1010.  
  1011.    The value of being able to construct a variant translator
  1012. quickly and easily is best illustrated by the tool for monitoring
  1013. expression evaluation events. This translator copies input to
  1014. output, inserting calls on procedures that tally expression
  1015. activations, the production of results, and expression resump-
  1016. tions. A similar system was built for Version 2 of Icon [14] and
  1017. was used to analyze the performance and behavior of generators.
  1018. In that case, the code generator and run-time system were modi-
  1019. fied extensively. This involved weeks of tedious and difficult
  1020. work that required expert knowledge of the internal structure of
  1021. the Version 2 system. The variant translator for Version 8 was
  1022. written in a few hours, and required only a knowledge of the for-
  1023. mat of variant macro specifications and the Icon source language
  1024. itself.  The monitoring of expression evaluation events in Ver-
  1025. sion 8 probably would not have been undertaken if it had been
  1026. necessary to modify the code generator and the run-time system.
  1027.  
  1028.    The usefulness of the system described here depends heavily on
  1029. its support software. The ability to specify macro definitions in
  1030. a simple format, and particularly to be able to provide a single
  1031. specification for the translation for all operators in a class,
  1032. makes it easy to write many variant translators that otherwise
  1033. would be impractically tedious.
  1034.  
  1035.    Although the system described in this report is specifically
  1036. tailored to Icon, the techniques have much broader applicability.
  1037. The automatic generation of such systems from grammatical specif-
  1038. ications is an interesting project.
  1039.  
  1040. Acknowledgements
  1041.  
  1042.    Tim Budd's Cg preprocessor was the inspiration for the Icon
  1043. variant translator system described here. Bill Mitchell assisted
  1044. in adapting the standard Icon translator to its use here.  Ken
  1045. Walker and Gregg Townsend did most of the implementation for the
  1046. current version.
  1047.  
  1048.    Tim Budd, Dave Hanson, Bill Mitchell, Janalee O'Bagy, and
  1049. Steve Wampler made a number of helpful suggestions on the variant
  1050. translator system and the presentation of the material in this
  1051.  
  1052.  
  1053.  
  1054. IPD245a                      - 16 -              October 25, 1995
  1055.  
  1056.  
  1057.  
  1058.  
  1059.  
  1060.  
  1061.  
  1062.  
  1063. report.
  1064.  
  1065. References
  1066.  
  1067.  
  1068. 1. B. W. Kernighan, ``Ratfor - A Preprocessor for a Rational
  1069.    Fortran'', Software-Practice & Experience 5(1975), 395-406.
  1070.  
  1071. 2. T. A. Budd, ``An Implementation of Generators in C'', J.
  1072.    Computer Lang. 7(1982), 69-87.
  1073.  
  1074. 3. R. E. Griswold and M. T. Griswold, The Icon Programming
  1075.    Language, Prentice-Hall, Inc., Englewood Cliffs, NJ, second
  1076.    edition, 1990.
  1077.  
  1078. 4. R. E. Griswold, Rebus - A SNOBOL4/Icon Hybrid, The Univ. of
  1079.    Arizona Tech. Rep. 84-9, 1984.
  1080.  
  1081. 5. J. L. Steffen, ``Ctrace - A Portable Debugger for C
  1082.    Programs'', UNICOM Conference Proceedings, Jan. 1983, 187-191.
  1083.    San Diego, California.
  1084.  
  1085. 6. S. C. Kendall, ``Bcc: Runtime Checking for C Programs'',
  1086.    USENIX Software Tools Summer 1983 Toronto Conference
  1087.    Proceedings, 1983, 5-16.
  1088.  
  1089. 7. M. E. Lesk and E. Schmidt, Lex - A Lexical Analyzer Generator,
  1090.    Bell Laboratories, Murray Hill, New Jersey, 1979.
  1091.  
  1092. 8. S. C. Johnson, Yacc: Yet Another Compiler-Compiler, Bell
  1093.    Laboratories, Murray Hill, New Jersey, 1978.
  1094.  
  1095. 9. R. E. Griswold and M. T. Griswold, The Implementation of the
  1096.    Icon Programming Language, Princeton University Press, 1986.
  1097.  
  1098. 10.A. J. Anderson and R. E. Griswold, Unifying List and String
  1099.    Processing in Icon, The Univ. of Arizona Tech. Rep. 83-4,
  1100.    1983.
  1101.  
  1102. 11.K. Walker and R. E. Griswold, A Pattern-Matching Laboratory;
  1103.    Part I - An Animated Display of String Pattern Matching, The
  1104.    Univ. of Arizona Tech. Rep. 86-1, 1986.
  1105.  
  1106. 12.R. E. Griswold and J. O'Bagy, Seque: A Language for
  1107.    Programming with Streams, The Univ. of Arizona Tech. Rep.
  1108.    85-2, 1985.
  1109.  
  1110. 13.R. E. Griswold and J. O'Bagy, Reference Manual for the Seque
  1111.    Programming Language, The Univ. of Arizona Tech. Rep. 85-4,
  1112.    1985.
  1113.  
  1114. 14.C. A. Coutant, R. E. Griswold and D. R. Hanson, ``Measuring
  1115.    the Performance and Behavior of Icon Programs'', IEEE Trans.
  1116.    on Software Eng. SE-9, 1 (Jan. 1983), 93-103.
  1117.  
  1118.  
  1119.  
  1120. IPD245a                      - 17 -              October 25, 1995
  1121.  
  1122.  
  1123.  
  1124.  
  1125.  
  1126.  
  1127.  
  1128.  
  1129.  
  1130.  
  1131.  
  1132.  
  1133.  
  1134.  
  1135.  
  1136.  
  1137.  
  1138.  
  1139.  
  1140.  
  1141.  
  1142.  
  1143.  
  1144.  
  1145.  
  1146.  
  1147.  
  1148.  
  1149.  
  1150.  
  1151.  
  1152.  
  1153.  
  1154.  
  1155.  
  1156.  
  1157.  
  1158.  
  1159.  
  1160.  
  1161.  
  1162.  
  1163.  
  1164.  
  1165.  
  1166.  
  1167.  
  1168.  
  1169.  
  1170.  
  1171.  
  1172.  
  1173.  
  1174.  
  1175.  
  1176.  
  1177.  
  1178.  
  1179.  
  1180.  
  1181.  
  1182.  
  1183.  
  1184.  
  1185.  
  1186. IPD245a                      - 18 -              October 25, 1995
  1187.  
  1188.  
  1189.