home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / compcomp / yacc / y2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-17  |  49.3 KB  |  1,625 lines

  1. /************************************************************************/
  2. /*                              y2.c                                    */  
  3. /*  YACC source file #2 (of 4).                                         */  
  4. /*  Scanner, parser and symbol table code.                */
  5. /************************************************************************/   
  6.     
  7. /************************************************************************/   
  8. /*                              contents                                */    
  9. /*                                                                      */    
  10. /*  * y2CpyAction       Copy C action to the next ; or closing }        */ 
  11. /*  * y2CpyCode         Copy code between %{ and %} to output.          */ 
  12. /*  * y2CpyUnion        Copy a union declaration to output.             */ 
  13. /*  * y2Define          Define s to be a terminal or nonterminal.       */ 
  14. /*  * y2EnterSymbol     Store id or literal in y2Text[], return address.*/ 
  15. /*  * y2FindName        Identify terminal/nonterminal.                  */ 
  16. /*  * y2GetToken                                                        */ 
  17. /*    y2Initialize      Initialize parser, then call y2yyParse.         */ 
  18. /*  * y2SkipComment     Skip over comments.                             */ 
  19. /*  * y2TypeOf          Determine the type of a symbol.                 */ 
  20. /*  * y2Usage                                                           */ 
  21. /*  * y2WriteDefines    Post declarations: write out the defines        */ 
  22. /*    y2yyParse         Kludged YACC input parser.                      */ 
  23. /*                                                                      */ 
  24. /* * Local to this file.                                                */  
  25. /*                                                                      */ 
  26. /************************************************************************/ 
  27.     
  28.     
  29. /************************************************************************/ 
  30. /*                              history                                 */ 
  31. /*                                                                      */ 
  32. /* 85Nov22 CrT  Below fouled up YYACCEPT/YYERROR.  Fixed.               */ 
  33. /* 85Nov18 CrT    User action chunks are now placed in functions rather    */
  34. /*        than switch cases.  The functions are accessed by an    */
  35. /*              array of function pointers.  This is because many       */ 
  36. /*              compilers have low limits on the size of functions,     */ 
  37. /*              switch statements, and the number of cases in a         */ 
  38. /*              switch statement.  In addition, some compilers implement*/ 
  39. /*              switch statements with a cascade of comparisons rather  */ 
  40. /*              than a jump table.                                      */ 
  41. /* 85Nov17 CrT  I had a } wrong in y2Define.  Fixed.                    */ 
  42. /* 85Nov17 CrT  Changed 'begin:' to 'start:' in y2GetToken, because     */ 
  43. /*              BDS C treats 'begin's as '{'s, with confusing results.  */ 
  44. /*              (This problem reported by Robert A. McIvor in '79.)     */ 
  45. /* 85Nov15 CrT  Global variable names decrypted.                        */ 
  46. /* 85Nov13 CrT  Give plaintiff routine in error messages.               */ 
  47. /* 85Nov12 CrT  Function names decrypted. Still unique in first 6 chars.*/ 
  48. /* 85Nov10 CrT  y2.c reconstructed from 12 subfiles.  Cosmetics.        */ 
  49. /* 83Dec23 SG   Adapted for IBM PC/XT & DeSmet C compiler               */ 
  50. /* 83May15 SG   Fixed up option flag handling for RT-11.                */ 
  51. /* 83Apr12 RBD  Make filename[] size per #define'd                      */ 
  52. /*              FNAMESIZE so VAX filenames won't blow out.              */ 
  53. /*              Conditionalize time handling for banner.                */ 
  54. /*              Make filespec buffer static for safety,                 */ 
  55. /*              since global "infile" is pointed to it.                 */ 
  56. /* 82Mar22 RBD  Added header line, changes for 'new' DECUS library      */ 
  57. /*                                                                      */ 
  58. /* 81Aug27 RBD  Modified for use with DECUS LEX                         */ 
  59. /*              Variable "yylval" resides in yylex(), not in yypars();  */ 
  60. /*              Therefore, is defined "extern" here.                    */ 
  61. /*                                                                      */ 
  62. /*              Also, the command line processing for the Decus version */ 
  63. /*              has been changed.  A new switch has been added to allow */ 
  64. /*              specification of the "table" file name(s), and unused   */ 
  65. /*              switch processing removed.                              */ 
  66. /*                               NOTE                                   */ 
  67. /*              This probably won't run on UNIX any more.               */ 
  68. /*                                                                      */ 
  69. /* 7?????? SCJ  Created.                                                */ 
  70. /*                                                                      */ 
  71. /*                              credits                                 */ 
  72. /*      CrT=CrT                                                         */  
  73. /*      RBD=Bob Denny                                                   */  
  74. /*      SCJ=Steven C Johnson.                                           */  
  75. /*      SG =Scott Guthery                                               */  
  76. /************************************************************************/ 
  77.  
  78.   
  79. #include <stdio.h>
  80. #include "system.h"
  81. #include "dtxtrn.h"
  82.  
  83.  
  84.  
  85.  
  86. /* Token types returned by yacc's input scanner: */
  87. # define IDENTIFIER   257  /* Identifier NOT followed by colo.        */
  88. # define MARK          258  /* %%                    */
  89. # define TERMINAL     259  /* %0 or %term or %token            */
  90. # define LEFT          260  /* %< or %left                */
  91. # define RIGHT          261  /* %> or %right                */
  92. # define BINARY       262  /* %2 or %binary or %nonassoc        */
  93. # define PREC          263  /* %= or %prec                */
  94. # define LCURLY       264  /* %{                    */
  95. # define C_IDENTIFIER 265  /* An IDENTIFIER followed by a colon.    */
  96. # define NUMBER       266  /* A number                    */
  97. # define START          267  /* %start                    */
  98. # define TYPEDEF      268  /* %type                    */
  99. # define TYPENAME     269  /*                        */
  100. # define UNION          270  /* %union                    */
  101. # define ENDFILE    0  /*                        */
  102.                           
  103.  
  104. /* Arguments for y2Define: */
  105. #define TYPEtERMINAL    0
  106. #define TYPEnONTERMINAL 1
  107. #define TYPEpREC    2
  108.  
  109.  
  110.  
  111. /* Communication variables between various I/O routines: */
  112.                                                           
  113. static int   y2InputNumberValue;        /* Value of an input number. */
  114. static char  y2InputTokenText[ NAMEsIZE ];  /* Input token name.     */
  115.                                                           
  116.  
  117.  
  118. /* Storage for names: */
  119.                                                           
  120. static char  y2Text[ MAXy2TEXT ];   /* Contains text of all names.     */
  121. static char *y2TextFree = y2Text;   /* Remaining free space in y2Text[]. */
  122. static int   y2NumberOfDefinedSymbolsWritten = 3;
  123.  
  124.  
  125.  
  126. /* Storage for user-declared types ("<...>" commands): */
  127.  
  128. /* Pointers to names of types, secreted in y2Text: */
  129. static char *  y2TypeName[ MAXtYPES ];
  130.  
  131. static int     y2NumberOfTypesDefined;
  132.  
  133.  
  134.  
  135. /* Symbol tables for tokens and nonterminals: */
  136.                                                           
  137. /* Table giving external name and internal number for each terminal: */
  138. struct toksymb y2Terminal[         MAXtERMINALsTATES ];
  139.  
  140. /* Bit vectors giving associativity and precedence of each terminal: */
  141. int           y2TerminalProperties[ MAXtERMINALsTATES ];
  142. int y2NextTerminal = 0;
  143.  
  144. /* Table giving external name and internal number for nonterminals: */
  145. struct ntsymb y2NonterminalState[ MAXnONTERMINALsTATES ];
  146. int y2LastNonterminal = -1;
  147.  
  148. static int y2RootNonterminal;    /* "%start" symbol.             */
  149.                                                           
  150.  
  151.  
  152. /* Next internal terminal number to assign: */
  153. static int y2NextTerminalNumber = 0;    /* y2Initialize sets it to 0400 */
  154.                                                           
  155.  
  156.  
  157. /* Input and output file descriptors: */
  158.                                                           
  159. FILE * y2InputFD;        /* Yacc input file.            */
  160. FILE * y2ActionFD;        /* File to saving actions in.        */
  161. FILE * y2DefineFD;        /* File for # defines.            */
  162. FILE * y2ytabcFD;        /* y.tab.c file.            */
  163. FILE * y2TempFileFD;        /* Temp. file to pass 2.        */
  164. FILE * y2OutputFD;        /* y.output file.            */
  165.                                                           
  166.  
  167.  
  168. /************************************************************************/
  169. /*                                                                      */
  170. /* Storage for grammar rules. Grammar rules are packed sequentially    */
  171. /* into y2Pool[].   y2Production[i] points to the start of the ith    */
  172. /* grammar rule.  A grammar rule consists of a sequence of positive    */
  173. /* integers terminated by a negative integer.  The positive integers    */
  174. /* are parts of the rule, the negative integer is -i.  Positive     */
  175. /* integers less than FIRSTnONTERMINAL are terminals, others are    */
  176. /* nonterminals -- subtracting FIRSTnONTERMINAL gives the correct    */
  177. /* offset into y2NonterminalState[].   The first entry in the rule is    */
  178. /* the LHS -- the nonterminal being defined -- and the remainder give    */
  179. /* the right hand side.                         */
  180. /*                                                                      */
  181. /* Actions are always fired at the end of a rule.  (Input rules with    */
  182. /* actions in the middle are split into multiple rules.)  When actions    */
  183. /* are encountered, a switch case labeled with the rule number is    */
  184. /* generated, and the RULEhASaCTION bit for that rule set.  Thus, when    */
  185. /* we later generate code reducing this rule, we need only check the    */
  186. /* RULEhASaCTION and, if set, synthesize a call from the rule number.    */
  187. /*                                    */
  188. /************************************************************************/
  189.  
  190. /* Buffer to pack productions into: */
  191. int y2Pool[ MAXy2POOL ];
  192.  
  193. /* Pointer to start of free space in y2Pool: */
  194. int *y2FreePool = y2Pool;
  195.  
  196. /* Count of number of productions in currently in y2Pool: */
  197. int y2ThisProduction= 1;
  198.  
  199. /* Pointers into y2Pool, giving the start of each production in it: */
  200. int *y2Production[ MAXpRODUCTIONS ];
  201.  
  202. /* The production precedence levels.  Same bit    */
  203. /* vector format as y2TerminalProperties:    */
  204. int y2ProductionProperties[ MAXpRODUCTIONS ] ;
  205.  
  206.  
  207.  
  208.  
  209.  
  210.  
  211.  
  212.  
  213. /************************************************************************/
  214. /*    y2CpyAction       Copy C action to the next ; or closing }        */
  215. /************************************************************************/
  216. static y2CpyAction( offset )           /* Called only from y2yyParse */
  217. int offset;              /* Number of arguments seen in production */
  218. {
  219.     int braceDepth, c, match, j, s, tok;
  220.        
  221. #ifdef OLD
  222.     /* Create a "case...:" for the impending action: */
  223.     fprintf( y2ActionFD, "\ncase %d:", y2ThisProduction );
  224. #else 
  225.     /* Create a function for the impending action: */
  226.     fprintf( y2ActionFD, "static yyA%03d() {", y2ThisProduction );
  227. #endif 
  228.     /* Pass current line number to output: */
  229.     fprintf(   y2ActionFD,   "\n# line %d\n",    y1LineNumber   );
  230.        
  231.     braceDepth = 0;
  232.        
  233. lup:
  234.     c = y1GetChar( y2InputFD );
  235.  
  236. swtch:
  237.     switch( c ) {
  238.        
  239.     case ';':
  240.     if (braceDepth == 0) {
  241.         putc( c , y2ActionFD );
  242.         goto cpyActEnd;
  243.          } 
  244.      goto lcopy;
  245.        
  246.     case '{':
  247.     braceDepth++;
  248.     goto lcopy;
  249.        
  250.     case '$':
  251.     s   = 1;
  252.     tok = -1;
  253.     c   = y1GetChar( y2InputFD );
  254.  
  255.         if (c == '<') {
  256.  
  257.             /* Type description: */
  258.         y1UngetChar( c, y2InputFD );
  259.         if (y2GetToken() != TYPENAME) {
  260.         y1Error( "y2CpyAction: Bad syntax on $<ident> clause" );
  261.         }
  262.         tok = y2InputNumberValue;
  263.         c    = y1GetChar( y2InputFD );
  264.     }
  265.     if (c == '$') {
  266.         fprintf( y2ActionFD, "yyval");
  267.         if (y2NumberOfTypesDefined) {
  268.  
  269.         /* Put out the proper name: */
  270.         if (tok < 0) {
  271.             tok = y2TypeOf( *y2Production[ y2ThisProduction ] );
  272.         }
  273.                 fprintf( y2ActionFD, ".%s", y2TypeName[tok] );
  274.             } 
  275.         goto lup;
  276.     }
  277.     if (c == '-') {
  278.         s = -s;
  279.         c = y1GetChar( y2InputFD );
  280.     }
  281.     if (isdigit( c )) {
  282.  
  283.         /* Handle a $3 type action argument: */
  284.  
  285.         /* Collect the numerical value in j: */
  286.             j = 0;
  287.         while (isdigit( c )) {
  288.         j = j * 10   +     c - '0';
  289.         c = y1GetChar( y2InputFD );
  290.             } 
  291.         j = j * s    -   offset;
  292.  
  293.         /* Can't refer to part of rule not seen yet: */
  294.             if (j > 0)  y1Error( "y2CpyAction: Illegal use of $%d", j+offset );
  295.  
  296.         /* Compile code for $n variable reference: */
  297.             fprintf( y2ActionFD, "yypvt[-%d]", -j );
  298.  
  299.         /* Special code if we are stacking unions instead of ints: */
  300.             if (y2NumberOfTypesDefined) {
  301.  
  302.         /* Put out the proper name: */
  303.  
  304.         if (j+offset <= 0   &&     tok < 0) {
  305.             y1Error(
  306.             "y2CpyAction: Must specify type of $%d",
  307.             j+offset
  308.             );
  309.         }
  310.         if (tok < 0)   {
  311.             tok = y2TypeOf(
  312.             y2Production[ y2ThisProduction ][ j+offset ]
  313.             );
  314.                 }
  315.                 fprintf( y2ActionFD, ".%s", y2TypeName[tok] );
  316.         }
  317.         goto swtch;
  318.     }
  319.     putc( '$' , y2ActionFD );
  320.     if (s < 0)   putc( '-', y2ActionFD );
  321.     goto swtch;
  322.        
  323.     case '}':
  324.     if (--braceDepth)   goto lcopy;
  325.     putc( c, y2ActionFD );
  326.     goto cpyActEnd;
  327.  
  328.     case '/':
  329.     /* Look for comments: */
  330.     putc( c , y2ActionFD );
  331.     c = y1GetChar( y2InputFD );
  332.     if (c != '*')    goto swtch;
  333.        
  334.     /* It really is a comment: */
  335.        
  336.     putc( c , y2ActionFD );
  337.     c = y1GetChar( y2InputFD );
  338.     while (c != EOF) {
  339.         while (c == '*') {
  340.         putc( c , y2ActionFD );
  341.         if ((c = y1GetChar( y2InputFD ))   ==    '/')   goto lcopy;
  342.             } 
  343.         putc( c , y2ActionFD );
  344.         if (c == '\n')   ++y1LineNumber;
  345.         c = y1GetChar( y2InputFD );
  346.     }
  347.     y1Error( "y2CpyAction: EOF inside comment" );
  348.        
  349.     case '\'':
  350.     /* Character constant: */
  351.     match = '\'';
  352.     goto string;
  353.        
  354.     case '"':
  355.     /* Character string: */
  356.     match = '"';
  357.        
  358. string: 
  359.        
  360.     putc( c, y2ActionFD );
  361.     while (c = y1GetChar( y2InputFD )) {
  362.         if (c == '\\') {
  363.         putc( c , y2ActionFD );
  364.         c = y1GetChar(y2InputFD);
  365.         if (c == '\n')     ++y1LineNumber;
  366.         } else if( c==match ) {
  367.         goto lcopy;
  368.         } else if( c=='\n' ) {
  369.         y1Error( "y2CpyAction: Newline in string or char constant" );
  370.         }
  371.         putc( c , y2ActionFD );
  372.     }
  373.     y1Error( "y2CpyAction: EOF in string or character constant" );
  374.        
  375.     case EOF:
  376.     /* EOF: */
  377.     y1Error( "y2CpyAction: Action does not terminate" );
  378.        
  379.     case '\n':
  380.     ++y1LineNumber;
  381.     goto lcopy;
  382.     }
  383.        
  384. lcopy: 
  385.     putc( c, y2ActionFD );
  386.     goto lup;
  387.  
  388.  
  389. cpyActEnd:
  390. #ifdef OLD
  391.     /* Wrap up this "case" in the action switch statement: */
  392.     fprintf( y2ActionFD, " break;" ); 
  393. #else
  394.     /* Wrap up this action fn: */
  395.     fprintf( y2ActionFD, "\n    return -1;\n}\n\n" );
  396. #endif
  397. }
  398.  
  399.  
  400. /************************************************************************/
  401. /*    y2CpyCode         Copy code between \{ and \} to output.          */ 
  402. /************************************************************************/ 
  403. static y2CpyCode() {
  404.  
  405.     int c; 
  406.  
  407.     c = y1GetChar( y2InputFD );
  408.  
  409.     if (c == '\n') { 
  410.     c = y1GetChar( y2InputFD );
  411.     y1LineNumber++;
  412.     } 
  413.  
  414.     /* Pass line number to output file: */
  415.     fprintf( y2ytabcFD, "\n# line %d\n", y1LineNumber );
  416.  
  417.     /* Copy the code over: */
  418.     while (c != EOF) {
  419.         if (c == '\\') { 
  420.         if ((c = y1GetChar(y2InputFD))   ==   '}')     return;
  421.         else                      putc('\\', y2ytabcFD );
  422.         } 
  423.         if (c == '%') { 
  424.         if ((c = y1GetChar(y2InputFD))   ==   '}')     return;
  425.         else                      putc('%', y2ytabcFD );
  426.         } 
  427.     putc( c , y2ytabcFD );
  428.     if (c == '\n')     ++y1LineNumber;
  429.     c = y1GetChar(y2InputFD);
  430.     } 
  431.     y1Error( "y2CpyCode: EOF before %%}" );
  432. }
  433.   
  434.  
  435. /************************************************************************/
  436. /*    y2CpyUnion        Copy a union declaration to output.             */
  437. /************************************************************************/
  438. static y2CpyUnion() {           /* Called only from y2yyParse */
  439.  
  440.     /**********************************************/
  441.     /* Copy the union declaration to the output.  */
  442.     /* Copy also to the .h file if one requested. */
  443.     /**********************************************/
  444.  
  445.     int level, c;
  446.  
  447.     /* Pass input line number to output for debugging purposes: */
  448.     fprintf( y2ytabcFD, "\n# line %d\n", y1LineNumber );
  449.  
  450.     fprintf( y2ytabcFD, "\n#define UNION 1\n");
  451.     fprintf( y2ytabcFD, "typedef union " );
  452.     if (y2DefineFD)   fprintf( y2DefineFD, "\ntypedef union " );
  453.        
  454.     level = 0;
  455.     loop {
  456.     if ((c = y1GetChar( y2InputFD ))   ==    EOF) {
  457.         y1Error( "y2CpyUnion: EOF encountered while processing %%union" );
  458.     }
  459.     putc( c, y2ytabcFD );
  460.     if (y2DefineFD)   putc( c, y2DefineFD );
  461.        
  462.     switch (c) {
  463.     case '\n':    ++y1LineNumber;             break;
  464.     case '{':    ++level;                break;
  465.     case '}':
  466.         if (!--level) {
  467.  
  468.         /* We are finished copying: */
  469.         fprintf( y2ytabcFD, " YYSTYPE;\n" );
  470.         if (y2DefineFD) {
  471.             fprintf(
  472.             y2DefineFD,
  473.             " YYSTYPE;\nextern YYSTYPE yylval;\n"
  474.             );
  475.         }
  476.         return;
  477.         }
  478.     }
  479.     }
  480. }
  481.  
  482.  
  483. /************************************************************************/
  484. /*    y2Define          Define s to be a terminal or nonterminal.       */ 
  485. /************************************************************************/ 
  486. y2Define( t, s )    /* Called by y2FindName and y2Initialize */
  487. int             t; 
  488. register char  *s; 
  489.     /*****************************************************/ 
  490.     /* Define s to be a    terminal if t=TYPEtERMINAL     */
  491.     /*           or a nonterminal if t=TYPEnONTERMINAL */
  492.     /*           or a (???--CrT)     t=TYPEpREC     */
  493.     /*****************************************************/ 
  494.  
  495.     register val; 
  496.            
  497.     if (t != TYPEtERMINAL) {
  498.     if (++y2LastNonterminal >= MAXnONTERMINALsTATES) {
  499.         y1Error(
  500.         "y2Define  Too many nonterminals, limit %d",
  501.         MAXnONTERMINALsTATES
  502.         );
  503.         } 
  504.     y2NonterminalState[ y2LastNonterminal ].name = y2EnterSymbol(s);
  505.  
  506.     return( FIRSTnONTERMINAL + y2LastNonterminal );
  507.     }
  508.  
  509.     /* Must be a terminal */
  510.     if (++y2NextTerminal >= MAXtERMINALsTATES)     {
  511.     y1Error( "y2Define: Too many terminals, limit %d",MAXtERMINALsTATES);
  512.     }
  513.     y2Terminal[ y2NextTerminal ].name  = y2EnterSymbol(s);
  514.            
  515.     /* Establish value for token: */ 
  516.            
  517.     if (s[0] == ' '   &&   s[2] == '\0') { 
  518.   
  519.         /* Single character literal: */ 
  520.         val = s[1]; 
  521.   
  522.     } else if (s[0] != ' '   ||   s[1] != '\\') {
  523.  
  524.         val = y2NextTerminalNumber++;
  525.  
  526.     } else {
  527.  
  528.         /* Escape sequence: */ 
  529.         if (s[3] == '\0' ) { 
  530.   
  531.             /* Single character escape sequence: */ 
  532.             switch ( s[2] ) { 
  533.                 /* Character which is escaped: */ 
  534.             case  'n':      val = '\n';             break; 
  535.             case  'r':      val = '\r';             break; 
  536.             case  'b':      val = '\b';             break; 
  537.             case  't':      val = '\t';             break; 
  538.             case  'f':      val = '\f';             break; 
  539.             case '\'':      val = '\'';             break; 
  540.             case  '"':      val =  '"';             break; 
  541.             case '\\':      val = '\\';             break; 
  542.             default: 
  543.         y1Error( "y2Define: Invalid escape" );
  544.             }  
  545.   
  546.         } else if (s[2] <= '7'   &&   s[2] >= '0') { 
  547.   
  548.             /* \nnn sequence: */ 
  549.             if ( 
  550.                 s[3] < '0' 
  551.                 || 
  552.                 s[3] > '7' 
  553.                 || 
  554.                 s[4] < '0' 
  555.                 || 
  556.                 s[4] > '7' 
  557.                 || 
  558.                 s[5] != '\0' 
  559.             ) { 
  560.         y1Error( "y2Define Illegal \\nnn construction" );
  561.             } 
  562.   
  563.             /****************************************************************/ 
  564.         /* CrT: Naive code to translate \nnn to octal char is:        */
  565.             /* val = 64 * (s[2]-'0')   +   8 * (s[3]-'0')   +   (s[4]-'0'); */ 
  566.             /* Factoring the '0's out for speed (?!?!!??) gives SCJ's:      */ 
  567.             /****************************************************************/ 
  568.         val = 64 * s[2]   +   8 * s[3]   +     s[4]    -   73 * '0';
  569.         if (val == 0)   y1Error( "y2Define: '\\000' is illegal" );
  570.         } 
  571.     }
  572.     y2Terminal[ y2NextTerminal ].value        = val;
  573.     y2TerminalProperties[ y2NextTerminal ]  = 0;
  574.  
  575.     return   y2NextTerminal;
  576.   
  577.  
  578. /************************************************************************/
  579. /*    y2EnterSymbol     Store id or literal in y2Text[], return address.*/
  580. /************************************************************************/
  581. static char *y2EnterSymbol( s )    /* Called by y2Define and y2GetToken */
  582. register char *s;
  583. {
  584.     char *temp;
  585.           
  586.     temp = y2TextFree;
  587.     do {
  588.     if (y2TextFree >= &y2Text[ MAXy2TEXT ]) {
  589.  
  590.             y1Error( "y2EnterSymbol: Too many chars in id's and literals" );
  591.  
  592.         } else {
  593.  
  594.             *y2TextFree++ = *s;
  595.  
  596.         }
  597.     } while (*s++);
  598.  
  599.     return  temp;
  600. }
  601.  
  602.  
  603. /************************************************************************/
  604. /*      y2FindName                                                      */ 
  605. /************************************************************************/ 
  606. static y2FindName( t, s )        /* Called only from y2yyParse    */
  607. int           t;    /* TYPEtERMINAL, TYPEnONTERMINAL or TYPEpREC.    */
  608. register char *s; 
  609.     int i; 
  610.            
  611.     /* Handle literals: */
  612.     if (s[0] == ' ')   t = TYPEtERMINAL;
  613.   
  614.     /* May be a terminal: */
  615.     FORaLLtERMINALS(i) {
  616.     if (!strcmp( s, y2Terminal[i].name ))    return i;
  617.     } 
  618.  
  619.     /* May be a nonterminal: */
  620.     FORaLLnONTERMINALS(i) {
  621.     if (!strcmp( s, y2NonterminalState[i].name )) {
  622.         return i+FIRSTnONTERMINAL;
  623.     }
  624.     } 
  625.  
  626.     /* Identifiers in "%prec id" statements should be predeclared: */
  627.     if (t == TYPEpREC) {
  628.     y1Error( "y2FindName: %s should have been defined earlier", s );
  629.     }
  630.   
  631.     /* Create an entry for undefined name: */
  632.     return   y2Define( t, s );
  633.   
  634.  
  635. /************************************************************************/
  636. /*    y2GetToken                            */
  637. /************************************************************************/
  638. static y2GetToken() {        /* Called from y2yyParse, y2CpyAction    */
  639.  
  640.     static int  peekline;
  641.  
  642.     register    len;
  643.     register    base;
  644.     register    c;
  645.  
  646.     int         match;
  647.     int     percentCommand;
  648.     int     i;
  649.  
  650. start:
  651.     percentCommand  = FALSE;
  652.     y1LineNumber   += peekline;
  653.     peekline        = 0;
  654.     c            = y1GetChar( y2InputFD );
  655.  
  656.     /* Skip any leading whitespace: */
  657.     while (
  658.     c == ' '
  659.     ||
  660.     c == '\n'
  661.     ||
  662.     c == '\t'
  663.     ||
  664.     c == '\f'
  665.     ||
  666.     c == '\r'
  667.     ) {
  668.     if (c == '\n')     ++y1LineNumber;
  669.     c = y1GetChar( y2InputFD );
  670.     }
  671.  
  672.     /* Skip comments: */
  673.     if (c == '/') {
  674.     /* Skip comment: */
  675.     y1LineNumber += y2SkipComment();
  676.     goto start;
  677.     }
  678.           
  679.     /* We have nonwhitespace noncomment: decide what kind of token: */
  680.     switch (c) {
  681.  
  682.     case EOF:
  683.     /* EOF: */
  684.     return     ENDFILE;
  685.  
  686.     case '{':
  687.     /* Action: */
  688.     y1UngetChar( c, y2InputFD );
  689.     return( '=' );
  690.  
  691.      case '<':
  692.     /* Get, and look up, a type name (union member name): */
  693.     len = 0;
  694.     while (
  695.         (c = y1GetChar( y2InputFD ))   !=    '>'
  696.         &&
  697.         c >= 0
  698.         &&
  699.         c != '\n'
  700.     ) {
  701.         y2InputTokenText[ i ] = c;
  702.  
  703.         /* Truncate too-long type names: */
  704.             if (++len >= NAMEsIZE)   --len;
  705.     }
  706.  
  707.     /* Check for '>' missing: */
  708.         if (c != '>')   y1Error( "y2GetToken: Unterminated < ... > clause" );
  709.  
  710.     /* Tie off name: */
  711.         y2InputTokenText[ len ] = '\0';
  712.  
  713.     /* If typename already entered, don't enter it again: */
  714.         for (i = 1;   i <= y2NumberOfTypesDefined;   ++i) {
  715.         if (!strcmp( y2TypeName[i], y2InputTokenText )) {
  716.         y2InputNumberValue = i;
  717.         return( TYPENAME );
  718.             } 
  719.     }
  720.  
  721.     /* Enter typename: */
  722.     y2TypeName[ y2InputNumberValue = ++y2NumberOfTypesDefined ]   = (
  723.         y2EnterSymbol( y2InputTokenText )
  724.     );
  725.  
  726.         return   TYPENAME;
  727.  
  728.     case '"':
  729.     case '\'':
  730.     match            = c;
  731.     y2InputTokenText[0] = ' ';
  732.     len            = 1;
  733.     loop {
  734.  
  735.         c = y1GetChar( y2InputFD );
  736.  
  737.             if (c == '\n'   ||   c == EOF) {
  738.         y1Error( "y2GetToken: Illegal or missing ' or \"" );
  739.         }
  740.         if (c == '\\') {
  741.  
  742.         c = y1GetChar( y2InputFD );
  743.         y2InputTokenText[i] = '\\';
  744.         if( ++len >= NAMEsIZE ) --len;
  745.  
  746.         } else if( c == match ) {
  747.  
  748.                 break;
  749.  
  750.             }
  751.         y2InputTokenText[len] = c;
  752.         if (++len >= NAMEsIZE )   --len;
  753.     }
  754.     break;
  755.           
  756.     case '%':
  757.     case '\\':
  758.           
  759.     switch (c = y1GetChar( y2InputFD ))  {
  760.  
  761.         case '%':
  762.     case '\\':    return     MARK     ;
  763.     case '0':    return     TERMINAL;
  764.     case '<':    return     LEFT     ;
  765.     case '2':    return     BINARY  ;
  766.     case '>':    return     RIGHT     ;
  767.     case '=':    return     PREC     ;
  768.     case '{':    return     LCURLY  ;
  769.     default:
  770.         percentCommand = TRUE;
  771.     }
  772.           
  773.     default:
  774.           
  775.     if (isdigit( c )) {
  776.  
  777.             /* Number: */
  778.         y2InputNumberValue    = c - '0';
  779.         base        =   (c == '0')     ?   8     :   10;
  780.  
  781.         for (
  782.         c = y1GetChar( y2InputFD );
  783.         isdigit( c );
  784.         c = y1GetChar( y2InputFD )
  785.         ) {
  786.         y2InputNumberValue = y2InputNumberValue * base     +   (c - '0');
  787.             } 
  788.         y1UngetChar( c, y2InputFD );
  789.         return   NUMBER;
  790.  
  791.         } else if (
  792.  
  793.             !islower( c )
  794.         &&
  795.         !isupper( c )
  796.         &&
  797.         c != '_'
  798.         &&
  799.         c != '.'
  800.         &&
  801.         c != '$'
  802.  
  803.         ) {
  804.  
  805.             return   c;
  806.  
  807.         } else {
  808.  
  809.             len = 0;
  810.  
  811.             while (
  812.         islower( c )
  813.         ||
  814.         isupper( c )
  815.         ||
  816.         isdigit( c )
  817.         ||
  818.         c == '_'
  819.         ||
  820.         c == '.'
  821.         ||
  822.         c == '$'
  823.         ) {
  824.         if (percentCommand && isupper(c)) {
  825.             c  +=  'a' - 'A';
  826.         }
  827.                 y2InputTokenText[ len ] = c;
  828.         if (++len >= NAMEsIZE)     --len;
  829.         c = y1GetChar( y2InputFD );
  830.             } 
  831.     }
  832.  
  833.     y1UngetChar( c, y2InputFD );
  834.     }
  835.           
  836.     y2InputTokenText[ len ] = '\0';
  837.           
  838.     if (percentCommand) {
  839.     /* Find a reserved word: */
  840.     if (!strcmp(y2InputTokenText,"term"    ))   return( TERMINAL );
  841.     if (!strcmp(y2InputTokenText,"token"   ))   return( TERMINAL );
  842.     if (!strcmp(y2InputTokenText,"left"    ))   return( LEFT     );
  843.     if (!strcmp(y2InputTokenText,"nonassoc"))   return( BINARY   );
  844.     if (!strcmp(y2InputTokenText,"binary"  ))   return( BINARY   );
  845.     if (!strcmp(y2InputTokenText,"right"   ))   return( RIGHT    );
  846.     if (!strcmp(y2InputTokenText,"prec"    ))   return( PREC     );
  847.     if (!strcmp(y2InputTokenText,"start"   ))   return( START    );
  848.     if (!strcmp(y2InputTokenText,"type"    ))   return( TYPEDEF  );
  849.     if (!strcmp(y2InputTokenText,"union"   ))   return( UNION    );
  850.  
  851.     y1Error(
  852.         "y2GetToken: Invalid escape, or illegal reserved word: %s",
  853.         y2InputTokenText
  854.     );
  855.     }
  856.           
  857.     /* Look ahead to distinguish IDENTIFIER from C_IDENTIFIER: */
  858.           
  859.     c = y1GetChar( y2InputFD );
  860.     while (
  861.     c == ' '
  862.     ||
  863.     c == '\t'
  864.     ||
  865.     c == '\n'
  866.     ||
  867.     c == '\f'
  868.     ||
  869.     c == '/'
  870.     ) {
  871.     if( c == '\n' ) {
  872.         ++peekline;
  873.     } else if( c == '/' ) {
  874.         /* Look for comments: */
  875.         peekline += y2SkipComment();
  876.     }
  877.     c = y1GetChar( y2InputFD );
  878.     }
  879.  
  880.     if (c == ':')   return C_IDENTIFIER;
  881.  
  882.     y1UngetChar( c, y2InputFD );
  883.  
  884.     return   IDENTIFIER;
  885. }
  886.  
  887.  
  888. /************************************************************************/
  889. /*    y2Initialize                            */
  890. /************************************************************************/
  891. y2Initialize( argc, argv )    /* Called once from main at startup    */
  892. int   argc; 
  893. char *argv[];  
  894.     char filename[    FNAMESIZE ];
  895.     char inputFilename[ FNAMESIZE ];
  896.     char *cp;
  897.     int  i;
  898.     int  makeHFile;
  899.     int  makeIFile;
  900.  
  901.     makeHFile    = FALSE;
  902.     makeIFile    = FALSE;
  903.  
  904.     y2OutputFD    = NULL;
  905.     y2DefineFD    = NULL;
  906.  
  907.     /* Handle all commandline switches: */
  908.     for (i = 1;   --argc   &&   argv[i][0] == '-';   i++) {
  909.  
  910.         while (*++(argv[i])) { 
  911.             switch( toupper( *argv[i] )) { 
  912.         case 'I':            makeIFile++;    continue;
  913.         case 'H':            makeHFile++;    continue;
  914.             default: 
  915.         fprintf(stderr, "y2Initialize: Bad option: %c\n", *argv[i]);
  916.                 y2Usage(); 
  917.             }  
  918.         } 
  919.     }
  920.            
  921.     /* Catch no filename given: */
  922.     if (!argc)     y2Usage();
  923.   
  924.     /************************************************************************/ 
  925.     /* Now open the input file with a default extension of ".Y",            */ 
  926.     /* then replace the period in argv[1] with a null, so argv[1]           */ 
  927.     /* can be used to form the table, defs and info filenames.              */ 
  928.     /************************************************************************/ 
  929.            
  930.     /* Find the input filename: */
  931.     cp = argv[i]; 
  932.   
  933.     /* Scan past '.' or to null: */ 
  934.     while (*cp++ != '.'   &&   *cp);
  935.   
  936.     /* Make our own copy: */
  937.     strcpy( filename, argv[i] );
  938.  
  939.     /* Make sure "filename" copy has ".Y" extention    */
  940.     /* and       , argv[] copy has   no extention:    */
  941.     if (!*cp)    strcat( filename, ".Y"    );   /* Add default ".y" */
  942.     else     *(argv[i]-1) = '\0';        /* Null the period: */
  943.  
  944.     /* Open the xxx.y input file: */
  945.     strcpy( inputFilename, filename );
  946.     if ((y2InputFD = fopen( filename, "r" ))   ==   NULL) {
  947.     y1Error( "y2Initialize: Cannot open input file \"%s\"", filename );
  948.     } 
  949.   
  950.     /* If -h option specified, create a xxx.h file to #define the tokens: */
  951.     if (makeHFile) {
  952.     strcpy( filename, argv[i] );
  953.     strcat( filename, ".H"      );
  954.   
  955.     if ((y2DefineFD = fopen( filename, "w" ))   ==     NULL)     {
  956.         y1Error( "y2Initialize: Cannot open defs file\"%s\"", filename);
  957.     }
  958.     } 
  959.            
  960.     /* If -i option specified, create a xxx.i file to hold the    */
  961.     /* human-readable description of the parser:        */
  962.     if (makeIFile) {
  963.     strcpy( filename, argv[i] );
  964.     strcat( filename, ".I"      );
  965.   
  966.     if ((y2OutputFD = fopen( filename, "w" ))   ==     NULL)     {
  967.         y1Error( "y2Initialize: Cannot open info file\"%s\"", filename);
  968.     }
  969.     } 
  970.   
  971.     /* Create the xxx.c file containing the parser proper: */
  972.     strcpy( filename, argv[i] );
  973.     strcat( filename, ".C"    );
  974.   
  975.     if ((y2ytabcFD = fopen(filename, "w"))   ==   NULL)   {
  976.     y1Error( "y2Initialize: Cannot open table file\"%s\"", filename);
  977.     }
  978.   
  979.     /* Open a temporary(?) file for gotos: */
  980.     if ((y2TempFileFD = fopen( TEMPNAME, "w" ))   ==   NULL)   {
  981.     y1Error( "y2Initialize: Cannot open temp file"     );
  982.     }
  983.   
  984.     /* Open a file to copy the user-supplied rule-action code into. */
  985.     /* (We add calling machinery as we go along.)            */
  986.     if ((y2ActionFD = fopen( ACTNAME, "w" ))   ==   NULL) {
  987.     y1Error( "y2Initialize: Cannot open action file" );
  988.     }
  989.   
  990.     /* Put out a header line at the beginning of the 'table' file: */
  991.     /* CrT: What is "CSD"? Capricious Software Demolition :-) ?    */
  992.     fprintf(
  993.     y2ytabcFD,
  994.     "\n/* Created by CSD_YACC (IBM PC) from \"%s\" */\n",
  995.     inputFilename
  996.     );
  997.   
  998.     /* Complete the initialization: */
  999.   
  1000.     y2TextFree     = y2Text;
  1001.   
  1002.     /* End token is 0: */
  1003.     y2Define( 0,"$end" ); 
  1004.   
  1005.     /* Other noncharacter terminal tokens start at 257: */
  1006.     y2NextTerminalNumber  = 0400;
  1007.   
  1008.     /* Define remaining special tokens: */
  1009.     y2Define( 0, "error"   ); 
  1010.     y2Define( 1, "$accept" ); 
  1011.   
  1012.     /* y2Pool is empty: */
  1013.     y2FreePool = y2Pool;
  1014. }
  1015.           
  1016.  
  1017. /************************************************************************/ 
  1018. /*      y2SkipComment   Skip over comments.                             */ 
  1019. /************************************************************************/  
  1020. static y2SkipComment() {    /* Called only from y2GetToken        */
  1021.     
  1022.     register c;
  1023.     register linesSkipped;
  1024.  
  1025.     linesSkipped =0;
  1026.     
  1027.     /* y2SkipComment is called after reading a '/': */ 
  1028.             
  1029.     if (y1GetChar( y2InputFD )     !=   '*')  {
  1030.     y1Error( "y2SkipComment: Illegal comment" );
  1031.     }
  1032.     
  1033.     for (c = y1GetChar( y2InputFD );   c != EOF;   c = y1GetChar( y2InputFD )){
  1034.     
  1035.         while (c == '*') {  
  1036.     
  1037.         if ((c = y1GetChar( y2InputFD ))   ==   '/')   return linesSkipped;
  1038.         }  
  1039.     if (c == '\n')     ++linesSkipped;
  1040.     }
  1041.  
  1042.     y1Error( "y2SkipComment: EOF inside comment" );
  1043.  
  1044.     /* NOTREACHED */  
  1045.   
  1046.  
  1047. /************************************************************************/
  1048. /*      y2TypeOf        Determine the type of a symbol.                 */ 
  1049. /************************************************************************/ 
  1050. static y2TypeOf( t )           /* Called only by y2CpyAction        */
  1051. int t; 
  1052.     register v; 
  1053.   
  1054.     if (t >= FIRSTnONTERMINAL)    {
  1055.     v = y2NonterminalState[ t - FIRSTnONTERMINAL ].tvalue;
  1056.     } else {
  1057.     v = TYPE( y2TerminalProperties[ t ] );
  1058.     }
  1059.   
  1060.     if (v <= 0) { 
  1061.         y1Error( 
  1062.         "y2TypeOf: Must specify type for %s",
  1063.         (
  1064.         (t >= FIRSTnONTERMINAL)
  1065.         ?
  1066.         y2NonterminalState[ t-FIRSTnONTERMINAL ].name
  1067.         :
  1068.         y2Terminal[ t ].name
  1069.         )
  1070.         ); 
  1071.     } 
  1072.     return   v; 
  1073.   
  1074.   
  1075. /************************************************************************/
  1076. /*    y2Usage                             */
  1077. /************************************************************************/ 
  1078. static y2Usage() {        /* Called only by y2Initialize        */
  1079.    
  1080.     fprintf( stderr, "\nCDS_YACC:\n"                  );
  1081.     fprintf( stderr, "   yacc -hi infile\n\n"                     ); 
  1082.     fprintf( stderr, "Switches:\n"                                ); 
  1083.     fprintf( stderr, "   -h   Create definitions header file\n"   ); 
  1084.     fprintf( stderr, "   -i   Create parser description file\n\n" ); 
  1085.     fprintf( stderr, "Default input file extension is \".Y\"\n"   ); 
  1086.     fprintf( stderr, "Defs file same name, \".H\" extension.\n"   ); 
  1087.     fprintf( stderr, "Info file same name, \".I\" extension.\n"   ); 
  1088.    
  1089.     exit(EX_ERR);  
  1090. }  
  1091.    
  1092.  
  1093. /************************************************************************/
  1094. /*    y2WriteDefines    Post declarations: write out the defines        */ 
  1095. /************************************************************************/ 
  1096. static y2WriteDefines() {    /* Called only by y2yyParse        */
  1097.   
  1098.     /********************************************************************/
  1099.     /* Write out the defines.  We do this at the end of the declaration */
  1100.     /* section.  If a %{ ... %} section is encountered we write all    */
  1101.     /* pending declarations out to give the C code access to them.    */
  1102.     /* Thus, we may not be writing ALL existing declarations this call: */
  1103.     /********************************************************************/
  1104.  
  1105.     register int  i, c; 
  1106.     register char *cp; 
  1107.            
  1108.     /* For all declarations not yet written out: */
  1109.     for (i = y2NumberOfDefinedSymbolsWritten;   i <= y2NextTerminal;   ++i) {
  1110.   
  1111.     cp = y2Terminal[i].name;
  1112.     if (*cp == ' ')   ++cp;  /* Literals. */
  1113.            
  1114.     /* Ignore defined strings with special characters in them: */
  1115.         for (   ;   c = *cp;   ++cp) {
  1116.         if (!islower(c)  &&  !isupper(c)  &&  !isdigit(c)  &&  c != '_') {
  1117.                 goto nodef; 
  1118.             } 
  1119.         } 
  1120.            
  1121.     /* Write out the #define: */
  1122.         fprintf(
  1123.         y2ytabcFD,
  1124.         "# define %s %d\n",
  1125.         y2Terminal[i].name,
  1126.         y2Terminal[i].value
  1127.     );
  1128.  
  1129.  
  1130.     /* If a .h file was requested, write to it also: */
  1131.         if (y2DefineFD != NULL) {
  1132.             fprintf( 
  1133.         y2DefineFD,
  1134.                 "# define %s %d\n", 
  1135.         y2Terminal[i].name,
  1136.         y2Terminal[i].value
  1137.             ); 
  1138.         } 
  1139. nodef:  ; 
  1140.     } 
  1141.     y2NumberOfDefinedSymbolsWritten = y2NextTerminal+1;
  1142.   
  1143.  
  1144. /************************************************************************/
  1145. /*    y2yyParse    Kludged YACC input parser.            */
  1146. /************************************************************************/
  1147. y2yyParse() {         /* Called only from main. */
  1148.  
  1149.     int  token;
  1150.     int  j;
  1151.     int  c;
  1152.     int *p;
  1153.     char actionName[8];
  1154.     int  typeOfEmpty;
  1155.  
  1156.     int  associativity = 0;
  1157.     int  type           = 0;
  1158.     int  precedence    = 0;
  1159.  
  1160.     /* "Sorry -- no yacc parser here..... we must bootstrap somehow..."  */
  1161.  
  1162.     /* Handle the declaration section ended by a %% MARKer: */
  1163.     for (token = y2GetToken();     token != MARK   &&   token != ENDFILE;   ) {
  1164.   
  1165.     switch (token) {
  1166.   
  1167.         case LCURLY: 
  1168.         /* Copy some literal C code across. Give it definitions to date: */
  1169.             y2WriteDefines(); 
  1170.             y2CpyCode(); 
  1171.         token = y2GetToken();
  1172.             continue;  
  1173.             
  1174.         case UNION: 
  1175.             /* Copy the union declaration to the output: */  
  1176.             y2CpyUnion(); 
  1177.         token = y2GetToken();
  1178.             continue;  
  1179.             
  1180.         case ';': 
  1181.         token = y2GetToken();
  1182.             break; 
  1183.            
  1184.         case START: 
  1185.         /* Handle a %start declaration: */
  1186.             if ((token = y2GetToken())   !=   IDENTIFIER) {
  1187.         y1Error( "y2yyParse: Bad %%start construction" );
  1188.             }  
  1189.         y2RootNonterminal    = (
  1190.         y2FindName( TYPEnONTERMINAL, y2InputTokenText )
  1191.         );
  1192.             token       = y2GetToken();
  1193.             continue; 
  1194.            
  1195.         case TYPEDEF: 
  1196.         /* Handle a %token declaration: */
  1197.             if ((token = y2GetToken())   !=   TYPENAME) {
  1198.         y1Error( "y2yyParse: Bad syntax in %%type" );
  1199.             } 
  1200.         type  = y2InputNumberValue;
  1201.   
  1202.         /* Handle IDENTIFIER string following the %token: */
  1203.             loop {
  1204.   
  1205.         switch (token = y2GetToken()) {
  1206.   
  1207.         case ',':                 continue;
  1208.         case ';':    token = y2GetToken();        break;
  1209.    
  1210.                 case IDENTIFIER: 
  1211.   
  1212.             /* Look up token, creating new entry if necessary: */
  1213.                     token = y2FindName( TYPEnONTERMINAL, y2InputTokenText );
  1214.  
  1215.             /* Handle terminals and nonterminals separately: */
  1216.                     if (token < FIRSTnONTERMINAL) {
  1217.   
  1218.                         /* Terminal: */
  1219.  
  1220.                         /* See what it is declared as: */
  1221.                         j = TYPE( y2TerminalProperties[ token ] );
  1222.   
  1223.             /* OK if no type yet or same type: */
  1224.                         if (j == 0   ||   j == type) {
  1225.  
  1226.                 SETtYPEtO( y2TerminalProperties[token], type );
  1227.  
  1228.                         } else { 
  1229.                             y1Error( 
  1230.                 "y2yyParse: Type redeclaration of token %s",
  1231.                  y2Terminal[token].name
  1232.                             ); 
  1233.                         } 
  1234.   
  1235.                     } else { 
  1236.   
  1237.             /* Nonterminal: */
  1238.  
  1239.             /* See what it is was previously declared as: */
  1240.                         j   = y2NonterminalState[
  1241.                 token - FIRSTnONTERMINAL
  1242.             ].tvalue;
  1243.   
  1244.             /* No type or matching type ok: */
  1245.                         if (j == 0   ||   j == type) {
  1246.  
  1247.                 y2NonterminalState[
  1248.                 token - FIRSTnONTERMINAL
  1249.                 ].tvalue = type;
  1250.  
  1251.                         } else { 
  1252.                 y1Error(
  1253.                 "y2yyParse: Redeclaration of nonterminal %s",
  1254.                 y2NonterminalState[
  1255.                     token - FIRSTnONTERMINAL
  1256.                 ].name
  1257.                             ); 
  1258.             }
  1259.                     } 
  1260.                     continue; 
  1261.   
  1262.                 default: 
  1263.                     break; 
  1264.                 } 
  1265.                 break; 
  1266.             }  
  1267.             continue; 
  1268.            
  1269.         case LEFT: 
  1270.         case BINARY: 
  1271.     case RIGHT:          ++precedence;    /* Fall into TERMINAL: */
  1272.  
  1273.     case TERMINAL:
  1274.         /* Nonzero means new precedence and associativity: */
  1275.         associativity = token - TERMINAL;
  1276.         type  = 0;
  1277.   
  1278.             /* Get identifiers so defined: */ 
  1279.            
  1280.         token = y2GetToken();
  1281.  
  1282.         if (token == TYPENAME) {
  1283.   
  1284.                 /* There is a type defined: */ 
  1285.         type    = y2InputNumberValue;
  1286.         token    = y2GetToken();
  1287.             }  
  1288.  
  1289.             loop {
  1290.   
  1291.         switch (token) {
  1292.  
  1293.                 case ',':       token = y2GetToken();        continue;
  1294.         case ';':                    break;
  1295.  
  1296.                 case IDENTIFIER: 
  1297.             j = y2FindName( TYPEtERMINAL, y2InputTokenText );
  1298.  
  1299.             if (associativity) {
  1300.  
  1301.             if (ASSOCIATIVITY( y2TerminalProperties[j] )) {
  1302.                             y1Error( 
  1303.                 "y2yyParse: Redeclaration of precedence of %s",
  1304.                 y2InputTokenText
  1305.                             ); 
  1306.                         } 
  1307.             SETaSSOCIATIVITYtO(   y2TerminalProperties[j], associativity);
  1308.             SETpRECEDENCElEVELtO( y2TerminalProperties[j], precedence);
  1309.                     } 
  1310.   
  1311.             if (type) {
  1312.             if (TYPE( y2TerminalProperties[j] )) {
  1313.                             y1Error( 
  1314.                 "y2yyParse: Redeclaration of type of %s",
  1315.                 y2InputTokenText
  1316.                             ); 
  1317.                         } 
  1318.             SETtYPEtO( y2TerminalProperties[j], type );
  1319.                     } 
  1320.   
  1321.             if ((token = y2GetToken())     ==   NUMBER) {
  1322.             y2Terminal[j].value = y2InputNumberValue;
  1323.             if (j < y2NumberOfDefinedSymbolsWritten   &&   j > 2) {
  1324.                             y1Error( 
  1325.                 "y2yyParse: Must define type # of %s earlier",
  1326.                 y2Terminal[j].name
  1327.                             ); 
  1328.                         } 
  1329.             token = y2GetToken();
  1330.                     } 
  1331.                     continue; 
  1332.                 } 
  1333.                 break; 
  1334.             }  
  1335.             continue; 
  1336.            
  1337.         default: 
  1338.         printf(  "y2yyParse: Unrecognized character: %o\n", token);
  1339.         y1Error( "y2yyParse: Syntax error" );
  1340.         } 
  1341.     } 
  1342.            
  1343.  
  1344.  
  1345.     /******************************/
  1346.     /* End of declaration section */
  1347.     /******************************/
  1348.  
  1349.     if (token == ENDFILE)  y1Error( "y2yyParse: Unexpected EOF before %%" );
  1350.   
  1351.     /* Token is MARK (%%), wrap up declaration section stuff: */
  1352.            
  1353.     y2WriteDefines(); 
  1354.            
  1355.     fprintf( y2ytabcFD,"#define yyclearin yychar = -1\n" );
  1356.     fprintf( y2ytabcFD,"#define yyerrok yyerrflag = 0\n" );
  1357. #ifdef XYZZY 
  1358.     fprintf( y2ytabcFD,"extern int yychar;\nextern short yyerrflag;\n" );
  1359. #endif 
  1360.     fprintf(
  1361.     y2ytabcFD,
  1362.     "#ifndef YYMAXDEPTH\n#define YYMAXDEPTH 150\n#endif\n"
  1363.     );
  1364.     if (!y2NumberOfTypesDefined) {
  1365.     fprintf(
  1366.         y2ytabcFD,
  1367.         "#ifndef YYSTYPE\n#define YYSTYPE int\n#endif\n"
  1368.     );
  1369.     } 
  1370.   
  1371. #ifdef unix  
  1372.     fprintf( y2ytabcFD,  "YYSTYPE yylval, yyval;\n" );
  1373. #else      
  1374.     fprintf( y2ytabcFD, "extern YYSTYPE yylval;  /*CSD & DECUS LEX */\n");
  1375.     fprintf( y2ytabcFD, "YYSTYPE yyval;          /*CSD & DECUS LEX */\n");
  1376. #endif     
  1377.   
  1378.     /* Set up to start parsing the rules ("productions"): */
  1379.     y2Production[ 0 ]     = y2FreePool;
  1380.   
  1381.     /* If no %start declaration is made, the first nonterminal is used: */
  1382.   
  1383.     *y2FreePool++ = FIRSTnONTERMINAL;
  1384.     *y2FreePool++ = y2RootNonterminal;
  1385.     *y2FreePool++ = 1;
  1386.     *y2FreePool++ = 0;
  1387.   
  1388.     y2Production[1]    = y2FreePool;
  1389.   
  1390.     /* Copy any %{...%} code between the %% and the first rule: */
  1391.     while ((token = y2GetToken())   ==     LCURLY)   y2CpyCode();
  1392.   
  1393.     if (token != C_IDENTIFIER) {
  1394.     y1Error( "y2yyParse: Bad syntax on first rule" );
  1395.     }
  1396.     if (!y2RootNonterminal) {
  1397.     y2Production[0][1] = y2FindName(TYPEnONTERMINAL,y2InputTokenText);
  1398.     }
  1399.            
  1400.     /* Now read all rules in the grammar: */
  1401.     while (token != MARK   &&    token != ENDFILE) {
  1402.   
  1403.         /* Process a rule: */ 
  1404.            
  1405.     if     (token == '|'         ) {
  1406.   
  1407.         /* Copy over LHS of previous production: */
  1408.         *y2FreePool++ = *y2Production[ y2ThisProduction-1 ];
  1409.   
  1410.     } else if (token == C_IDENTIFIER) {
  1411.   
  1412.         /* Copy internal ID# for LHS nonterminal to first slot in rule: */
  1413.             *y2FreePool   = y2FindName( TYPEnONTERMINAL, y2InputTokenText );
  1414.         if (*y2FreePool < FIRSTnONTERMINAL)  {
  1415.            y1Error( "y2yyParse: Terminal illegal on LHS of grammar rule" );
  1416.         }
  1417.         ++y2FreePool;
  1418.   
  1419.         } else { 
  1420.   
  1421.         y1Error( "y2yyParse: Illegal rule: missing semicolon or | ?" );
  1422.   
  1423.         } 
  1424.            
  1425.         /* Read rule body: */ 
  1426.     token = y2GetToken();
  1427.   
  1428. more_rule:  
  1429.     while (token == IDENTIFIER) {
  1430.   
  1431.         *y2FreePool = y2FindName( TYPEnONTERMINAL, y2InputTokenText );
  1432.   
  1433.         /* Grammar rules inherit the associativity and  */
  1434.         /* precedence of any embedded terminals:        */
  1435.             if (*y2FreePool < FIRSTnONTERMINAL) {
  1436.         y2ProductionProperties[ y2ThisProduction ]  = (
  1437.             y2TerminalProperties[ *y2FreePool ]
  1438.         );
  1439.             }
  1440.   
  1441.         ++y2FreePool;
  1442.         token = y2GetToken();
  1443.         } 
  1444.   
  1445.     /* Handle "%prec" commands: */
  1446.         if (token == PREC) {
  1447.         if (y2GetToken() != IDENTIFIER)   {
  1448.         y1Error( "y2yyParse: Illegal %%prec syntax" );
  1449.         }
  1450.  
  1451.         /* Look up terminal specified in %prec: */
  1452.             j   = y2FindName( TYPEpREC, y2InputTokenText );
  1453.  
  1454.         /* Make sure it is not a nonterminal: */
  1455.             if (j >= FIRSTnONTERMINAL) {
  1456.                 y1Error( 
  1457.             "y2yyParse: Nonterminal %s illegal after %%prec",
  1458.             y2NonterminalState[ j-FIRSTnONTERMINAL ].name
  1459.                 ); 
  1460.             } 
  1461.  
  1462.         /* Let current rule inherit specified precedence: */
  1463.         y2ProductionProperties[ y2ThisProduction ] = (
  1464.         y2TerminalProperties[ j ]
  1465.         );
  1466.             token = y2GetToken();
  1467.         } 
  1468.   
  1469.     /* Handle actions: */
  1470.         if (token == '=') {
  1471.             int RHSItems;
  1472.  
  1473.         /* Remember that this rule has an action: */
  1474.             y2ProductionProperties[ y2ThisProduction ]   |= RULEhASaCTION;
  1475.  
  1476.         /* Figure number of items seen so far on right-hand side */
  1477.         /* of grammar rule (for check $n args in actions):         */
  1478.         RHSItems  =  y2FreePool  -    y2Production[ y2ThisProduction ]  -1;
  1479.  
  1480.         /* Copy action code to output, handling $ variables: */
  1481.             y2CpyAction( RHSItems );
  1482.  
  1483.         /* Check for more rule after the action: */
  1484.             if ((token = y2GetToken())   ==   IDENTIFIER) {
  1485.   
  1486.         /* Action within rule. Split it into two rules: */
  1487.         sprintf( actionName, "$$%d", y2ThisProduction );
  1488.   
  1489.         /* Create a nonterminal: */
  1490.         j = y2FindName(TYPEnONTERMINAL,actionName);
  1491.   
  1492.   
  1493.                 /*******************************************************/ 
  1494.         /* The current rule will become rule number           */
  1495.         /* y2ThisProduction+1.    Move the contents down, and    */
  1496.         /* make room for the null:                   */
  1497.                 /*******************************************************/ 
  1498.   
  1499.         for (
  1500.             p  = y2FreePool;
  1501.             p >= y2Production[ y2ThisProduction ];
  1502.             p--
  1503.         ) {
  1504.             p[2] = *p;
  1505.         }
  1506.                 y2FreePool += 2;
  1507.   
  1508.                 /* Enter null production for action: */ 
  1509.         p    = y2Production[ y2ThisProduction ];
  1510.                 *p++    = j; 
  1511.         *p++    = -y2ThisProduction;
  1512.            
  1513.                 /* Update the production information: */ 
  1514.  
  1515.         /* Current rule does NOT have an action after all: */
  1516.         y2ProductionProperties[ y2ThisProduction+1 ] = (
  1517.             y2ProductionProperties[ y2ThisProduction ] & ~RULEhASaCTION
  1518.         );
  1519.  
  1520.         /* But added null production DOES have an action: */
  1521.         y2ProductionProperties[ y2ThisProduction   ] =    RULEhASaCTION;
  1522.            
  1523.         /* Check for too productions: */
  1524.         if (++y2ThisProduction >= MAXpRODUCTIONS)   {
  1525.             y1Error( "y2yyParse: More than %d rules", MAXpRODUCTIONS );
  1526.         }
  1527.         y2Production[ y2ThisProduction ]    = p;
  1528.            
  1529.                 /* Make the action appear in the original rule: */ 
  1530.         *y2FreePool++ = j;
  1531.   
  1532.                 /* Get some more of the rule: */ 
  1533.                 goto more_rule; 
  1534.             }  
  1535.         } 
  1536.            
  1537.     /* Handle end of rule: */
  1538.         while (token == ';')    token = y2GetToken();
  1539.            
  1540.     *y2FreePool++ = -y2ThisProduction;
  1541.            
  1542.         /* Check that default action is reasonable: */ 
  1543.            
  1544.         if ( 
  1545.         y2NumberOfTypesDefined
  1546.             && 
  1547.         !(y2ProductionProperties[ y2ThisProduction ] & RULEhASaCTION)
  1548.             && 
  1549.         y2NonterminalState[ * /* DeSmet C bug pins the '*' to this line */
  1550.         y2Production[ y2ThisProduction ]
  1551.         -
  1552.         FIRSTnONTERMINAL
  1553.         ].tvalue
  1554.     ) {
  1555.             /* No explicit action, LHS has value: */ 
  1556.         typeOfEmpty = y2Production[ y2ThisProduction ][ 1 ];
  1557.   
  1558.         if (typeOfEmpty < 0) {
  1559.   
  1560.         y1Error("y2yyParse: Must return value, since LHS has a type");
  1561.  
  1562.         } else if (typeOfEmpty >= FIRSTnONTERMINAL ) {
  1563.   
  1564.          typeOfEmpty = (
  1565.              y2NonterminalState[ typeOfEmpty-FIRSTnONTERMINAL ].tvalue
  1566.          );
  1567.             } else { 
  1568.   
  1569.          typeOfEmpty = TYPE( y2TerminalProperties[typeOfEmpty] );
  1570.             } 
  1571.   
  1572.         if (
  1573.         typeOfEmpty
  1574.         !=
  1575.         y2NonterminalState[ * /* DeSmet C bug keeps '*' from moving */
  1576.             y2Production[ y2ThisProduction ]
  1577.             -
  1578.             FIRSTnONTERMINAL
  1579.         ].tvalue
  1580.         ) {
  1581.         y1Error("y2yyParse: Default action has potential type clash");
  1582.         }
  1583.         } 
  1584.  
  1585.     /* Check for too many productions: */
  1586.     if (++y2ThisProduction >= MAXpRODUCTIONS)  {
  1587.          y1Error( "y2yyParse: more than %d rules", MAXpRODUCTIONS );
  1588.     }
  1589.   
  1590.     y2Production[ y2ThisProduction ]       = y2FreePool;
  1591.     y2ProductionProperties[ y2ThisProduction ] =   0;
  1592.     } 
  1593.   
  1594.  
  1595.     /*********************/
  1596.     /* End of all rules: */
  1597.     /*********************/
  1598.  
  1599.     /* Properly terminate the last line: */ 
  1600.     fprintf(y2ActionFD, "/* End of actions. */");
  1601.     fclose( y2ActionFD );
  1602.     fprintf( y2ytabcFD, "# define YYERRCODE %d\n", y2Terminal[2].value );
  1603.   
  1604.     /* Copy anything remaining to the output code file: */
  1605.     if (token == MARK) {
  1606.     fprintf( y2ytabcFD, "\n#line %d\n", y1LineNumber );
  1607.   
  1608.     while ((c = y1GetChar( y2InputFD ))   !=   EOF)   putc( c, y2ytabcFD );
  1609.     } 
  1610.     fclose( y2InputFD );
  1611.  
  1612.     /* All finished with input! Now return and start analysing grammar: */
  1613. }
  1614.            
  1615.  
  1616.