home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pccts.zip / pccts / antlr / antlr.g < prev    next >
Text File  |  1994-03-31  |  35KB  |  1,208 lines

  1. /*
  2.  * antlr.g    --    PCCTS Version 1.xx ANTLR
  3.  *
  4.  * $Id: antlr.g,v 1.7 1994/03/25 19:40:05 parrt Exp parrt $
  5.  * $Revision: 1.7 $
  6.  *
  7.  * Parse an antlr input grammar and build a syntax-diagram.
  8.  *
  9.  * Written in itself (needs at least 1.06 to work)
  10.  *
  11.  * SOFTWARE RIGHTS
  12.  *
  13.  * We reserve no LEGAL rights to the Purdue Compiler Construction Tool
  14.  * Set (PCCTS) -- PCCTS is in the public domain.  An individual or
  15.  * company may do whatever they wish with source code distributed with
  16.  * PCCTS or the code generated by PCCTS, including the incorporation of
  17.  * PCCTS, or its output, into commerical software.
  18.  * 
  19.  * We encourage users to develop software with PCCTS.  However, we do ask
  20.  * that credit is given to us for developing PCCTS.  By "credit",
  21.  * we mean that if you incorporate our source code into one of your
  22.  * programs (commercial product, research project, or otherwise) that you
  23.  * acknowledge this fact somewhere in the documentation, research report,
  24.  * etc...  If you like PCCTS and have developed a nice tool with the
  25.  * output, please mention that you developed it using PCCTS.  In
  26.  * addition, we ask that this header remain intact in our source code.
  27.  * As long as these guidelines are kept, we expect to continue enhancing
  28.  * this system and expect to make other tools available as they are
  29.  * completed.
  30.  *
  31.  * ANTLR 1.20
  32.  * Terence Parr
  33.  * Purdue University
  34.  * With AHPCRC, University of Minnesota
  35.  * 1989-1994
  36.  */
  37. #header <<
  38.     #ifdef __cplusplus
  39.     #ifndef __STDC__
  40.     #define __STDC__
  41.     #endif
  42.     #endif
  43.     #include "set.h"
  44.     #include <ctype.h>
  45.     #include "syn.h"
  46.     #include "hash.h"
  47.     #include "generic.h"
  48.     #define zzcr_attr(attr,tok,t)
  49.     >>
  50.  
  51. <<
  52. #ifdef __STDC__
  53. static void chkToken(char *, char *, char *, int);
  54. #else
  55. static void chkToken();
  56. #endif
  57.  
  58. static int class_nest_level = 0;
  59. >>
  60.  
  61. #lexaction <<
  62. /* maintained, but not used for now */
  63. set AST_nodes_refd_in_actions = set_init;
  64. >>
  65.  
  66. #lexclass STRINGS
  67. #token QuotedTerm "\""        << zzmode(START); >>
  68. #token "\n"                    <<
  69.                             zzline++;
  70.                             warn("eoln found in string");
  71.                             zzskip();
  72.                             >>
  73. #token "\\~[]"                << zzmore(); >>
  74. #token "~[\n\"\\]+"            << zzmore(); >>
  75.  
  76. #lexclass ACTION_STRINGS
  77. #token "\""                    << zzmode(ACTIONS); zzmore(); >>
  78. #token "\n"                    <<
  79.                             zzline++;
  80.                             warn("eoln found in string (in user action)");
  81.                             zzskip();
  82.                             >>
  83. #token "\\~[]"                << zzmore(); >>
  84. #token "~[\n\"\\]+"            << zzmore(); >>
  85.  
  86. #lexclass ACTION_CHARS
  87. #token "'"                    << zzmode(ACTIONS); zzmore(); >>
  88. #token "\n"                    <<
  89.                             zzline++;
  90.                             warn("eoln found in char literal (in user action)");
  91.                             zzskip();
  92.                             >>
  93. #token "\\~[]"                << zzmore(); >>
  94. #token "~[\n'\\]+"            << zzmore(); >>
  95.  
  96. #lexclass ACTION_COMMENTS
  97. #token "\*/"                << zzmode(ACTIONS); zzmore(); >>
  98. #token "\*"                    << zzmore(); >>
  99. #token "\n"                    << zzline++; zzmore(); >>
  100. #token "~[\n\*]+"            << zzmore(); >>
  101.  
  102. #lexclass TOK_DEF_COMMENTS
  103. #token "\*/"                << zzmode(PARSE_ENUM_FILE); zzmore(); >>
  104. #token "\*"                    << zzmore(); >>
  105. #token "\n"                    << zzline++; zzmore(); >>
  106. #token "~[\n\*]+"            << zzmore(); >>
  107.  
  108. #lexclass TOK_DEF_CPP_COMMENTS
  109. #token "\n"                    << zzline++; zzmode(PARSE_ENUM_FILE); zzmore(); >>
  110. #token "~[\n]+"                << zzmore(); >>
  111.  
  112. #lexclass ACTION_CPP_COMMENTS
  113. #token "\n"                    << zzline++; zzmode(ACTIONS); zzmore(); >>
  114. #token "~[\n]+"                << zzmore(); >>
  115.  
  116. #lexclass CPP_COMMENTS
  117. #token "\n"                    << zzline++; zzmode(START); zzskip(); >>
  118. #token "~[\n]+"                << zzskip(); >>
  119.  
  120. #lexclass COMMENTS
  121. #token "\*/"                << zzmode(START); zzskip(); >>
  122. #token "\*"                    << zzskip(); >>
  123. #token "\n"                    << zzline++; zzskip(); >>
  124. #token "~[\n\*]+"            << zzskip(); >>
  125.  
  126. /*
  127.  * This lexical class accepts actions of type [..] and <<..>>
  128.  *
  129.  * It translates the following special items for C:
  130.  *
  131.  * $j        --> "zzaArg(current zztasp, j)"
  132.  * $i.j        --> "zzaArg(zztaspi, j)"
  133.  * $i.nondigit> "zzaArg(current zztasp, i).nondigit"
  134.  * $$        --> "zzaRet"
  135.  * $alnum    --> "alnum"            (used to ref parameters)
  136.  * $rule    --> "zzaRet"
  137.  * $retval    --> "_retv.retval" if > 1 return values else "_retv"
  138.  * $[token, text] --> "zzconstr_attr(token, text)"
  139.  * $[]        --> "zzempty_attr()"
  140.  *
  141.  * It translates the following special items for C++:
  142.  * (attributes are now stored with 'Token' and $i's are only 
  143.  *  pointers to the Tokens.  Rules don't have attributes now.)
  144.  *
  145.  * $j        --> "_tbj" where b is the block level
  146.  * $i.j        --> "_tij"
  147.  * $j->nondigit> "_tbj->nondigit"
  148.  * $$        --> "$$"
  149.  * $alnum    --> "alnum"            (used to ref parameters)
  150.  * $rule    --> "$rule"
  151.  * $retval    --> "_retv.retval" if > 1 return values else "_retv"
  152.  * $[token, text] --> invalid
  153.  * $[]        --> invalid
  154.  *
  155.  * And, for trees:
  156.  *
  157.  * #0        -->    "(*_root)"
  158.  * #i        --> "zzastArg(i)"
  159.  * #[args]    --> "zzmk_ast(zzastnew(), args)"
  160.  * #[]        --> "zzastnew()"
  161.  * #( root, child1, ..., childn )
  162.             --> "zztmake(root, child1, ...., childn, NULL)"
  163.  * #()        --> "NULL"
  164.  *
  165.  * For C++, ...
  166.  *
  167.  * #0        -->    "(*_root)"
  168.  * #i        --> "_astbi" where b is the block level
  169.  * #[args]    --> "new AST(args)"
  170.  * #[]        --> "new AST"
  171.  * #( root, child1, ..., childn )
  172.             --> "AST::tmake(root, child1, ...., childn, NULL)"
  173.  * #()        --> "NULL"
  174.  *
  175.  * To escape,
  176.  *
  177.  * \]        --> ]
  178.  * \)        --> )
  179.  * \$        --> $
  180.  * \#        --> #
  181.  *
  182.  * A stack is used to nest action terminators because they can be nested
  183.  * like crazy:  << #[$[..],..] >>
  184.  */
  185. #lexclass ACTIONS
  186. #token Action "\>\>"        << /* these do not nest */
  187.                               zzmode(START);
  188.                               NLATEXT[0] = ' ';
  189.                               NLATEXT[1] = ' ';
  190.                               zzbegexpr[0] = ' ';
  191.                               zzbegexpr[1] = ' ';
  192.                               if ( zzbufovf ) {
  193.                                 err( eMsgd("action buffer overflow; size %d",ZZLEXBUFSIZE));
  194.                               }
  195.                             >>
  196. #token Pred "\>\>?"            << /* these do not nest */
  197.                               zzmode(START);
  198.                               NLATEXT[0] = ' ';
  199.                               NLATEXT[1] = ' ';
  200.                               zzbegexpr[0] = '\0';
  201.                               if ( zzbufovf ) {
  202.                                 err( eMsgd("predicate buffer overflow; size %d",ZZLEXBUFSIZE));
  203.                               }
  204.                             >>
  205. #token PassAction "\]"        << if ( topint() == ']' ) {
  206.                                   popint();
  207.                                   if ( istackempty() )    /* terminate action */
  208.                                   {
  209.                                       zzmode(START);
  210.                                       NLATEXT[0] = ' ';
  211.                                       zzbegexpr[0] = ' ';
  212.                                       if ( zzbufovf ) {
  213.                                         err( eMsgd("parameter buffer overflow; size %d",ZZLEXBUFSIZE));
  214.                                       }
  215.                                   }
  216.                                   else {
  217.                                       /* terminate $[..] and #[..] */
  218.                                       if ( GenCC ) zzreplstr("))");
  219.                                       else zzreplstr(")");
  220.                                       zzmore();
  221.                                   }
  222.                                }
  223.                                else if ( topint() == '|' ) { /* end of simple [...] */
  224.                                   popint();
  225.                                   zzmore();
  226.                                }
  227.                                else zzmore();
  228.                             >>
  229. #token "\n"                    << zzline++; zzmore(); >>
  230. #token "\>"                    << zzmore(); >>
  231. #token "$"                    << zzmore(); >>
  232. #token "$$"                    << if ( !GenCC ) {zzreplstr("zzaRet"); zzmore();}
  233.                                else err("$$ use invalid in C++ mode"); >>
  234.  
  235. #token "$\[\]"                << if ( !GenCC ) {zzreplstr("zzempty_attr"); zzmore();}
  236.                                else err("$[] use invalid in C++ mode"); >>
  237. #token "$\["                <<
  238.                             pushint(']');
  239.                             if ( !GenCC ) zzreplstr("zzconstr_attr(");
  240.                             else err("$[..] use invalid in C++ mode");
  241.                             zzmore();
  242.                             >>
  243. #token "$[0-9]+"            <<{
  244.                             static char buf[100];
  245.                             if ( strlen(zzbegexpr)>85 )
  246.                                 fatal("$i attrib ref too big");
  247.                             if ( !GenCC ) sprintf(buf,"zzaArg(zztasp%d,%s)",
  248.                                         BlkLevel-1,zzbegexpr+1);
  249.                             else sprintf(buf,"_t%d%s",
  250.                                         BlkLevel-1,zzbegexpr+1);
  251.                             zzreplstr(buf);
  252.                             zzmore();
  253.                             }
  254.                             >>
  255. #token "$[0-9]+."            <<{
  256.                             static char buf[100];
  257.                             if ( strlen(zzbegexpr)>85 )
  258.                                 fatal("$i.field attrib ref too big");
  259.                             zzbegexpr[strlen(zzbegexpr)-1] = ' ';
  260.                             if ( !GenCC ) sprintf(buf,"zzaArg(zztasp%d,%s).",
  261.                                         BlkLevel-1,zzbegexpr+1);
  262.                             else sprintf(buf,"_t%d%s.",
  263.                                         BlkLevel-1,zzbegexpr+1);
  264.                             zzreplstr(buf);
  265.                             zzmore();
  266.                             }
  267.                             >>
  268. #token "$[0-9]+.[0-9]+"        <<{
  269.                             static char buf[100];
  270.                             static char i[20], j[20];
  271.                             char *p,*q;
  272.                             if (strlen(zzbegexpr)>85) fatal("$i.j attrib ref too big");
  273.                             for (p=zzbegexpr+1,q= &i[0]; *p!='.'; p++) {
  274.                                 if ( q == &i[20] ) fatalFL("i of $i.j attrib ref too big", FileStr[CurFile], zzline );
  275.                                 *q++ = *p;
  276.                             }
  277.                             *q = '\0';
  278.                             for (p++, q= &j[0]; *p!='\0'; p++) {
  279.                                 if ( q == &j[20] ) fatalFL("j of $i.j attrib ref too big", FileStr[CurFile], zzline );
  280.                                 *q++ = *p;
  281.                             }
  282.                             *q = '\0';
  283.                             if ( !GenCC ) sprintf(buf,"zzaArg(zztasp%s,%s)",i,j);
  284.                             else sprintf(buf,"_t%s%s",i,j);
  285.                             zzreplstr(buf);
  286.                             zzmore();
  287.                             }
  288.                             >>
  289. #token "$[_a-zA-Z][_a-zA-Z0-9]*"
  290.                             <<{ static char buf[300];
  291.                             zzbegexpr[0] = ' ';
  292.                             if ( CurRule != NULL &&
  293.                                  strcmp(CurRule, &zzbegexpr[1])==0 ) {
  294.                                 if ( !GenCC ) zzreplstr("zzaRet");
  295.                             }
  296.                             else if ( CurRetDef != NULL ) {
  297.                                 if ( strmember(CurRetDef, &zzbegexpr[1]) ) {
  298.                                     if ( HasComma( CurRetDef ) ) {
  299.                                         require (strlen(zzbegexpr)<=285,
  300.                                                  "$retval attrib ref too big");
  301.                                         sprintf(buf,"_retv.%s",&zzbegexpr[1]);
  302.                                         zzreplstr(buf);
  303.                                     }
  304.                                     else zzreplstr("_retv");
  305.                                 }
  306.                                 else if ( CurParmDef != NULL ) {
  307.                                     if ( !strmember(CurParmDef, &zzbegexpr[1]) )
  308.                                         warn(eMsg1("$%s not parameter or return value",&zzbegexpr[1]));
  309.                                 }
  310.                                 else warn(eMsg1("$%s not parameter or return value",&zzbegexpr[1]));
  311.                             }
  312.                             }
  313.                             zzmore();
  314.                             >>
  315. #token "#0"                    << zzreplstr("(*_root)"); zzmore(); >>
  316. #token "#\[\]"                << if ( GenCC ) zzreplstr("(new AST)");
  317.                                zzreplstr("zzastnew()"); zzmore();>>
  318. #token "#\(\)"                << zzreplstr("NULL"); zzmore(); >>
  319. #token "#[0-9]+"            <<{
  320.                             static char buf[100];
  321.                             if ( strlen(zzbegexpr)>85 )
  322.                                 fatal("#i AST ref too big");
  323.                             if ( GenCC ) sprintf(buf,"_ast%d%s",BlkLevel-1,zzbegexpr+1);
  324.                             else sprintf(buf,"zzastArg(%s)",zzbegexpr+1);
  325.                             zzreplstr(buf);
  326.                             zzmore();
  327.                             set_orel(atoi(zzbegexpr+1), &AST_nodes_refd_in_actions);
  328.                             }
  329.                             >>
  330. #token "#\["                <<
  331.                             pushint(']');
  332.                             if ( GenCC ) zzreplstr("(new AST(");
  333.                             else zzreplstr("zzmk_ast(zzastnew(),");
  334.                             zzmore();
  335.                             >>
  336. #token "#\("                <<
  337.                             pushint('}');
  338.                             if ( GenCC ) zzreplstr("ASTBase::tmake(");
  339.                             else zzreplstr("zztmake(");
  340.                             zzmore();
  341.                             >>
  342. #token "#"                    << zzmore(); >>
  343. #token "\)"                    <<
  344.                             if ( istackempty() )
  345.                                 zzmore();
  346.                             else if ( topint()==')' ) {
  347.                                 popint();
  348.                             }
  349.                             else if ( topint()=='}' ) {
  350.                                 popint();
  351.                                 /* terminate #(..) */
  352.                                 zzreplstr(", NULL)");
  353.                             }
  354.                             zzmore();
  355.                             >>
  356. #token "\["                    <<
  357.                             pushint('|');    /* look for '|' to terminate simple [...] */
  358.                             zzmore();
  359.                             >>
  360. #token "\("                    <<
  361.                             pushint(')');
  362.                             zzmore();
  363.                             >>
  364.  
  365. #token "\\\]"                << zzreplstr("]");  zzmore(); >>
  366. #token "\\\)"                << zzreplstr(")");  zzmore(); >>
  367. #token "\\>"                << zzreplstr(">");  zzmore(); >>
  368.  
  369.  
  370. #token "'"                    << zzmode(ACTION_CHARS); zzmore();>>
  371. #token "\""                    << zzmode(ACTION_STRINGS); zzmore();>>
  372. #token "\\$"                << zzreplstr("$");  zzmore(); >>
  373. #token "\\#"                << zzreplstr("#");  zzmore(); >>
  374. /*#token "\\\\"                << zzmore(); >> /* need this for some reason */
  375. #token "\\~[\]\)>$#]"        << zzmore(); >> /* escaped char, always ignore */
  376. #token "/"                    << zzmore(); >>
  377. #token "/\*"                << zzmode(ACTION_COMMENTS); zzmore(); >>
  378. #token "\*/"                << warn("Missing /*; found dangling */ in action"); zzmore(); >>
  379. #token "//"                    << zzmode(ACTION_CPP_COMMENTS); zzmore(); >>
  380. #token "~[\n\)\(\\$#\>\]\[\"'/]+" << zzmore(); >>
  381.  
  382. #lexclass START
  383. #token "[\t\ ]+"            << zzskip(); >>                /* Ignore White */
  384. #token "[\n\r]"                << zzline++; zzskip(); >>    /* Track Line # */
  385. #token "\["                 << zzmode(ACTIONS); zzmore();
  386.                                istackreset();
  387.                                pushint(']'); >>
  388. #token "\<\<"               << action_file=CurFile; action_line=zzline;
  389.                                zzmode(ACTIONS); zzmore();
  390.                                istackreset();
  391.                                pushint('>'); >>
  392. #token "\""                    << zzmode(STRINGS); zzmore(); >>
  393. #token "/\*"                << zzmode(COMMENTS); zzskip(); >>
  394. #token "\*/"                << warn("Missing /*; found dangling */"); zzskip(); >>
  395. #token "//"                    << zzmode(CPP_COMMENTS); zzskip(); >>
  396. #token "\>\>"                << warn("Missing <<; found dangling \\>\\>"); zzskip(); >>
  397. #token WildCard "."
  398. #token Eof                    "@"
  399.                             <<    /* L o o k  F o r  A n o t h e r  F i l e */
  400.                             {
  401.                             FILE *new_input;
  402.                             new_input = NextFile();
  403.                             if ( new_input == NULL ) { NLA=Eof; return; }
  404.                             fclose( input );
  405.                             input = new_input;
  406.                             zzrdstream( input );
  407.                             /*zzadvance();    /* Get 1st char of this file */
  408.                             zzskip();    /* Skip the Eof (@) char i.e continue */
  409.                             }
  410.                             >>
  411.  
  412. #errclass "grammar-element" { element }
  413. #errclass "meta-symbol"        { "\}" "!" ";" "\|" "\~" "^" "\)" }
  414.  
  415. /*
  416.  * Get a grammar -- Build a list of rules like:
  417.  *
  418.  *    o-->Rule1--o
  419.  *    |
  420.  *    o-->Rule2--o
  421.  *    |
  422.  *    ...
  423.  *    |
  424.  *    o-->RuleN--o
  425.  */
  426. grammar :    <<Graph g;>>
  427.             (    "#header" Action
  428.                 <<
  429.                 if ( HdrAction==NULL ) {
  430.                 HdrAction = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  431.                 require(HdrAction!=NULL, "rule grammar: cannot allocate header action");
  432.                 strcpy(HdrAction, LATEXT(1));
  433.                 }
  434.                 else warn("additional #header statement ignored");
  435.                 >>
  436.             |    "#parser" QuotedTerm
  437.                 <<
  438.                 if ( GenCC ) {
  439.                     warn("#parser meta-op incompatible with -CC; ignored");
  440.                 }
  441.                 else {
  442.                     if ( strcmp(ParserName,"zzparser")==0 ) {
  443.                         ParserName=StripQuotes(mystrdup(LATEXT(1)));
  444.                         if ( RulePrefix[0]!='\0' )
  445.                         {
  446.                             warn("#parser meta-op incompatible with '-gp prefix'; '-gp' ignored");
  447.                             RulePrefix[0]='\0';
  448.                         }
  449.                     }
  450.                     else warn("additional #parser statement ignored");
  451.                 }
  452.                 >>
  453.             |    "#tokdefs" QuotedTerm
  454.                 <<{
  455.                 zzantlr_state st; FILE *f; struct zzdlg_state dst;
  456.                 UserTokenDefsFile = mystrdup(LATEXT(1));
  457.                 zzsave_antlr_state(&st);
  458.                 zzsave_dlg_state(&dst);
  459.                 f = fopen(StripQuotes(LATEXT(1)), "r");
  460.                 if ( f==NULL ) {warn(eMsg1("cannot open token defs file '%s'", LATEXT(1)+1));}
  461.                 else {
  462.                     ANTLRm(enum_file(), f, PARSE_ENUM_FILE);
  463.                     UserDefdTokens = 1;
  464.                 }
  465.                 zzrestore_antlr_state(&st);
  466.                 zzrestore_dlg_state(&dst);
  467.                 }>>
  468.             )*
  469.             (    <<char *a;>>
  470.                 Action
  471.                 <<
  472.                 a = (char *) calloc(strlen(LATEXT(1))+1,
  473. sizeof(char));
  474.                 require(a!=NULL, "rule grammar: cannot allocate action");
  475.                 strcpy(a, LATEXT(1));
  476.                 if ( class_nest_level>0 ) list_add(&class_actions, a);
  477.                 else list_add(&BeforeActions, a);
  478.                 >>
  479.             |    laction
  480.             |    aLexclass
  481.             |    token
  482.             |    error
  483.             |    tclass
  484.             |    class_def
  485.             |    "\}"
  486.                 <<
  487.                 if ( class_nest_level==0 )
  488.                     warn("missing class definition for trailing '}'");
  489.                 class_nest_level--;
  490.                 >>
  491.             )*
  492.             rule        <<g=$3; SynDiag = (Junction *) $3.left;>>
  493.             (    rule    <<if ( $1.left!=NULL ) {g.right = NULL; g = Or(g, $1);}>>
  494.             |    aLexclass
  495.             |    token
  496.             |    error
  497.             |    tclass
  498.             |    class_def
  499.             |    "\}"
  500.                 <<
  501.                 if ( class_nest_level==0 )
  502.                     warn("missing class definition for trailing '}'");
  503.                 class_nest_level--;
  504.                 >>
  505.             )*
  506.             (    <<char *a;>>
  507.                 Action
  508.                 <<
  509.                 a = (char *) calloc(strlen(LATEXT(1))+1,
  510. sizeof(char));
  511.                 require(a!=NULL, "rule grammar: cannot allocate action");
  512.                 strcpy(a, LATEXT(1));
  513.                 if ( class_nest_level>0 ) list_add(&class_actions, a);
  514.                 else list_add(&AfterActions, a);
  515.                 >>
  516.             |    laction
  517.             |    error
  518.             |    tclass
  519.             |    class_def
  520.             |    "\}"
  521.                 <<
  522.                 if ( class_nest_level==0 )
  523.                     warn("missing class definition for trailing '}'");
  524.                 class_nest_level--;
  525.                 >>
  526.             )*
  527.             Eof
  528.         ;
  529.         <<CannotContinue=TRUE;>>
  530.  
  531. class_def
  532.     :    <<int go=1; char name[MaxRuleName+1];>>
  533.         "class"
  534.         (    NonTerminal        <<if(go) strncpy(name,LATEXT(1),MaxRuleName);>>
  535.         |    TokenTerm        <<if(go) strncpy(name,LATEXT(1),MaxRuleName);>>
  536.         )
  537.         <<
  538.         if ( CurrentClassName[0]!='\0' && strcmp(CurrentClassName,name)!=0
  539.              && GenCC ) {
  540.             err("only one grammar class allowed in this release");
  541.             go = 0;
  542.         }
  543.         else strcpy(CurrentClassName, name);
  544.         >>
  545.         <<if ( !GenCC ) { err("class meta-op used without C++ option"); }>>
  546.         "\{"
  547.         <<
  548.         no_classes_found = 0;
  549.         if ( class_nest_level>=1 ) {warn("cannot have nested classes");}
  550.         else class_nest_level++;
  551.         >>
  552.     ;
  553.     <<CannotContinue=TRUE;>>
  554.  
  555. /*
  556.  * Build -o-->o-R-o-->o-    where -o-R-o- is the block from rule 'block'.
  557.  * Construct the RuleBlk front and EndRule node on the end of the
  558.  * block.  This is used to add FOLLOW pointers to the rule end.  Add the
  559.  * new rule name to the Rname hash table and sets its rulenum.
  560.  * Store the parameter definitions if any are found.
  561.  *
  562.  * Note that locks are required on the RuleBlk and EndRule nodes to thwart
  563.  * infinite recursion.
  564.  *
  565.  * Return the left graph pointer == NULL to indicate error/dupl rule def.
  566.  */
  567. rule    :    <<
  568.             RuleEntry *q; Junction *p; Graph r; int f, l; ECnode *e;
  569.             set toksrefd, rulesrefd;
  570.             char *pdecl=NULL, *ret=NULL, *a; CurRetDef = CurParmDef = NULL;
  571.             >>
  572.             NonTerminal
  573.             <<q=NULL;
  574.               if ( hash_get(Rname, LATEXT(1))!=NULL ) {
  575.                   warn(eMsg1("duplicate rule definition: '%s'",LATEXT(1)));
  576.                   CannotContinue=TRUE;
  577.               }
  578.               else
  579.               {
  580.                     q = (RuleEntry *)hash_add(Rname,
  581.                                         LATEXT(1),
  582.                                         (Entry *)newRuleEntry(LATEXT(1)));
  583.                   CurRule = q->str;
  584.               }
  585.               CurRuleNode = q;
  586.               f = CurFile; l = zzline;
  587.               NumRules++;
  588.             >>
  589.             {    "!"  <<if ( q!=NULL ) q->noAST = TRUE;>> }
  590.             {    <<;>>
  591.                 {"\<"}
  592.                 PassAction
  593.                 <<    pdecl = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  594.                     require(pdecl!=NULL, "rule rule: cannot allocate param decl");
  595.                     strcpy(pdecl, LATEXT(1));
  596.                     CurParmDef = pdecl;
  597.                 >>
  598.             }
  599.             {    "\>"
  600.                 PassAction
  601.                 <<    ret = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  602.                     require(ret!=NULL, "rule rule: cannot allocate ret type");
  603.                     strcpy(ret, LATEXT(1));
  604.                      CurRetDef = ret;
  605.                 >>
  606.             }
  607.             { QuotedTerm <<if ( q!=NULL ) q->egroup=mystrdup(LATEXT(1));>> }
  608.             <<
  609.             if ( GenEClasseForRules && q!=NULL ) {
  610.                 e = newECnode;
  611.                 require(e!=NULL, "cannot allocate error class node");
  612.                 if ( q->egroup == NULL ) {a = q->str; a[0] = (char)toupper(a[0]);}
  613.                 else a = q->egroup;
  614.                 if ( Tnum( a ) == 0 )
  615.                 {
  616.                     e->tok = addTname( a );
  617.                     list_add(&eclasses, (char *)e);
  618.                     if ( q->egroup == NULL ) a[0] = (char)tolower(a[0]);
  619.                     /* refers to itself */
  620.                     list_add(&(e->elist), mystrdup(q->str));
  621.                 }
  622.                 else {
  623.                     warn(eMsg1("default errclass for '%s' would conflict with token/errclass/tokclass",a));
  624.                     if ( q->egroup == NULL ) a[0] = (char)tolower(a[0]);
  625.                     free(e);
  626.                 }
  627.             }
  628.             >>
  629.             <<BlkLevel++;>>
  630.             ":" block[&toksrefd, &rulesrefd]
  631.                             <<r = makeBlk($7,0);
  632.                               ((Junction *)r.left)->jtype = RuleBlk;
  633.                               if ( q!=NULL ) ((Junction *)r.left)->rname = q->str;
  634.                               ((Junction *)r.left)->file = f;
  635.                               ((Junction *)r.left)->line = l;
  636.                               ((Junction *)r.left)->pdecl = pdecl;
  637.                               ((Junction *)r.left)->ret = ret;
  638.                               ((Junction *)r.left)->lock = makelocks();
  639.                               ((Junction *)r.left)->pred_lock = makelocks();
  640.                               ((Junction *)r.left)->tokrefs = toksrefd;
  641.                               ((Junction *)r.left)->rulerefs = rulesrefd;
  642.                               p = newJunction();    /* add EndRule Node */
  643.                               ((Junction *)r.right)->p1 = (Node *)p;
  644.                               r.right = (Node *) p;
  645.                               p->jtype = EndRule;
  646.                               p->lock = makelocks();
  647.                               p->pred_lock = makelocks();
  648.                               ((Junction *)r.left)->end = p;
  649.                               if ( q!=NULL ) q->rulenum = NumRules;
  650.                               $7 = r;
  651.                             >>
  652.             <<--BlkLevel;>>
  653.             ";"
  654.             {    Action
  655.                 <<    a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  656.                     require(a!=NULL, "rule rule: cannot allocate error action");
  657.                     strcpy(a, LATEXT(1));
  658.                     ((Junction *)r.left)->erraction = a;
  659.                 >>
  660.             }
  661.             <<if ( q==NULL ) $0.left = NULL; else $0 = $7;>>
  662.             <<CurRuleNode = NULL;>>
  663.         ;
  664.         <<CannotContinue=TRUE;>>
  665.  
  666. laction    :    <<char *a;>>
  667.             "#lexaction"
  668.             Action
  669.             <<
  670.             a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  671.             require(a!=NULL, "rule laction: cannot allocate action");
  672.             strcpy(a, LATEXT(1));
  673.             list_add(&LexActions, a);
  674.             >>
  675.         ;
  676.         <<CannotContinue=TRUE;>>
  677.  
  678. aLexclass:    "#lexclass" TokenTerm <<lexclass(mystrdup(LATEXT(1)));>>
  679.         ;
  680.         <<CannotContinue=TRUE;>>
  681.  
  682. error    :    <<char *t=NULL; ECnode *e; int go=1; TermEntry *p;>>
  683.             "#errclass"
  684.             (<<;>>    TokenTerm  <<t=mystrdup(LATEXT(1));>>
  685.             |        QuotedTerm <<t=mystrdup(LATEXT(1));>>
  686.             )
  687.             <<e = newECnode;
  688.               require(e!=NULL, "cannot allocate error class node");
  689.               e->lexclass = CurrentLexClass;
  690.               if ( Tnum( (t=StripQuotes(t)) ) == 0 )
  691.               {
  692.                 if ( hash_get(Texpr, t) != NULL )
  693.                     warn(eMsg1("errclass name conflicts with regular expression  '%s'",t));
  694.                   e->tok = addTname( t );
  695.                 set_orel(e->tok, &imag_tokens);
  696.                 require((p=(TermEntry *)hash_get(Tname, t)) != NULL,
  697.                         "hash table mechanism is broken");
  698.                 p->classname = 1;    /* entry is errclass name, not token */
  699.                 list_add(&eclasses, (char *)e);
  700.               }
  701.               else
  702.               {
  703.                   warn(eMsg1("redefinition of errclass or conflict w/token or tokclass '%s'; ignored",t));
  704.                 free( e );
  705.                 go=0;
  706.               }
  707.             >>
  708.             "\{"
  709.                 ( NonTerminal <<if ( go ) t=mystrdup(LATEXT(1));>>
  710.                 | TokenTerm <<if ( go ) t=mystrdup(LATEXT(1));>>
  711.                 | QuotedTerm <<if ( go ) t=mystrdup(LATEXT(1));>>
  712.                 )
  713.                 <<if ( go ) list_add(&(e->elist), t);>>
  714.                 (
  715.                     ( NonTerminal <<if ( go ) t=mystrdup(LATEXT(1));>>
  716.                     | TokenTerm <<if ( go ) t=mystrdup(LATEXT(1));>>
  717.                     | QuotedTerm <<if ( go ) t=mystrdup(LATEXT(1));>>
  718.                     )
  719.                     <<if ( go ) list_add(&(e->elist), t);>>
  720.                 )*
  721.             "\}"
  722.         ;
  723.         <<CannotContinue=TRUE;>>
  724.  
  725. tclass    :    <<char *t=NULL; TCnode *e; int go=1,tok; TermEntry *p, *term;>>
  726.             "#tokclass" TokenTerm <<t=mystrdup(LATEXT(1));>>
  727.             <<e = newTCnode;
  728.               require(e!=NULL, "cannot allocate token class node");
  729.               e->lexclass = CurrentLexClass;
  730.               if ( Tnum( t ) == 0 )
  731.               {
  732.                   e->tok = addTname( t );
  733.                 set_orel(e->tok, &imag_tokens);
  734.                 require((p=(TermEntry *)hash_get(Tname, t)) != NULL,
  735.                         "hash table mechanism is broken");
  736.                 p->classname = 1;    /* entry is class name, not token */
  737.                 p->tclass = e;        /* save ptr to this tclass def */
  738.                 list_add(&tclasses, (char *)e);
  739.               }
  740.               else
  741.               {
  742.                   warn(eMsg1("redefinition of tokclass or conflict w/token '%s'; ignored",t));
  743.                 free( e );
  744.                 go=0;
  745.               }
  746.             >>
  747.             "\{"
  748.                 (
  749.                 ( TokenTerm
  750.                   <<if ( go ) {
  751.                     term = (TermEntry *) hash_get(Tname, LATEXT(1));
  752.                     if ( term==NULL && UserDefdTokens ) {
  753.                         err("implicit token definition not allowed with #tokdefs");
  754.                         go = 0;
  755.                     }
  756.                     else {t=mystrdup(LATEXT(1)); tok=addTname(LATEXT(1));}
  757.                     }>>
  758.                 | QuotedTerm
  759.                   <<if ( go ) {
  760.                     term = (TermEntry *) hash_get(Texpr, LATEXT(1));
  761.                     if ( term==NULL && UserDefdTokens ) {
  762.                         err("implicit token definition not allowed with #tokdefs");
  763.                         go = 0;
  764.                     }
  765.                     else {t=mystrdup(LATEXT(1)); tok=addTexpr(LATEXT(1));}
  766.                     }>>
  767.                 )
  768.                 <<if ( go ) list_add(&(e->tlist), t);>>
  769.                 )*
  770.             "\}"
  771.         ;
  772.         <<CannotContinue=TRUE;>>
  773.  
  774. token    :    <<char *t=NULL, *e=NULL, *a=NULL; int tnum=0;>>
  775.             "#token"
  776.             {    TokenTerm  <<t=mystrdup(LATEXT(1));>>
  777.                 {    "=" "[0-9]+"        /* define the token type number */
  778.                     <<tnum = atoi(LATEXT(1));>>
  779.                 }
  780.             }
  781.             { QuotedTerm <<e=mystrdup(LATEXT(1));>> }
  782.             {    Action
  783.                 <<
  784.                     a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  785.                     require(a!=NULL, "rule token: cannot allocate action");
  786.                     strcpy(a, LATEXT(1));
  787.                 >>
  788.             }
  789.             <<chkToken(t, e, a, tnum);>>
  790.         ;
  791.         <<CannotContinue=TRUE;>>
  792.  
  793. block[set *toksrefd, set *rulesrefd]
  794.         :    <<
  795.             Graph g, b;
  796.             *$toksrefd = empty;
  797.             *$rulesrefd = empty;
  798.             set_clr(AST_nodes_refd_in_actions);
  799.             >>
  800.             alt[toksrefd,rulesrefd]        <<b = g = $1;>>
  801.             <<
  802.             if ( ((Junction *)g.left)->p1->ntype == nAction )
  803.             {
  804.                 if ( !((ActionNode *)(((Junction *)g.left)->p1))->is_predicate )
  805.                 {
  806.                     ((ActionNode *)(((Junction *)g.left)->p1))->init_action = TRUE;
  807.                 }
  808.             }
  809.             >>
  810.             (    "\|"
  811.                 alt[toksrefd,rulesrefd]        <<g = Or(g, $2);>>
  812.             )*
  813.             <<$0 = b;>>
  814.         ;
  815.         <<CannotContinue=TRUE;>>
  816.  
  817. alt[set *toksrefd, set *rulesrefd]
  818.         :    <<int n=0,ne=0; Graph g; int e_num=0, not=0;
  819.             int first_on_line = 1; g.left=g.right=NULL;
  820.             >>
  821.             (    <<int tok;>>
  822.                 <<tok = LA(1);>>
  823.                 { <<not=0;>> "\~" <<not=1;>> }
  824.                 element[not, first_on_line]
  825.                 <<if ( tok!=Action && tok!=Pred ) first_on_line = 0;>>
  826.                 <<
  827.                 if ( $2.left!=NULL ) {
  828.                     g = Cat(g, $2);
  829.                     n++;
  830.                     if ( tok!=Action && tok!=Pred ) e_num++;
  831.                     /* record record number of all rule and token refs */
  832.                     if ( tok==TokenTerm||tok==QuotedTerm||tok==WildCard ) {
  833.                         ((TokNode *)((Junction *)$2.left)->p1)->elnum = e_num;
  834.                         set_orel(e_num, $toksrefd);
  835.                     }
  836.                     else if ( tok==NonTerminal ) {
  837.                         ((RuleRefNode *)((Junction *)$2.left)->p1)->elnum = e_num;
  838.                         set_orel(e_num, $rulesrefd);
  839.                     }
  840.                 }
  841.                 >>
  842.             )*
  843.             <<if ( n == 0 ) g = emptyAlt();
  844.               $0 = g;
  845.             >>
  846.         ;
  847.         <<CannotContinue=TRUE;>>
  848.  
  849. element[int not, int first_on_line]
  850.         :    <<
  851.             set toksrefd, rulesrefd;
  852.             TermEntry *term;
  853.             TokNode *p=NULL; RuleRefNode *q; int approx=0;
  854.             >>
  855.             TokenTerm
  856.             <<
  857.             term = (TermEntry *) hash_get(Tname, LATEXT(1));
  858.             if ( term==NULL && UserDefdTokens ) {
  859.                 err("implicit token definition not allowed with #tokdefs");
  860.                 $0.left = $0.right = NULL;
  861.             }
  862.             else {
  863.                 $0 = buildToken(LATEXT(1)); p=((TokNode *)((Junction *)$0.left)->p1);
  864.                 term = (TermEntry *) hash_get(Tname, LATEXT(1));
  865.                 require( term!= NULL, "hash table mechanism is broken");
  866.                 p->tclass = term->tclass;
  867.                 p->complement = $not;
  868.             }
  869.             >>
  870.             {    ".."
  871.                 (    QuotedTerm
  872.                     <<if ( p!=NULL ) setUpperRange(p, LATEXT(1));>>
  873.                 |    TokenTerm
  874.                     <<if ( p!=NULL ) setUpperRange(p, LATEXT(1));>>
  875.                 )
  876.             }
  877.             <<
  878.             if ( p!=NULL && (p->upper_range!=0 || p->tclass || $not) )
  879.                 list_add(&MetaTokenNodes, (void *)p);
  880.             >>
  881.             (    "^"    <<if ( p!=NULL ) p->astnode=ASTroot;>>
  882.             |        <<if ( p!=NULL ) p->astnode=ASTchild;>>
  883.             |    "!" <<if ( p!=NULL ) p->astnode=ASTexclude;>>
  884.             )
  885.         |    QuotedTerm
  886.             <<
  887.             term = (TermEntry *) hash_get(Texpr, LATEXT(1));
  888.             if ( term==NULL && UserDefdTokens ) {
  889.                 err("implicit token definition not allowed with #tokdefs");
  890.                 $0.left = $0.right = NULL;
  891.             }
  892.             else {
  893.                 $0 = buildToken(LATEXT(1)); p=((TokNode *)((Junction *)$0.left)->p1);
  894.                 p->complement = $not;
  895.             }
  896.             >>
  897.             {    ".."
  898.                 (    QuotedTerm
  899.                     <<if ( p!=NULL ) setUpperRange(p, LATEXT(1));>>
  900.                 |    TokenTerm
  901.                     <<if ( p!=NULL ) setUpperRange(p, LATEXT(1));>>
  902.                 )
  903.             }
  904.             (    "^"    <<if ( p!=NULL ) p->astnode=ASTroot;>>
  905.             |        <<if ( p!=NULL ) p->astnode=ASTchild;>>
  906.             |    "!" <<if ( p!=NULL ) p->astnode=ASTexclude;>>
  907.             )
  908.             <<
  909.             if ( p!=NULL && (p->upper_range!=0 || p->tclass || $not) )
  910.                 list_add(&MetaTokenNodes, (void *)p);
  911.             >>
  912.         |    <<if ( $not ) warn("~ WILDCARD is an undefined operation (implies 'nothing')");>>
  913.             "."
  914.             <<$0 = buildWildCard(LATEXT(1)); p=((TokNode *)((Junction *)$0.left)->p1);>>
  915.             (    "^"    <<p->astnode=ASTroot;>>
  916.             |        <<p->astnode=ASTchild;>>
  917.             |    "!" <<p->astnode=ASTexclude;>>
  918.             )
  919.             <<list_add(&MetaTokenNodes, (void *)p);>>
  920.         |    <<if ( $not ) warn("~ NONTERMINAL is an undefined operation");>>
  921.             NonTerminal
  922.             <<$0 = buildRuleRef(LATEXT(1));>>
  923.             { "!" <<q = (RuleRefNode *) ((Junction *)$$.left)->p1;
  924.                     q->astnode=ASTexclude;>>
  925.             }
  926.             {    {"\<"}
  927.                 PassAction <<addParm(((Junction *)$$.left)->p1, LATEXT(1));>>
  928.             }
  929.             {    <<char *a; RuleRefNode *rr=(RuleRefNode *) ((Junction *)$$.left)->p1;
  930.                   >>
  931.                 "\>"
  932.                 PassAction
  933.                 <<
  934.                     a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  935.                     require(a!=NULL, "rule element: cannot allocate assignment");
  936.                     strcpy(a, LATEXT(1));
  937.                     rr->assign = a;
  938.                 >>
  939.             }
  940.         |    <<if ( $not )    warn("~ ACTION is an undefined operation");>>
  941.             Action <<$0 = buildAction(LATEXT(1),action_file,action_line, 0);>>
  942.         |    <<if ( $not )    warn("~ SEMANTIC-PREDICATE is an undefined operation");>>
  943.             Pred   <<$0 = buildAction(LATEXT(1),action_file,action_line, 1);>>
  944.             {    <<char *a; ActionNode *act = (ActionNode *) ((Junction *)$$.left)->p1;>>
  945.                 PassAction
  946.                 <<
  947.                 a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  948.                 require(a!=NULL, "rule element: cannot allocate predicate fail action");
  949.                 strcpy(a, LATEXT(1));
  950.                 act->pred_fail = a;
  951.                 >>
  952.             }
  953.             <<
  954.             if ( DemandLookahead )
  955.             {
  956.                 warn("-gk incompatible with <<..>>? predicate usage; -gk turned off");
  957.                 DemandLookahead = 0;
  958.             }
  959.             >>
  960.         |    <<if ( $not )    warn("~ BLOCK is an undefined operation");>>
  961.             <<BlkLevel++;>>
  962.             {    "#pragma"
  963.                 (    "approx" <<approx=LL_k;>>
  964.                 |    "LL(1)"  <<approx = 1;>>
  965.                 |    "LL(2)"  <<approx = 2;>>
  966.                 )
  967.             }
  968.             (    "\(" block[&toksrefd,&rulesrefd]
  969.                                 <<$$ = $2; --BlkLevel;>> "\)"
  970.                 (    "\*"        <<$$ = makeLoop($$,approx);>>
  971.                 |    "\+"        <<$$ = makePlus($$,approx);>>
  972.                 |    "?"            <<$$ = makeBlk($$,approx);
  973.                                   FoundGuessBlk = 1;
  974.                                   ((Junction *) ((Junction *)$$.left)->p1)->guess=1;
  975.                                   if ( !$first_on_line ) {
  976.                                     err("(...)? predicate must be first element of production");
  977.                                   }
  978.                                 >>
  979.                 |                <<$$ = makeBlk($$,approx);>>
  980.                 )
  981.                 <<
  982.                 ((Junction *)((Junction *)$$.left)->p1)->tokrefs = toksrefd;
  983.                 ((Junction *)((Junction *)$$.left)->p1)->rulerefs = rulesrefd;
  984.                 >>
  985.  
  986.                 {    PassAction    <<addParm(((Junction *)$$.left)->p1, LATEXT(1));>>
  987.                 }
  988.             |    "\{"    block[&toksrefd,&rulesrefd]
  989.                         <<$$ = makeOpt($2,approx); --BlkLevel;>>
  990.                 "\}"
  991.                 <<
  992.                 ((Junction *)((Junction *)$$.left)->p1)->tokrefs = toksrefd;
  993.                 ((Junction *)((Junction *)$$.left)->p1)->rulerefs = rulesrefd;
  994.                 >>
  995.                 {    PassAction    <<addParm(((Junction *)$$.left)->p1, LATEXT(1));>>
  996.                 }
  997.             )
  998.  
  999. /* Error catching alternatives */
  1000.         |    ":"        <<warn(eMsg1("missing ';' on rule %s", CurRule));
  1001.                       CannotContinue=TRUE;>>
  1002.         |    "\*"    <<warn("don't you want a ')' with that '*'?"); CannotContinue=TRUE;>>
  1003.         |    "\+"    <<warn("don't you want a ')' with that '+'?"); CannotContinue=TRUE;>>
  1004.         |    "\>"    <<warn("'>' can only appear after a nonterminal"); CannotContinue=TRUE;>>
  1005.         |    PassAction <<warn("[...] out of context 'rule > [...]'");
  1006.                          CannotContinue=TRUE;>>
  1007.         ;
  1008.         <<CannotContinue=TRUE;>>
  1009.  
  1010. #token NonTerminal        "[a-z] [A-Za-z0-9_]*"
  1011. #token TokenTerm        "[A-Z] [A-Za-z0-9_]*"
  1012. #token "#[A-Za-z0-9_]*"    <<warn(eMsg1("unknown meta-op: %s",LATEXT(1))); zzskip(); >>
  1013.  
  1014. #lexclass PARSE_ENUM_FILE
  1015.  
  1016. #token "[\t\ ]+"            << zzskip(); >>                /* Ignore White */
  1017. #token "[\n\r]"                << zzline++; zzskip(); >>    /* Track Line # */
  1018. #token "//"                    << zzmode(TOK_DEF_CPP_COMMENTS); zzmore(); >>
  1019. #token "/\*"                << zzmode(TOK_DEF_COMMENTS); zzmore(); >>
  1020. #token "@"                    << ; >>
  1021.  
  1022. enum_file
  1023.     :    ( enum_def )*
  1024.     |    defines
  1025.     ;
  1026.  
  1027. defines
  1028.     :    <<int v,maxt= -1; char *t;>>
  1029.         (
  1030.             "#define" ID
  1031.             <<t = mystrdup(LATEXT(1));>>
  1032.             INT
  1033.             <<
  1034.             v = atoi(LATEXT(1));
  1035. /*            fprintf(stderr, "#token %s=%d\n", t, v); */
  1036.             TokenNum = v;
  1037.             if ( v>maxt ) maxt=v;
  1038.             if ( Tnum( t ) == 0 ) addForcedTname( t, v );
  1039.             else {
  1040.                 warn(eMsg1("redefinition of token %s; ignored",t));
  1041.             }
  1042.             >>
  1043.         )*
  1044.         <<TokenNum = maxt + 1;>>
  1045.     ;
  1046.  
  1047. enum_def
  1048.     :    <<int v= -1; char *t;>>
  1049.         "enum" ID
  1050.         "\{"
  1051.             ID
  1052.             <<t = mystrdup(LATEXT(1));>>
  1053.             (    "=" INT    <<v=atoi(LATEXT(1));>>
  1054.             |            <<v++;>>
  1055.             )
  1056.             <<
  1057. /*            fprintf(stderr, "#token %s=%d\n", t, v);*/
  1058.             TokenNum = v;
  1059.             if ( Tnum( t ) == 0 ) addForcedTname( t, v );
  1060.             else {
  1061.                 warn(eMsg1("redefinition of token %s; ignored",t));
  1062.             }
  1063.             >>
  1064.             (    ","
  1065.                 {    ID
  1066.                     <<t = mystrdup(LATEXT(1));>>
  1067.                     (    "=" INT    <<v=atoi(LATEXT(1));>>
  1068.                     |            <<v++;>>
  1069.                     )
  1070.                     <<
  1071. /*                    fprintf(stderr, "#token %s=%d\n", t, v);*/
  1072.                     TokenNum = v;
  1073.                     if ( Tnum( t ) == 0 ) addForcedTname( t, v );
  1074.                     else {
  1075.                         warn(eMsg1("redefinition of token %s; ignored",t));
  1076.                     }
  1077.                     >>
  1078.                 }
  1079.             )*
  1080.         "\}"
  1081.         ";"
  1082.         <<TokenNum++;>>
  1083.     ;
  1084.  
  1085. #token INT    "[0-9]+"
  1086. #token ID    "[A-Z][_a-zA-Z0-9]*"
  1087.  
  1088. #lexclass START
  1089.  
  1090. <<
  1091. /* semantics of #token */
  1092. static void
  1093. #ifdef __STDC__
  1094. chkToken(char *t, char *e, char *a, int tnum)
  1095. #else
  1096. chkToken(t,e,a,tnum)
  1097. char *t, *e, *a;
  1098. int tnum;
  1099. #endif
  1100. {
  1101.     TermEntry *p;
  1102.  
  1103.     /* check to see that they don't try to redefine a token as a token class */
  1104.     if ( t!=NULL ) {
  1105.         p = (TermEntry *) hash_get(Tname, t);
  1106.         if ( p!=NULL && p->classname ) {
  1107.             err(eMsg1("redefinition of #tokclass '%s' to #token not allowed; ignored",t));
  1108.             if ( a!=NULL ) free(a);
  1109.             return;
  1110.         }
  1111.     }
  1112.  
  1113.     if ( t==NULL && e==NULL ) {            /* none found */
  1114.         err("#token requires at least token name or rexpr");
  1115.     }
  1116.     else if ( t!=NULL && e!=NULL ) {    /* both found */
  1117.         if ( UserDefdTokens ) {            /* if #tokdefs, must not define new */
  1118.             p = (TermEntry *) hash_get(Tname, t);
  1119.             if ( p==NULL ) {
  1120.                 err(eMsg1("#token definition '%s' not allowed with #tokdefs; ignored",t));
  1121.                 return;
  1122.             }
  1123.         }
  1124.         Tklink(t, e);
  1125.         if ( a!=NULL ) {
  1126.             if ( hasAction(e) ) {
  1127.                 err(eMsg1("redefinition of action for %s; ignored",e));
  1128.             }
  1129.             else setHasAction(e, a);
  1130.         }
  1131.     }
  1132.     else if ( t!=NULL ) {                /* only one found */
  1133.         if ( UserDefdTokens ) {
  1134.             err(eMsg1("#token definition '%s' not allowed with #tokdefs; ignored",t));
  1135.             return;
  1136.         }
  1137.         if ( Tnum( t ) == 0 ) addTname( t );
  1138.         else {
  1139.             err(eMsg1("redefinition of token %s; ignored",t));
  1140.         }
  1141.         if ( a!=NULL ) {
  1142.             err(eMsg1("action cannot be attached to a token name (%s); ignored",t));
  1143.             free(a);
  1144.         }
  1145.     }
  1146.     else if ( e!=NULL ) {
  1147.         if ( Tnum( e ) == 0 ) addTexpr( e );
  1148.         else {
  1149.             if ( hasAction(e) ) {
  1150.                 err(eMsg1("redefinition of action for expr %s; ignored",e));
  1151.             }
  1152.             else if ( a==NULL ) {
  1153.                 err(eMsg1("redefinition of expr %s; ignored",e));
  1154.             }
  1155.         }
  1156.         if ( a!=NULL ) setHasAction(e, a);
  1157.     }
  1158.  
  1159.     /* if a token type number was specified, then add the token ID and 'tnum'
  1160.      * pair to the ForcedTokens list.  (only applies if an id was given)
  1161.      */
  1162.     if ( t!=NULL && tnum>0 )
  1163.     {
  1164.         if ( set_el(tnum, reserved_positions) )
  1165.         {
  1166.             err(eMsgd("a token has already been forced to token number %d; ignored", tnum));
  1167.         }
  1168.         else
  1169.         {
  1170.             list_add(&ForcedTokens, newForcedToken(t,tnum));
  1171.             set_orel(tnum, &reserved_positions);
  1172.         }
  1173.     }
  1174. }
  1175. >>
  1176.  
  1177. <<
  1178. /* ANTLR-specific syntax error message generator 
  1179.  * (define USER_ZZSYN when compiling so don't get 2 definitions)
  1180.  */
  1181. void
  1182. #ifdef __STDC__
  1183. zzsyn(char *text, int tok, char *egroup, SetWordType *eset, int etok, int k, char *bad_text)
  1184. #else
  1185. zzsyn(text, tok, egroup, eset, etok, k, bad_text)
  1186. char *text, *egroup, *bad_text;
  1187. int tok;
  1188. int etok;
  1189. int k;
  1190. SetWordType *eset;
  1191. #endif
  1192. {
  1193.     fprintf(stderr, ErrHdr, FileStr[CurFile]!=NULL?FileStr[CurFile]:"stdin", zzline);
  1194.     fprintf(stderr, " syntax error at \"%s\"", (tok==zzEOF_TOKEN)?"EOF":text);
  1195.     if ( !etok && !eset ) {fprintf(stderr, "\n"); return;}
  1196.     if ( k==1 ) fprintf(stderr, " missing");
  1197.     else
  1198.     {
  1199.         fprintf(stderr, "; \"%s\" not", bad_text);
  1200.         if ( zzset_deg(eset)>1 ) fprintf(stderr, " in");
  1201.     }
  1202.     if ( zzset_deg(eset)>0 ) zzedecode(eset);
  1203.     else fprintf(stderr, " %s", zztokens[etok]);
  1204.     if ( strlen(egroup) > 0 ) fprintf(stderr, " in %s", egroup);
  1205.     fprintf(stderr, "\n");
  1206. }
  1207. >>
  1208.