home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / p / pccts.zip / antlr / antlr.g < prev    next >
Text File  |  1992-12-08  |  21KB  |  671 lines

  1. /*
  2.  * antlr.g    --    PCCTS Version 1.xx ANTLR
  3.  *
  4.  * Parse an antlr input grammar and build a syntax-diagram.
  5.  *
  6.  * Terence Parr
  7.  * Purdue University
  8.  * August 1990
  9.  *
  10.  * Rewritten in itself (needs at least 1.00 to work) May 1992--TJP
  11.  *
  12.  * SOFTWARE RIGHTS
  13.  *
  14.  * We reserve no LEGAL rights to the Purdue Compiler Construction Tool
  15.  * Set (PCCTS) -- PCCTS is in the public domain.  An individual or
  16.  * company may do whatever they wish with source code distributed with
  17.  * PCCTS or the code generated by PCCTS, including the incorporation of
  18.  * PCCTS, or its output, into commerical software.
  19.  * 
  20.  * We encourage users to develop software with PCCTS.  However, we do ask
  21.  * that credit is given to us for developing PCCTS.  By "credit",
  22.  * we mean that if you incorporate our source code into one of your
  23.  * programs (commercial product, research project, or otherwise) that you
  24.  * acknowledge this fact somewhere in the documentation, research report,
  25.  * etc...  If you like PCCTS and have developed a nice tool with the
  26.  * output, please mention that you developed it using PCCTS.  In
  27.  * addition, we ask that this header remain intact in our source code.
  28.  * As long as these guidelines are kept, we expect to continue enhancing
  29.  * this system and expect to make other tools available as they are
  30.  * completed.
  31.  *
  32.  * ANTLR 1.06
  33.  * Terence Parr
  34.  * Purdue University
  35.  * 1989-1992
  36.  */
  37. #header <<#include "set.h"
  38.           #include <ctype.h>
  39.           #include "syn.h"
  40.           #include "hash.h"
  41.           #include "generic.h"
  42.           #define zzcr_attr(attr,tok,t)
  43.         >>
  44.  
  45. <<
  46. #ifdef __STDC__
  47. static void chkToken(char *, char *, char *);
  48. #else
  49. static void chkToken();
  50. #endif
  51. >>
  52.  
  53. #lexclass STRINGS
  54. #token QuotedTerm "\""        << zzmode(START); >>
  55. #token "\\\""                << zzmore(); >>
  56. #token "\n"                    <<
  57.                             zzline++;
  58.                             warn("eoln found in string (in user action)");
  59.                             zzskip();
  60.                             >>
  61. #token "\\~[\"]"            << zzmore(); >>
  62. #token "~[\n\"\\]+"            << zzmore(); >>
  63.  
  64. #lexclass COMMENTS
  65. #token "\*/"                << zzmode(START); zzskip(); >>
  66. #token "\*"                    << zzskip(); >>
  67. #token "\n"                    << zzline++; zzskip(); >>
  68. #token "~[\n\*]+"            << zzskip(); >>
  69.  
  70. /*
  71.  * This lexical class accepts actions of type [..] and <<..>>
  72.  *
  73.  * It translates the following special items:
  74.  *
  75.  * $j        --> "zzaArg(current zztasp, j)"
  76.  * $i.j        --> "zzaArg(zztaspi, j)"
  77.  * $i.nondigit> "zzaArg(current zztasp, i).nondigit"
  78.  * $$        --> "zzaRet"
  79.  * $alnum    --> "alnum"            (used to ref parameters)
  80.  * $rule    --> "zzaRet"
  81.  * $retval    --> "_retv.retval" if > 1 return values else "_retv"
  82.  * $[token, text] --> "zzconstr_attr(token, text)"
  83.  * $[]        --> "zzempty_attr()"
  84.  *
  85.  * And, for trees:
  86.  *
  87.  * #0        -->    "(*_root)"
  88.  * #i        --> "zzastArg(i)"
  89.  * #[args]    --> "zzmk_ast(zzastnew(), args)"
  90.  * #[]        --> "zzastnew()"
  91.  * #( root, child1, ..., childn )
  92.             --> "zztmake(root, child1, ...., childn, NULL)"
  93.  * #()        --> "NULL"
  94.  *
  95.  * To escape,
  96.  *
  97.  * \]        --> ]
  98.  * \)        --> )
  99.  * \$        --> $
  100.  * \#        --> #
  101.  *
  102.  * A stack is used to nest action terminators because they can be nested
  103.  * like crazy:  << #[$[..],..] >>
  104.  */
  105. #lexclass ACTIONS
  106. #token Action "\>\>"        << /* these do not nest */
  107.                               zzmode(START);
  108.                               NLATEXT[0] = ' ';
  109.                               NLATEXT[1] = ' ';
  110.                               zzbegexpr[0] = ' ';
  111.                               zzbegexpr[1] = ' ';
  112.                               if ( zzbufovf ) {
  113.                                 warn( eMsgd("action buffer overflow; size %d",ZZLEXBUFSIZE));
  114.                               }
  115.                             >>
  116. #token Pred "\>\>?"         << /* these do not nest */
  117.                               zzmode(START);
  118.                               NLATEXT[0] = ' ';
  119.                               NLATEXT[1] = ' ';
  120.                               zzbegexpr[0] = ' ';
  121.                               zzbegexpr[1] = ' ';
  122.                               zzbegexpr[2] = ' ';
  123.                               if ( zzbufovf ) {
  124.                                 warn( eMsgd("predicate buffer overflow; size %d",ZZLEXBUFSIZE));
  125.                               }
  126.                             >>
  127. #token PassAction "\]"        << if ( topint() == ']' ) {
  128.                                   popint();
  129.                                   if ( istackempty() )    /* terminate action */
  130.                                   {
  131.                                       zzmode(START);
  132.                                       NLATEXT[0] = ' ';
  133.                                       zzbegexpr[0] = ' ';
  134.                                       if ( zzbufovf ) {
  135.                                         warn( eMsgd("parameter buffer overflow; size %d",ZZLEXBUFSIZE));
  136.                                       }
  137.                                   }
  138.                                   else {
  139.                                       /* terminate $[..] and #[..] */
  140.                                       zzreplstr(")");
  141.                                       zzmore();
  142.                                   }
  143.                                }
  144.                                else if ( topint() == '|' ) { /* end of simple [...] */
  145.                                   popint();
  146.                                   zzmore();
  147.                                }
  148.                                else zzmore();
  149.                             >>
  150. #token "\n"                    << zzline++; zzmore(); >>
  151. #token "\>"                    << zzmore(); >>
  152. #token "$"                    << zzmore(); >>
  153. #token "$$"                    << zzreplstr("zzaRet"); zzmore(); >>
  154. #token "$\[\]"                << zzreplstr("zzempty_attr"); zzmore(); >>
  155. #token "$\["                <<
  156.                             pushint(']');
  157.                             zzreplstr("zzconstr_attr(");
  158.                             zzmore();
  159.                             >>
  160. #token "$[0-9]+"            <<{
  161.                             static char buf[100];
  162.                             if ( strlen(zzbegexpr)>85 )
  163.                                 fatal("$i attrib ref too big");
  164.                             sprintf(buf,"zzaArg(zztasp%d,%s)",
  165.                                         BlkLevel-1,zzbegexpr+1);
  166.                             zzreplstr(buf);
  167.                             zzmore();
  168.                             }
  169.                             >>
  170. #token "$[0-9]+."            <<{
  171.                             static char buf[100];
  172.                             if ( strlen(zzbegexpr)>85 )
  173.                                 fatal("$i.field attrib ref too big");
  174.                             zzbegexpr[strlen(zzbegexpr)-1] = ' ';
  175.                             sprintf(buf,"zzaArg(zztasp%d,%s).",
  176.                                         BlkLevel-1,zzbegexpr+1);
  177.                             zzreplstr(buf);
  178.                             zzmore();
  179.                             }
  180.                             >>
  181. #token "$[0-9]+.[0-9]+"        <<{
  182.                             static char buf[100];
  183.                             static char i[20], j[20];
  184.                             char *p,*q;
  185.                             if (strlen(zzbegexpr)>85) fatal("$i.j attrib ref too big");
  186.                             for (p=zzbegexpr+1,q= &i[0]; *p!='.'; p++) {
  187.                                 if ( q == &i[20] ) fatalFL("i of $i.j attrib ref too big", FileStr[CurFile], zzline );
  188.                                 *q++ = *p;
  189.                             }
  190.                             *q = '\0';
  191.                             for (p++, q= &j[0]; *p!='\0'; p++) {
  192.                                 if ( q == &j[20] ) fatalFL("j of $i.j attrib ref too big", FileStr[CurFile], zzline );
  193.                                 *q++ = *p;
  194.                             }
  195.                             *q = '\0';
  196.                             sprintf(buf,"zzaArg(zztasp%s,%s)",i,j);
  197.                             zzreplstr(buf);
  198.                             zzmore();
  199.                             }
  200.                             >>
  201. #token "$[_a-zA-Z][_a-zA-Z0-9]*"
  202.                             <<{ static char buf[300];
  203.                             zzbegexpr[0] = ' ';
  204.                             if ( CurRule != NULL &&
  205.                                  strcmp(CurRule, &zzbegexpr[1])==0 ) {
  206.                                 zzreplstr("zzaRet");
  207.                             }
  208.                             else if ( CurRetDef != NULL ) {
  209.                                 if ( strmember(CurRetDef, &zzbegexpr[1]) ) {
  210.                                     if ( HasComma( CurRetDef ) ) {
  211.                                         require (strlen(zzbegexpr)<=285,
  212.                                                  "$retval attrib ref too big");
  213.                                         sprintf(buf,"_retv.%s",&zzbegexpr[1]);
  214.                                         zzreplstr(buf);
  215.                                     }
  216.                                     else zzreplstr("_retv");
  217.                                 }
  218.                                 else if ( CurParmDef != NULL ) {
  219.                                     if ( !strmember(CurParmDef, &zzbegexpr[1]) )
  220.                                         warn(eMsg1("$%s not parameter or return value",&zzbegexpr[1]));
  221.                                 }
  222.                                 else warn(eMsg1("$%s not parameter or return value",&zzbegexpr[1]));
  223.                             }
  224.                             }
  225.                             zzmore();
  226.                             >>
  227. #token "#0"                    << zzreplstr("(*_root)"); zzmore(); >>
  228. #token "#\[\]"                << zzreplstr("zzastnew()"); zzmore(); >>
  229. #token "#\(\)"                << zzreplstr("NULL"); zzmore(); >>
  230. #token "#[0-9]+"            <<{
  231.                             static char buf[100];
  232.                             if ( strlen(zzbegexpr)>85 )
  233.                                 fatal("#i AST ref too big");
  234.                             sprintf(buf,"zzastArg(%s)",zzbegexpr+1);
  235.                             zzreplstr(buf);
  236.                             zzmore();
  237.                             }
  238.                             >>
  239. #token "#\["                <<
  240.                             pushint(']');
  241.                             zzreplstr("zzmk_ast(zzastnew(),");
  242.                             zzmore();
  243.                             >>
  244. #token "#\("                <<
  245.                             pushint('}');
  246.                             zzreplstr("zztmake(");
  247.                             zzmore();
  248.                             >>
  249. #token "#"                    << zzmore(); >>
  250. #token "\)"                    <<
  251.                             if ( istackempty() )
  252.                                 zzmore();
  253.                             else if ( topint()==')' ) {
  254.                                 popint();
  255.                             }
  256.                             else if ( topint()=='}' ) {
  257.                                 popint();
  258.                                 /* terminate #(..) */
  259.                                 zzreplstr(", NULL)");
  260.                             }
  261.                             zzmore();
  262.                             >>
  263. #token "\["                    <<
  264.                             pushint('|');    /* look for '|' to terminate simple [...] */
  265.                             zzmore();
  266.                             >>
  267. #token "\("                    <<
  268.                             pushint(')');
  269.                             zzmore();
  270.                             >>
  271. #token "\\\]"                << zzreplstr("]");  zzmore(); >>
  272. #token "\\\)"                << zzreplstr(")");  zzmore(); >>
  273. #token "\\>"                << zzreplstr(">");  zzmore(); >>
  274. #token "\\$"                << zzreplstr("$");  zzmore(); >>
  275. #token "\\#"                << zzreplstr("#");  zzmore(); >>
  276. #token "\\\\"                << zzmore(); >> /* need this for some reason */
  277. #token "\\~[\]\)>$#\\]"        << zzmore(); >> /* escaped char, always ignore */
  278. #token "~[\n\)\(\\$#\>\]\[]+" << zzmore(); >>
  279.  
  280. #lexclass START
  281. #token "[\t\ ]+"            << zzskip(); >>                /* Ignore White */
  282. #token "[\n\r]"                << zzline++; zzskip(); >>    /* Track Line # */
  283. #token "\["                 << zzmode(ACTIONS); zzmore();
  284.                                istackreset();
  285.                                pushint(']'); >>
  286. #token "\<\<"               << action_file=CurFile; action_line=zzline;
  287.                                zzmode(ACTIONS); zzmore();
  288.                                istackreset();
  289.                                pushint('>'); >>
  290. #token "\""                    << zzmode(STRINGS); zzmore(); >>
  291. #token "/\*"                << zzmode(COMMENTS); zzskip(); >>
  292. #token "\*/"                << warn("Missing /*; found dangling */"); zzskip(); >>
  293. #token "\>\>"                << warn("Missing <<; found dangling \\>\\>"); zzskip(); >>
  294. #token Eof                    "@"
  295.                             <<    /* L o o k  F o r  A n o t h e r  F i l e */
  296.                             {
  297.                             FILE *new_input;
  298.                             new_input = NextFile();
  299.                             if ( new_input == NULL ) return;
  300.                             fclose( input );
  301.                             input = new_input;
  302.                             zzrdstream( input );
  303.                             /*zzadvance();    /* Get 1st char of this file */
  304.                             zzskip();    /* Skip the Eof (@) char i.e continue */
  305.                             }
  306.                             >>
  307.  
  308. /*
  309.  * Get a grammar -- Build a list of rules like:
  310.  *
  311.  *    o-->Rule1--o
  312.  *    |
  313.  *    o-->Rule2--o
  314.  *    |
  315.  *    ...
  316.  *    |
  317.  *    o-->RuleN--o
  318.  */
  319. grammar :    <<Graph g;>>
  320.             {    "#header" Action
  321.                 <<
  322.                 HdrAction = calloc(strlen(LATEXT(1))+1, sizeof(char));
  323.                 require(HdrAction!=NULL, "rule grammar: cannot allocate header action");
  324.                 strcpy(HdrAction, LATEXT(1));
  325.                 >>
  326.             }
  327.             (    <<char *a;>>
  328.                 Action
  329.                 <<
  330.                 a = calloc(strlen(LATEXT(1))+1, sizeof(char));
  331.                 require(a!=NULL, "rule grammar: cannot allocate action");
  332.                 strcpy(a, LATEXT(1));
  333.                 list_add(&BeforeActions, a);
  334.                 >>
  335.             |    laction
  336.             |    aLexclass
  337.             |    token
  338.             |    error
  339.             )*
  340.             rule        <<g=$3; SynDiag = (Junction *) $3.left;>>
  341.             (    rule    <<if ( $1.left!=NULL ) {g.right = NULL; g = Or(g, $1);}>>
  342.             |    aLexclass
  343.             |    token
  344.             |    error
  345.             )*
  346.             (    <<char *a;>>
  347.                 Action
  348.                 <<
  349.                 a = calloc(strlen(LATEXT(1))+1, sizeof(char));
  350.                 require(a!=NULL, "rule grammar: cannot allocate action");
  351.                 strcpy(a, LATEXT(1));
  352.                 list_add(&AfterActions, a);
  353.                 >>
  354.             |    laction
  355.             |    error
  356.             )*
  357.             Eof
  358.         ;
  359.         <<CannotContinue=TRUE;>>
  360.  
  361. /*
  362.  * Build -o-->o-R-o-->o-    where -o-R-o- is the block from rule 'block'.
  363.  * Construct the RuleBlk front and EndRule node on the end of the
  364.  * block.  This is used to add FOLLOW pointers to the rule end.  Add the
  365.  * new rule name to the Rname hash table and sets its rulenum.
  366.  * Store the parameter definitions if any are found.
  367.  *
  368.  * Note that locks are required on the RuleBlk and EndRule nodes to thwart
  369.  * infinite recursion.
  370.  *
  371.  * Return the left graph pointer == NULL to indicate error/dupl rule def.
  372.  */
  373. rule    :    <<RuleEntry *q; Junction *p; Graph r; int f, l; ECnode *e;
  374.               char *pdecl=NULL, *ret=NULL, *a;>>
  375.             NonTerminal
  376.             <<q=NULL;
  377.               if ( hash_get(Rname, LATEXT(1))!=NULL ) {
  378.                   warn(eMsg1("duplicate rule definition: '%s'",LATEXT(1)))
  379.                   CannotContinue=TRUE;
  380.               }
  381.               else
  382.               {
  383.                     q = (RuleEntry *)hash_add(Rname,
  384.                                         LATEXT(1),
  385.                                         (Entry *)newRuleEntry(LATEXT(1)));
  386.                   CurRule = q->str;
  387.               }
  388.               CurRuleNode = q;
  389.               f = CurFile; l = zzline;
  390.               NumRules++;
  391.             >>
  392.             {    "!"   <<if ( q!=NULL ) q->noAST = TRUE;>> }
  393.             {    <<;>>
  394.                 {"\<"}
  395.                 PassAction
  396.                 <<    pdecl = calloc(strlen(LATEXT(1))+1, sizeof(char));
  397.                     require(pdecl!=NULL, "rule rule: cannot allocate param decl");
  398.                     strcpy(pdecl, LATEXT(1));
  399.                     CurParmDef = pdecl;
  400.                 >>
  401.             }
  402.             {    "\>"
  403.                 PassAction
  404.                 <<    ret = calloc(strlen(LATEXT(1))+1, sizeof(char));
  405.                     require(ret!=NULL, "rule rule: cannot allocate ret type");
  406.                     strcpy(ret, LATEXT(1));
  407.                     CurRetDef = ret;
  408.                 >>
  409.             }
  410.             { QuotedTerm <<if ( q!=NULL ) q->egroup=strdup(LATEXT(1));>> }
  411.             <<
  412.             if ( GenEClasseForRules && q!=NULL ) {
  413.                 e = newECnode;
  414.                 require(e!=NULL, "cannot allocate error class node");
  415.                 if ( q->egroup == NULL ) {a = q->str; a[0] = toupper(a[0]);}
  416.                 else a = q->egroup;
  417.                 if ( Tnum( a ) == 0 )
  418.                 {
  419.                     e->tok = addTname( a );
  420.                     list_add(&eclasses, (char *)e);
  421.                     if ( q->egroup == NULL ) a[0] = tolower(a[0]);
  422.                     /* refers to itself */
  423.                     list_add(&(e->elist), strdup(q->str));
  424.                 }
  425.                 else {
  426.                     warn(eMsg1("default errclass for '%s' would conflict with token/errclass",a));
  427.                     if ( q->egroup == NULL ) a[0] = tolower(a[0]);
  428.                     free(e);
  429.                 }
  430.             }
  431.             >>
  432.             <<BlkLevel++;>>
  433.             ":" block        <<r = makeBlk($7);
  434.                               ((Junction *)r.left)->jtype = RuleBlk;
  435.                               if ( q!=NULL ) ((Junction *)r.left)->rname = q->str;
  436.                               ((Junction *)r.left)->file = f;
  437.                               ((Junction *)r.left)->line = l;
  438.                               ((Junction *)r.left)->pdecl = pdecl;
  439.                               ((Junction *)r.left)->ret = ret;
  440.                               ((Junction *)r.left)->lock = makelocks();
  441.                               ((Junction *)r.left)->pred_lock = makelocks();
  442.                               p = newJunction();    /* add EndRule Node */
  443.                               ((Junction *)r.right)->p1 = (Node *)p;
  444.                               r.right = (Node *) p;
  445.                               p->jtype = EndRule;
  446.                               p->lock = makelocks();
  447.                               p->pred_lock = makelocks();
  448.                               ((Junction *)r.left)->end = p;
  449.                               if ( q!=NULL ) q->rulenum = NumRules;
  450.                               $7 = r;
  451.                             >>
  452.             <<--BlkLevel;>>
  453.             ";"
  454.             {    Action
  455.                 <<    a = calloc(strlen(LATEXT(1))+1, sizeof(char));
  456.                     require(a!=NULL, "rule rule: cannot allocate error action");
  457.                     strcpy(a, LATEXT(1));
  458.                     ((Junction *)r.left)->erraction = a;
  459.                 >>
  460.             }
  461.             <<if ( q==NULL ) $0.left = NULL; else $0 = $7;>>
  462.             <<CurRuleNode = NULL;>>
  463.         ;
  464.         <<CannotContinue=TRUE;>>
  465.  
  466. laction    :    <<char *a;>>
  467.             "#lexaction"
  468.             Action
  469.             <<
  470.             a = calloc(strlen(LATEXT(1))+1, sizeof(char));
  471.             require(a!=NULL, "rule laction: cannot allocate action");
  472.             strcpy(a, LATEXT(1));
  473.             list_add(&LexActions, a);
  474.             >>
  475.         ;
  476.  
  477. aLexclass:    "#lexclass" TokenTerm <<lexclass(strdup(LATEXT(1)));>>
  478.         ;
  479.  
  480. error    :    <<char *t=NULL; ECnode *e; int go=1; TermEntry *p;>>
  481.             "#errclass"
  482.             (<<;>>    TokenTerm  <<t=strdup(LATEXT(1));>>
  483.             |        QuotedTerm <<t=strdup(LATEXT(1));>>
  484.             )
  485.             <<e = newECnode;
  486.               require(e!=NULL, "cannot allocate error class node");
  487.               e->lexclass = CurrentLexClass;
  488.               if ( Tnum( (t=StripQuotes(t)) ) == 0 )
  489.               {
  490.                 if ( hash_get(Texpr, t) != NULL )
  491.                     warn(eMsg1("errclass name conflicts with regular expression  '%s'",t));
  492.                   e->tok = addTname( t );
  493.                 require((p=(TermEntry *)hash_get(Tname, t)) != NULL,
  494.                         "hash table mechanism is broken");
  495.                 p->errclassname = 1;    /* entry is errclass name, not token */
  496.                 list_add(&eclasses, (char *)e);
  497.               }
  498.               else
  499.               {
  500.                   warn(eMsg1("redefinition of errclass or conflict w/token '%s'; ignored",t));
  501.                 free( e );
  502.                 go=0;
  503.               }
  504.             >>
  505.             "\{"
  506.                 ( NonTerminal <<if ( go ) t=strdup(LATEXT(1));>>
  507.                 | TokenTerm <<if ( go ) t=strdup(LATEXT(1));>>
  508.                 | QuotedTerm <<if ( go ) t=strdup(LATEXT(1));>>
  509.                 )
  510.                 <<if ( go ) list_add(&(e->elist), t);>>
  511.                 (
  512.                     ( NonTerminal <<if ( go ) t=strdup(LATEXT(1));>>
  513.                     | TokenTerm <<if ( go ) t=strdup(LATEXT(1));>>
  514.                     | QuotedTerm <<if ( go ) t=strdup(LATEXT(1));>>
  515.                     )
  516.                     <<if ( go ) list_add(&(e->elist), t);>>
  517.                 )*
  518.             "\}"
  519.         ;
  520.  
  521. token    :    <<char *t=NULL, *e=NULL, *a=NULL;>>
  522.             "#token"
  523.             { TokenTerm  <<t=strdup(LATEXT(1));>> }
  524.             { QuotedTerm <<e=strdup(LATEXT(1));>> }
  525.             {    Action
  526.                 <<
  527.                     a = calloc(strlen(LATEXT(1))+1, sizeof(char));
  528.                     require(a!=NULL, "rule token: cannot allocate action");
  529.                     strcpy(a, LATEXT(1));
  530.                 >>
  531.             }
  532.             <<chkToken(t, e, a);>>
  533.         ;
  534.         <<CannotContinue=TRUE;>>
  535.  
  536. block    :    <<Graph g, b;>>
  537.             alt                <<b = g = $1;>>
  538.             <<
  539.             if ( ((Junction *)g.left)->p1->ntype == nAction )
  540.             {
  541.                 if ( !((ActionNode *)(((Junction *)g.left)->p1))->is_predicate )
  542.                 {
  543.                     ((ActionNode *)(((Junction *)g.left)->p1))->init_action = TRUE;
  544.                 }
  545.             }
  546.             >>
  547.             (    "\|"
  548.                 alt            <<g = Or(g, $2);>>
  549.             )*
  550.             <<$0 = b;>>
  551.         ;
  552.         <<CannotContinue=TRUE;>>
  553.  
  554. alt        :    <<int n=0; Graph g; g.left=g.right=NULL;>>
  555.             (    element     <<n++; g = Cat(g, $1);>>
  556.             )*
  557.             <<if ( n == 0 ) g = emptyAlt();
  558.               $0 = g;
  559.             >>
  560.         ;
  561.         <<CannotContinue=TRUE;>>
  562.  
  563. element    :    <<TokNode *p; RuleRefNode *q;>>
  564.             TokenTerm
  565.             <<$0 = buildToken(LATEXT(1));>>
  566.             (    <<p = (TokNode *) ((Junction *)$$.left)->p1;>>
  567.                 "^"    <<p->astnode=ASTroot;>>
  568.             |        <<p->astnode=ASTchild;>>
  569.             |    "!" <<p->astnode=ASTexclude;>>
  570.             )
  571.         |    QuotedTerm
  572.             <<$0 = buildToken(LATEXT(1));>>    
  573.             (    <<p = (TokNode *) ((Junction *)$$.left)->p1;>>
  574.                 "^"    <<p->astnode=ASTroot;>>
  575.             |        <<p->astnode=ASTchild;>>
  576.             |    "!" <<p->astnode=ASTexclude;>>
  577.             )
  578.         |    NonTerminal
  579.             <<$0 = buildRuleRef(LATEXT(1));>>
  580.             { "!" <<q = (RuleRefNode *) ((Junction *)$$.left)->p1;
  581.                     q->astnode=ASTexclude;>>
  582.             }
  583.             {    {"\<"}
  584.                 PassAction <<addParm(((Junction *)$$.left)->p1, LATEXT(1));>>
  585.             }
  586.             {    <<char *a; RuleRefNode *rr=(RuleRefNode *) ((Junction *)$$.left)->p1;
  587.                   >>
  588.                 "\>"
  589.                 PassAction
  590.                 <<
  591.                     a = calloc(strlen(LATEXT(1))+1, sizeof(char));
  592.                     require(a!=NULL, "rule element: cannot allocate assignment");
  593.                     strcpy(a, LATEXT(1));
  594.                     rr->assign = a;
  595.                 >>
  596.             }
  597.         |    Action <<$0 = buildAction(LATEXT(1),action_file,action_line, 0);>>
  598.         |    Pred   <<$0 = buildAction(LATEXT(1),action_file,action_line, 1);>>
  599.             {    <<char *a; ActionNode *act = (ActionNode *) ((Junction *)$$.left)->p1;>>
  600.                 PassAction
  601.                 <<
  602.                 a = calloc(strlen(LATEXT(1))+1, sizeof(char));
  603.                 require(a!=NULL, "rule element: cannot allocate predicate fail action");
  604.                 strcpy(a, LATEXT(1));
  605.                 act->pred_fail = a;
  606.                 >>
  607.             }
  608.         |    <<BlkLevel++;>> "\(" block <<$0 = $2; --BlkLevel;>> "\)"
  609.             (    "\*"        <<$$ = makeLoop($$);>>
  610.             |    "\+"        <<$$ = makePlus($$);>>
  611.             |                <<$$ = makeBlk($$);>>
  612.             )
  613.             { PassAction <<addParm(((Junction *)$$.left)->p1, LATEXT(1));>> }
  614.         |    <<BlkLevel++;>> "\{" block <<$0 = makeOpt($2); --BlkLevel;>> "\}"
  615.             { PassAction <<addParm(((Junction *)$$.left)->p1, LATEXT(1));>> }
  616.         |    ":"        <<warn(eMsg1("missing ';' on rule %s", CurRule));
  617.                       CannotContinue=TRUE;>>
  618.         |    "\*"    <<warn("don't you want a ')' with that '*'?"); CannotContinue=TRUE;>>
  619.         |    "\+"    <<warn("don't you want a ')' with that '+'?"); CannotContinue=TRUE;>>
  620.         |    "\>"    <<warn("'>' can only appear after a nonterminal"); CannotContinue=TRUE;>>
  621.         |    PassAction <<warn("[...] out of context 'rule > [...]'");
  622.                          CannotContinue=TRUE;>>
  623.         ;
  624.         <<CannotContinue=TRUE;>>
  625.  
  626. #token NonTerminal        "[a-z] [A-Za-z0-9_]*"
  627. #token TokenTerm        "[A-Z] [A-Za-z0-9_]*"
  628. #token "#[A-Za-z0-9_]*"    <<warn(eMsg1("unknown meta-op: %s",LATEXT(1))); zzskip(); >>
  629.  
  630. <<
  631. /* semantics of #token */
  632. static void
  633. chkToken(t,e,a)
  634. char *t, *e, *a;
  635. {
  636.     if ( t==NULL && e==NULL ) {            /* none found */
  637.         warn("#token requires at least token name or rexpr");
  638.     }
  639.     else if ( t!=NULL && e!=NULL ) {    /* both found */
  640.         Tlink(t, e);
  641.         if ( a!=NULL ) {
  642.             if ( hasAction(e) ) {
  643.                 warn(eMsg1("redefinition of action for %s; ignored",e));
  644.             }
  645.             else setHasAction(e, a);
  646.         }
  647.     }
  648.     else if ( t!=NULL ) {                /* only one found */
  649.         if ( Tnum( t ) == 0 ) addTname( t );
  650.         else {
  651.             warn(eMsg1("redefinition of token %s; ignored",t));
  652.         }
  653.         if ( a!=NULL ) {
  654.             warn(eMsg1("action cannot be attached to a token name (%s); ignored",t));
  655.         }
  656.     }
  657.     else if ( e!=NULL ) {
  658.         if ( Tnum( e ) == 0 ) addTexpr( e );
  659.         else {
  660.             if ( hasAction(e) ) {
  661.                 warn(eMsg1("redefinition of action for %s; ignored",e));
  662.             }
  663.             else if ( a==NULL ) {
  664.                 warn(eMsg1("redefinition of expr %s; ignored",e));
  665.             }
  666.         }
  667.         if ( a!=NULL ) setHasAction(e, a);
  668.     }
  669. }
  670. >>
  671.