home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Trees / V7 / usr / src / cmd / yacc / y2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1979-01-10  |  18.5 KB  |  860 lines

  1. # include "dextern"
  2. # define IDENTIFIER 257
  3. # define MARK 258
  4. # define TERM 259
  5. # define LEFT 260
  6. # define RIGHT 261
  7. # define BINARY 262
  8. # define PREC 263
  9. # define LCURLY 264
  10. # define C_IDENTIFIER 265  /* name followed by colon */
  11. # define NUMBER 266
  12. # define START 267
  13. # define TYPEDEF 268
  14. # define TYPENAME 269
  15. # define UNION 270
  16. # define ENDFILE 0
  17.  
  18.     /* communication variables between various I/O routines */
  19.  
  20. char *infile;    /* input file name */
  21. int numbval;    /* value of an input number */
  22. char tokname[NAMESIZE];    /* input token name */
  23.  
  24.     /* storage of names */
  25.  
  26. char cnames[CNAMSZ];    /* place where token and nonterminal names are stored */
  27. int cnamsz = CNAMSZ;    /* size of cnames */
  28. char * cnamp = cnames;    /* place where next name is to be put in */
  29. int ndefout = 3;  /* number of defined symbols output */
  30.  
  31.     /* storage of types */
  32. int ntypes;    /* number of types defined */
  33. char * typeset[NTYPES];    /* pointers to type tags */
  34.  
  35.     /* symbol tables for tokens and nonterminals */
  36.  
  37. int ntokens = 0;
  38. struct toksymb tokset[NTERMS];
  39. int toklev[NTERMS];
  40. int nnonter = -1;
  41. struct ntsymb nontrst[NNONTERM];
  42. int start;    /* start symbol */
  43.  
  44.     /* assigned token type values */
  45. int extval = 0;
  46.  
  47.     /* input and output file descriptors */
  48.  
  49. FILE * finput;        /* yacc input file */
  50. FILE * faction;        /* file for saving actions */
  51. FILE * fdefine;        /* file for # defines */
  52. FILE * ftable;        /* y.tab.c file */
  53. FILE * ftemp;        /* tempfile to pass 2 */
  54. FILE * foutput;        /* y.output file */
  55.  
  56.     /* storage for grammar rules */
  57.  
  58. int mem0[MEMSIZE] ; /* production storage */
  59. int *mem = mem0;
  60. int nprod= 1;    /* number of productions */
  61. int *prdptr[NPROD];    /* pointers to descriptions of productions */
  62. int levprd[NPROD] ;    /* precedence levels for the productions */
  63.  
  64.  
  65. setup(argc,argv) int argc; char *argv[];
  66. {    int i,j,lev,t, ty;
  67.     int c;
  68.     int *p;
  69.     char actname[8];
  70.  
  71.     foutput = NULL;
  72.     fdefine = NULL;
  73.     i = 1;
  74.     while( argc >= 2  && argv[1][0] == '-' ) {
  75.         while( *++(argv[1]) ){
  76.             switch( *argv[1] ){
  77.             case 'v':
  78.             case 'V':
  79.                 foutput = fopen(FILEU, "w" );
  80.                 if( foutput == NULL ) error( "cannot open y.output" );
  81.                 continue;
  82.             case 'D':
  83.             case 'd':
  84.                 fdefine = fopen( FILED, "w" );
  85.                 continue;
  86.             case 'o':
  87.             case 'O':
  88.                 fprintf( stderr, "`o' flag now default in yacc\n" );
  89.                 continue;
  90.  
  91.             case 'r':
  92.             case 'R':
  93.                 error( "Ratfor Yacc is dead: sorry...\n" );
  94.  
  95.             default:
  96.                 error( "illegal option: %c", *argv[1]);
  97.                 }
  98.             }
  99.         argv++;
  100.         argc--;
  101.         }
  102.  
  103.     ftable = fopen( OFILE, "w" );
  104.     if( ftable == NULL ) error( "cannot open table file" );
  105.  
  106.     ftemp = fopen( TEMPNAME, "w" );
  107.     faction = fopen( ACTNAME, "w" );
  108.     if( ftemp==NULL || faction==NULL ) error( "cannot open temp file" );
  109.  
  110.     if( argc < 2 || ((finput=fopen( infile=argv[1], "r" )) == NULL ) ){
  111.         error( "cannot open input file" );
  112.         }
  113.  
  114.     cnamp = cnames;
  115.     defin(0,"$end");
  116.     extval = 0400;
  117.     defin(0,"error");
  118.     defin(1,"$accept");
  119.     mem=mem0;
  120.     lev = 0;
  121.     ty = 0;
  122.     i=0;
  123.  
  124.     /* sorry -- no yacc parser here.....
  125.         we must bootstrap somehow... */
  126.  
  127.     for( t=gettok();  t!=MARK && t!= ENDFILE; ){
  128.         switch( t ){
  129.  
  130.         case ';':
  131.             t = gettok();
  132.             break;
  133.  
  134.         case START:
  135.             if( (t=gettok()) != IDENTIFIER ){
  136.                 error( "bad %%start construction" );
  137.                 }
  138.             start = chfind(1,tokname);
  139.             t = gettok();
  140.             continue;
  141.  
  142.         case TYPEDEF:
  143.             if( (t=gettok()) != TYPENAME ) error( "bad syntax in %%type" );
  144.             ty = numbval;
  145.             for(;;){
  146.                 t = gettok();
  147.                 switch( t ){
  148.  
  149.                 case IDENTIFIER:
  150.                     if( (t=chfind( 1, tokname ) ) < NTBASE ) {
  151.                         j = TYPE( toklev[t] );
  152.                         if( j!= 0 && j != ty ){
  153.                             error( "type redeclaration of token %s",
  154.                                 tokset[t].name );
  155.                             }
  156.                         else SETTYPE( toklev[t],ty);
  157.                         }
  158.                     else {
  159.                         j = nontrst[t-NTBASE].tvalue;
  160.                         if( j != 0 && j != ty ){
  161.                             error( "type redeclaration of nonterminal %s",
  162.                                 nontrst[t-NTBASE].name );
  163.                             }
  164.                         else nontrst[t-NTBASE].tvalue = ty;
  165.                         }
  166.                 case ',':
  167.                     continue;
  168.  
  169.                 case ';':
  170.                     t = gettok();
  171.                     break;
  172.                 default:
  173.                     break;
  174.                     }
  175.                 break;
  176.                 }
  177.             continue;
  178.  
  179.         case UNION:
  180.             /* copy the union declaration to the output */
  181.             cpyunion();
  182.             t = gettok();
  183.             continue;
  184.  
  185.         case LEFT:
  186.         case BINARY:
  187.         case RIGHT:
  188.             ++i;
  189.         case TERM:
  190.             lev = t-TERM;  /* nonzero means new prec. and assoc. */
  191.             ty = 0;
  192.  
  193.             /* get identifiers so defined */
  194.  
  195.             t = gettok();
  196.             if( t == TYPENAME ){ /* there is a type defined */
  197.                 ty = numbval;
  198.                 t = gettok();
  199.                 }
  200.  
  201.             for(;;) {
  202.                 switch( t ){
  203.  
  204.                 case ',':
  205.                     t = gettok();
  206.                     continue;
  207.  
  208.                 case ';':
  209.                     break;
  210.  
  211.                 case IDENTIFIER:
  212.                     j = chfind(0,tokname);
  213.                     if( lev ){
  214.                         if( ASSOC(toklev[j]) ) error( "redeclaration of precedence of %s", tokname );
  215.                         SETASC(toklev[j],lev);
  216.                         SETPLEV(toklev[j],i);
  217.                         }
  218.                     if( ty ){
  219.                         if( TYPE(toklev[j]) ) error( "redeclaration of type of %s", tokname );
  220.                         SETTYPE(toklev[j],ty);
  221.                         }
  222.                     if( (t=gettok()) == NUMBER ){
  223.                         tokset[j].value = numbval;
  224.                         if( j < ndefout && j>2 ){
  225.                             error( "please define type number of %s earlier",
  226.                                 tokset[j].name );
  227.                             }
  228.                         t=gettok();
  229.                         }
  230.                     continue;
  231.  
  232.                     }
  233.  
  234.                 break;
  235.                 }
  236.  
  237.             continue;
  238.  
  239.         case LCURLY:
  240.             defout();
  241.             cpycode();
  242.             t = gettok();
  243.             continue;
  244.  
  245.         default:
  246.             error( "syntax error" );
  247.  
  248.             }
  249.  
  250.         }
  251.  
  252.     if( t == ENDFILE ){
  253.         error( "unexpected EOF before %%" );
  254.         }
  255.  
  256.     /* t is MARK */
  257.  
  258.     defout();
  259.  
  260.         fprintf( ftable,  "#define yyclearin yychar = -1\n" );
  261.         fprintf( ftable,  "#define yyerrok yyerrflag = 0\n" );
  262.         fprintf( ftable,  "extern int yychar;\nextern short yyerrflag;\n" );
  263.         fprintf( ftable,  "#ifndef YYMAXDEPTH\n#define YYMAXDEPTH 150\n#endif\n" );
  264.         if( !ntypes ) fprintf( ftable,  "#ifndef YYSTYPE\n#define YYSTYPE int\n#endif\n" );
  265.         fprintf( ftable,  "YYSTYPE yylval, yyval;\n" );
  266.  
  267.     prdptr[0]=mem;
  268.     /* added production */
  269.     *mem++ = NTBASE;
  270.     *mem++ = start;  /* if start is 0, we will overwrite with the lhs of the first rule */
  271.     *mem++ = 1;
  272.     *mem++ = 0;
  273.     prdptr[1]=mem;
  274.  
  275.     while( (t=gettok()) == LCURLY ) cpycode();
  276.  
  277.     if( t != C_IDENTIFIER ) error( "bad syntax on first rule" );
  278.  
  279.     if( !start ) prdptr[0][1] = chfind(1,tokname);
  280.  
  281.     /* read rules */
  282.  
  283.     while( t!=MARK && t!=ENDFILE ){
  284.  
  285.         /* process a rule */
  286.  
  287.         if( t == '|' ){
  288.             *mem++ = *prdptr[nprod-1];
  289.             }
  290.         else if( t == C_IDENTIFIER ){
  291.             *mem = chfind(1,tokname);
  292.             if( *mem < NTBASE ) error( "token illegal on LHS of grammar rule" );
  293.             ++mem;
  294.             }
  295.         else error( "illegal rule: missing semicolon or | ?" );
  296.  
  297.         /* read rule body */
  298.  
  299.  
  300.         t = gettok();
  301.     more_rule:
  302.         while( t == IDENTIFIER ) {
  303.             *mem = chfind(1,tokname);
  304.             if( *mem<NTBASE ) levprd[nprod] = toklev[*mem];
  305.             ++mem;
  306.             t = gettok();
  307.             }
  308.  
  309.  
  310.         if( t == PREC ){
  311.             if( gettok()!=IDENTIFIER) error( "illegal %%prec syntax" );
  312.             j = chfind(2,tokname);
  313.             if( j>=NTBASE)error("nonterminal %s illegal after %%prec", nontrst[j-NTBASE].name);
  314.             levprd[nprod]=toklev[j];
  315.             t = gettok();
  316.             }
  317.  
  318.         if( t == '=' ){
  319.             levprd[nprod] |= ACTFLAG;
  320.             fprintf( faction, "\ncase %d:", nprod );
  321.             cpyact( mem-prdptr[nprod]-1 );
  322.             fprintf( faction, " break;" );
  323.             if( (t=gettok()) == IDENTIFIER ){
  324.                 /* action within rule... */
  325.  
  326.                 sprintf( actname, "$$%d", nprod );
  327.                 j = chfind(1,actname);  /* make it a nonterminal */
  328.  
  329.                 /* the current rule will become rule number nprod+1 */
  330.                 /* move the contents down, and make room for the null */
  331.  
  332.                 for( p=mem; p>=prdptr[nprod]; --p ) p[2] = *p;
  333.                 mem += 2;
  334.  
  335.                 /* enter null production for action */
  336.  
  337.                 p = prdptr[nprod];
  338.  
  339.                 *p++ = j;
  340.                 *p++ = -nprod;
  341.  
  342.                 /* update the production information */
  343.  
  344.                 levprd[nprod+1] = levprd[nprod] & ~ACTFLAG;
  345.                 levprd[nprod] = ACTFLAG;
  346.  
  347.                 if( ++nprod >= NPROD ) error( "more than %d rules", NPROD );
  348.                 prdptr[nprod] = p;
  349.  
  350.                 /* make the action appear in the original rule */
  351.                 *mem++ = j;
  352.  
  353.                 /* get some more of the rule */
  354.  
  355.                 goto more_rule;
  356.                 }
  357.  
  358.             }
  359.  
  360.         while( t == ';' ) t = gettok();
  361.  
  362.         *mem++ = -nprod;
  363.  
  364.         /* check that default action is reasonable */
  365.  
  366.         if( ntypes && !(levprd[nprod]&ACTFLAG) && nontrst[*prdptr[nprod]-NTBASE].tvalue ){
  367.             /* no explicit action, LHS has value */
  368.             register tempty;
  369.             tempty = prdptr[nprod][1];
  370.             if( tempty < 0 ) error( "must return a value, since LHS has a type" );
  371.             else if( tempty >= NTBASE ) tempty = nontrst[tempty-NTBASE].tvalue;
  372.             else tempty = TYPE( toklev[tempty] );
  373.             if( tempty != nontrst[*prdptr[nprod]-NTBASE].tvalue ){
  374.                 error( "default action causes potential type clash" );
  375.                 }
  376.             }
  377.  
  378.         if( ++nprod >= NPROD ) error( "more than %d rules", NPROD );
  379.         prdptr[nprod] = mem;
  380.         levprd[nprod]=0;
  381.  
  382.         }
  383.  
  384.     /* end of all rules */
  385.  
  386.     finact();
  387.     if( t == MARK ){
  388.         fprintf( ftable, "\n# line %d \"%s\"\n", lineno, infile );
  389.         while( (c=getc(finput)) != EOF ) putc( c, ftable );
  390.         }
  391.     fclose( finput );
  392.     }
  393.  
  394. finact(){
  395.     /* finish action routine */
  396.  
  397.     fclose(faction);
  398.  
  399.     fprintf( ftable, "# define YYERRCODE %d\n", tokset[2].value );
  400.  
  401.     }
  402.  
  403. defin( t, s ) register char  *s; {
  404. /*    define s to be a terminal if t=0
  405.     or a nonterminal if t=1        */
  406.  
  407.     register val;
  408.  
  409.     if (t) {
  410.         if( ++nnonter >= NNONTERM ) error("too many nonterminals, limit %d",NNONTERM);
  411.         nontrst[nnonter].name = cstash(s);
  412.         return( NTBASE + nnonter );
  413.         }
  414.     /* must be a token */
  415.     if( ++ntokens >= NTERMS ) error("too many terminals, limit %d",NTERMS );
  416.     tokset[ntokens].name = cstash(s);
  417.  
  418.     /* establish value for token */
  419.  
  420.     if( s[0]==' ' && s[2]=='\0' ) /* single character literal */
  421.         val = s[1];
  422.     else if ( s[0]==' ' && s[1]=='\\' ) { /* escape sequence */
  423.         if( s[3] == '\0' ){ /* single character escape sequence */
  424.             switch ( s[2] ){
  425.                      /* character which is escaped */
  426.             case 'n': val = '\n'; break;
  427.             case 'r': val = '\r'; break;
  428.             case 'b': val = '\b'; break;
  429.             case 't': val = '\t'; break;
  430.             case 'f': val = '\f'; break;
  431.             case '\'': val = '\''; break;
  432.             case '"': val = '"'; break;
  433.             case '\\': val = '\\'; break;
  434.             default: error( "invalid escape" );
  435.                 }
  436.             }
  437.         else if( s[2] <= '7' && s[2]>='0' ){ /* \nnn sequence */
  438.             if( s[3]<'0' || s[3] > '7' || s[4]<'0' ||
  439.                 s[4]>'7' || s[5] != '\0' ) error("illegal \\nnn construction" );
  440.             val = 64*s[2] + 8*s[3] + s[4] - 73*'0';
  441.             if( val == 0 ) error( "'\\000' is illegal" );
  442.             }
  443.         }
  444.     else {
  445.         val = extval++;
  446.         }
  447.     tokset[ntokens].value = val;
  448.     toklev[ntokens] = 0;
  449.     return( ntokens );
  450.     }
  451.  
  452. defout(){ /* write out the defines (at the end of the declaration section) */
  453.  
  454.     register int i, c;
  455.     register char *cp;
  456.  
  457.     for( i=ndefout; i<=ntokens; ++i ){
  458.  
  459.         cp = tokset[i].name;
  460.         if( *cp == ' ' ) ++cp;  /* literals */
  461.  
  462.         for( ; (c= *cp)!='\0'; ++cp ){
  463.  
  464.             if( islower(c) || isupper(c) || isdigit(c) || c=='_' );  /* VOID */
  465.             else goto nodef;
  466.             }
  467.  
  468.         fprintf( ftable, "# define %s %d\n", tokset[i].name, tokset[i].value );
  469.         if( fdefine != NULL ) fprintf( fdefine, "# define %s %d\n", tokset[i].name, tokset[i].value );
  470.  
  471.     nodef:    ;
  472.         }
  473.  
  474.     ndefout = ntokens+1;
  475.  
  476.     }
  477.  
  478. char *
  479. cstash( s ) register char *s; {
  480.     char *temp;
  481.  
  482.     temp = cnamp;
  483.     do {
  484.         if( cnamp >= &cnames[cnamsz] ) error("too many characters in id's and literals" );
  485.         else *cnamp++ = *s;
  486.         }  while ( *s++ );
  487.     return( temp );
  488.     }
  489.  
  490. gettok() {
  491.     register i, base;
  492.     static int peekline; /* number of '\n' seen in lookahead */
  493.     register c, match, reserve;
  494.  
  495. begin:
  496.     reserve = 0;
  497.     lineno += peekline;
  498.     peekline = 0;
  499.     c = getc(finput);
  500.     while( c==' ' || c=='\n' || c=='\t' || c=='\f' ){
  501.         if( c == '\n' ) ++lineno;
  502.         c=getc(finput);
  503.         }
  504.     if( c == '/' ){ /* skip comment */
  505.         lineno += skipcom();
  506.         goto begin;
  507.         }
  508.  
  509.     switch(c){
  510.  
  511.     case EOF:
  512.         return(ENDFILE);
  513.     case '{':
  514.         ungetc( c, finput );
  515.         return( '=' );  /* action ... */
  516.     case '<':  /* get, and look up, a type name (union member name) */
  517.         i = 0;
  518.         while( (c=getc(finput)) != '>' && c>=0 && c!= '\n' ){
  519.             tokname[i] = c;
  520.             if( ++i >= NAMESIZE ) --i;
  521.             }
  522.         if( c != '>' ) error( "unterminated < ... > clause" );
  523.         tokname[i] = '\0';
  524.         for( i=1; i<=ntypes; ++i ){
  525.             if( !strcmp( typeset[i], tokname ) ){
  526.                 numbval = i;
  527.                 return( TYPENAME );
  528.                 }
  529.             }
  530.         typeset[numbval = ++ntypes] = cstash( tokname );
  531.         return( TYPENAME );
  532.  
  533.     case '"':    
  534.     case '\'':
  535.         match = c;
  536.         tokname[0] = ' ';
  537.         i = 1;
  538.         for(;;){
  539.             c = getc(finput);
  540.             if( c == '\n' || c == EOF )
  541.                 error("illegal or missing ' or \"" );
  542.             if( c == '\\' ){
  543.                 c = getc(finput);
  544.                 tokname[i] = '\\';
  545.                 if( ++i >= NAMESIZE ) --i;
  546.                 }
  547.             else if( c == match ) break;
  548.             tokname[i] = c;
  549.             if( ++i >= NAMESIZE ) --i;
  550.             }
  551.         break;
  552.  
  553.     case '%':
  554.     case '\\':
  555.  
  556.         switch(c=getc(finput)) {
  557.  
  558.         case '0':    return(TERM);
  559.         case '<':    return(LEFT);
  560.         case '2':    return(BINARY);
  561.         case '>':    return(RIGHT);
  562.         case '%':
  563.         case '\\':    return(MARK);
  564.         case '=':    return(PREC);
  565.         case '{':    return(LCURLY);
  566.         default:    reserve = 1;
  567.             }
  568.  
  569.     default:
  570.  
  571.         if( isdigit(c) ){ /* number */
  572.             numbval = c-'0' ;
  573.             base = (c=='0') ? 8 : 10 ;
  574.             for( c=getc(finput); isdigit(c) ; c=getc(finput) ){
  575.                 numbval = numbval*base + c - '0';
  576.                 }
  577.             ungetc( c, finput );
  578.             return(NUMBER);
  579.             }
  580.         else if( islower(c) || isupper(c) || c=='_' || c=='.' || c=='$' ){
  581.             i = 0;
  582.             while( islower(c) || isupper(c) || isdigit(c) || c=='_' || c=='.' || c=='$' ){
  583.                 tokname[i] = c;
  584.                 if( reserve && isupper(c) ) tokname[i] += 'a'-'A';
  585.                 if( ++i >= NAMESIZE ) --i;
  586.                 c = getc(finput);
  587.                 }
  588.             }
  589.         else return(c);
  590.  
  591.         ungetc( c, finput );
  592.         }
  593.  
  594.     tokname[i] = '\0';
  595.  
  596.     if( reserve ){ /* find a reserved word */
  597.         if( !strcmp(tokname,"term")) return( TERM );
  598.         if( !strcmp(tokname,"token")) return( TERM );
  599.         if( !strcmp(tokname,"left")) return( LEFT );
  600.         if( !strcmp(tokname,"nonassoc")) return( BINARY );
  601.         if( !strcmp(tokname,"binary")) return( BINARY );
  602.         if( !strcmp(tokname,"right")) return( RIGHT );
  603.         if( !strcmp(tokname,"prec")) return( PREC );
  604.         if( !strcmp(tokname,"start")) return( START );
  605.         if( !strcmp(tokname,"type")) return( TYPEDEF );
  606.         if( !strcmp(tokname,"union")) return( UNION );
  607.         error("invalid escape, or illegal reserved word: %s", tokname );
  608.         }
  609.  
  610.     /* look ahead to distinguish IDENTIFIER from C_IDENTIFIER */
  611.  
  612.     c = getc(finput);
  613.     while( c==' ' || c=='\t'|| c=='\n' || c=='\f' || c== '/' ) {
  614.         if( c == '\n' ) ++peekline;
  615.         else if( c == '/' ){ /* look for comments */
  616.             peekline += skipcom();
  617.             }
  618.         c = getc(finput);
  619.         }
  620.     if( c == ':' ) return( C_IDENTIFIER );
  621.     ungetc( c, finput );
  622.     return( IDENTIFIER );
  623. }
  624.  
  625. fdtype( t ){ /* determine the type of a symbol */
  626.     register v;
  627.     if( t >= NTBASE ) v = nontrst[t-NTBASE].tvalue;
  628.     else v = TYPE( toklev[t] );
  629.     if( v <= 0 ) error( "must specify type for %s", (t>=NTBASE)?nontrst[t-NTBASE].name:
  630.             tokset[t].name );
  631.     return( v );
  632.     }
  633.  
  634. chfind( t, s ) register char *s; {
  635.     int i;
  636.  
  637.     if (s[0]==' ')t=0;
  638.     TLOOP(i){
  639.         if(!strcmp(s,tokset[i].name)){
  640.             return( i );
  641.             }
  642.         }
  643.     NTLOOP(i){
  644.         if(!strcmp(s,nontrst[i].name)) {
  645.             return( i+NTBASE );
  646.             }
  647.         }
  648.     /* cannot find name */
  649.     if( t>1 )
  650.         error( "%s should have been defined earlier", s );
  651.     return( defin( t, s ) );
  652.     }
  653.  
  654. cpyunion(){
  655.     /* copy the union declaration to the output, and the define file if present */
  656.  
  657.     int level, c;
  658.     fprintf( ftable, "\n# line %d \"%s\"\n", lineno, infile );
  659.     fprintf( ftable, "typedef union " );
  660.     if( fdefine ) fprintf( fdefine, "\ntypedef union " );
  661.  
  662.     level = 0;
  663.     for(;;){
  664.         if( (c=getc(finput)) < 0 ) error( "EOF encountered while processing %%union" );
  665.         putc( c, ftable );
  666.         if( fdefine ) putc( c, fdefine );
  667.  
  668.         switch( c ){
  669.  
  670.         case '\n':
  671.             ++lineno;
  672.             break;
  673.  
  674.         case '{':
  675.             ++level;
  676.             break;
  677.  
  678.         case '}':
  679.             --level;
  680.             if( level == 0 ) { /* we are finished copying */
  681.                 fprintf( ftable, " YYSTYPE;\n" );
  682.                 if( fdefine ) fprintf( fdefine, " YYSTYPE;\nextern YYSTYPE yylval;\n" );
  683.                 return;
  684.                 }
  685.             }
  686.         }
  687.     }
  688.  
  689. cpycode(){ /* copies code between \{ and \} */
  690.  
  691.     int c;
  692.     c = getc(finput);
  693.     if( c == '\n' ) {
  694.         c = getc(finput);
  695.         lineno++;
  696.         }
  697.     fprintf( ftable, "\n# line %d \"%s\"\n", lineno, infile );
  698.     while( c>=0 ){
  699.         if( c=='\\' )
  700.             if( (c=getc(finput)) == '}' ) return;
  701.             else putc('\\', ftable );
  702.         if( c=='%' )
  703.             if( (c=getc(finput)) == '}' ) return;
  704.             else putc('%', ftable );
  705.         putc( c , ftable );
  706.         if( c == '\n' ) ++lineno;
  707.         c = getc(finput);
  708.         }
  709.     error("eof before %%}" );
  710.     }
  711.  
  712. skipcom(){ /* skip over comments */
  713.     register c, i=0;  /* i is the number of lines skipped */
  714.  
  715.     /* skipcom is called after reading a / */
  716.  
  717.     if( getc(finput) != '*' ) error( "illegal comment" );
  718.     c = getc(finput);
  719.     while( c != EOF ){
  720.         while( c == '*' ){
  721.             if( (c=getc(finput)) == '/' ) return( i );
  722.             }
  723.         if( c == '\n' ) ++i;
  724.         c = getc(finput);
  725.         }
  726.     error( "EOF inside comment" );
  727.     /* NOTREACHED */
  728.     }
  729.  
  730. cpyact(offset){ /* copy C action to the next ; or closing } */
  731.     int brac, c, match, j, s, tok;
  732.  
  733.     fprintf( faction, "\n# line %d \"%s\"\n", lineno, infile );
  734.  
  735.     brac = 0;
  736.  
  737. loop:
  738.     c = getc(finput);
  739. swt:
  740.     switch( c ){
  741.  
  742. case ';':
  743.         if( brac == 0 ){
  744.             putc( c , faction );
  745.             return;
  746.             }
  747.         goto lcopy;
  748.  
  749. case '{':
  750.         brac++;
  751.         goto lcopy;
  752.  
  753. case '$':
  754.         s = 1;
  755.         tok = -1;
  756.         c = getc(finput);
  757.         if( c == '<' ){ /* type description */
  758.             ungetc( c, finput );
  759.             if( gettok() != TYPENAME ) error( "bad syntax on $<ident> clause" );
  760.             tok = numbval;
  761.             c = getc(finput);
  762.             }
  763.         if( c == '$' ){
  764.             fprintf( faction, "yyval");
  765.             if( ntypes ){ /* put out the proper tag... */
  766.                 if( tok < 0 ) tok = fdtype( *prdptr[nprod] );
  767.                 fprintf( faction, ".%s", typeset[tok] );
  768.                 }
  769.             goto loop;
  770.             }
  771.         if( c == '-' ){
  772.             s = -s;
  773.             c = getc(finput);
  774.             }
  775.         if( isdigit(c) ){
  776.             j=0;
  777.             while( isdigit(c) ){
  778.                 j= j*10+c-'0';
  779.                 c = getc(finput);
  780.                 }
  781.  
  782.             j = j*s - offset;
  783.             if( j > 0 ){
  784.                 error( "Illegal use of $%d", j+offset );
  785.                 }
  786.  
  787.             fprintf( faction, "yypvt[-%d]", -j );
  788.             if( ntypes ){ /* put out the proper tag */
  789.                 if( j+offset <= 0 && tok < 0 ) error( "must specify type of $%d", j+offset );
  790.                 if( tok < 0 ) tok = fdtype( prdptr[nprod][j+offset] );
  791.                 fprintf( faction, ".%s", typeset[tok] );
  792.                 }
  793.             goto swt;
  794.             }
  795.         putc( '$' , faction );
  796.         if( s<0 ) putc('-', faction );
  797.         goto swt;
  798.  
  799. case '}':
  800.         if( --brac ) goto lcopy;
  801.         putc( c, faction );
  802.         return;
  803.  
  804.  
  805. case '/':    /* look for comments */
  806.         putc( c , faction );
  807.         c = getc(finput);
  808.         if( c != '*' ) goto swt;
  809.  
  810.         /* it really is a comment */
  811.  
  812.         putc( c , faction );
  813.         c = getc(finput);
  814.         while( c != EOF ){
  815.             while( c=='*' ){
  816.                 putc( c , faction );
  817.                 if( (c=getc(finput)) == '/' ) goto lcopy;
  818.                 }
  819.             putc( c , faction );
  820.             if( c == '\n' )++lineno;
  821.             c = getc(finput);
  822.             }
  823.         error( "EOF inside comment" );
  824.  
  825. case '\'':    /* character constant */
  826.         match = '\'';
  827.         goto string;
  828.  
  829. case '"':    /* character string */
  830.         match = '"';
  831.  
  832.     string:
  833.  
  834.         putc( c , faction );
  835.         while( c=getc(finput) ){
  836.  
  837.             if( c=='\\' ){
  838.                 putc( c , faction );
  839.                 c=getc(finput);
  840.                 if( c == '\n' ) ++lineno;
  841.                 }
  842.             else if( c==match ) goto lcopy;
  843.             else if( c=='\n' ) error( "newline in string or char. const." );
  844.             putc( c , faction );
  845.             }
  846.         error( "EOF in string or character constant" );
  847.  
  848. case EOF:
  849.         error("action does not terminate" );
  850.  
  851. case '\n':    ++lineno;
  852.         goto lcopy;
  853.  
  854.         }
  855.  
  856. lcopy:
  857.     putc( c , faction );
  858.     goto loop;
  859.     }
  860.