home *** CD-ROM | disk | FTP | other *** search
/ ftp.mactech.com 2010 / ftp.mactech.com.tar / ftp.mactech.com / online / source / c / compilers / mpw-perl-byacc1.8.1.sit.hqx / mpw-perl-byacc1.8.1 / reader.c < prev    next >
C/C++ Source or Header  |  1992-10-20  |  34KB  |  1,915 lines

  1. #include "defs.h"
  2.  
  3. /*  The line size must be a positive integer.  One hundred was chosen    */
  4. /*  because few lines in Yacc input grammars exceed 100 characters.    */
  5. /*  Note that if a line exceeds LINESIZE characters, the line buffer    */
  6. /*  will be expanded to accomodate it.                    */
  7.  
  8. #define LINESIZE 100
  9.  
  10. char *cache;
  11. int cinc, cache_size;
  12.  
  13. int ntags, tagmax;
  14. char **tag_table;
  15.  
  16. char saw_eof, unionized;
  17. char *cptr, *line;
  18. int linesize;
  19.  
  20. bucket *goal;
  21. int prec;
  22. int gensym;
  23. char last_was_action;
  24.  
  25. int maxitems;
  26. bucket **pitem;
  27.  
  28. int maxrules;
  29. bucket **plhs;
  30.  
  31. int name_pool_size;
  32. char *name_pool;
  33.  
  34. char line_format[] = "#line %d \"%s\"\n";
  35.  
  36. /* dollar sign is allowed in identifiers */
  37. #define dollar_ok()    (language==C)
  38.  
  39. cachec(c)
  40. int c;
  41. {
  42.     assert(cinc >= 0);
  43.     if (cinc >= cache_size)
  44.     {
  45.     cache_size += 256;
  46.     cache = REALLOC(cache, cache_size);
  47.     if (cache == 0) no_space();
  48.     }
  49.     cache[cinc] = c;
  50.     ++cinc;
  51. }
  52.  
  53.  
  54. get_line()
  55. {
  56.     register FILE *f = input_file;
  57.     register int c;
  58.     register int i;
  59.  
  60.     Cooperate();    /* do this to give visual feedback on some ports, or contribute
  61.                      * to the macintosh cooperative multitasking environment - RA */
  62.     
  63.     if (saw_eof || (c = getc(f)) == EOF)
  64.     {
  65.     if (line) { FREE(line); line = 0; }
  66.     cptr = 0;
  67.     saw_eof = 1;
  68.     return;
  69.     }
  70.  
  71.     if (line == 0 || linesize != (LINESIZE + 1))
  72.     {
  73.     if (line) FREE(line);
  74.     linesize = LINESIZE + 1;
  75.     line = MALLOC(linesize);
  76.     if (line == 0) no_space();
  77.     }
  78.  
  79.     i = 0;
  80.     ++lineno;
  81.     for (;;)
  82.     {
  83.     line[i]  =  c;
  84.     if (c == '\n') { cptr = line; return; }
  85.     if (++i >= linesize)
  86.     {
  87.         linesize += LINESIZE;
  88.         line = REALLOC(line, linesize);
  89.         if (line ==  0) no_space();
  90.     }
  91.     c = getc(f);
  92.     if (c ==  EOF)
  93.     {
  94.         line[i] = '\n';
  95.         saw_eof = 1;
  96.         cptr = line;
  97.         return;
  98.     }
  99.     }
  100. }
  101.  
  102.  
  103. char *
  104. dup_line()
  105. {
  106.     register char *p, *s, *t;
  107.  
  108.     if (line == 0) return (0);
  109.     s = line;
  110.     while (*s != '\n') ++s;
  111.     p = MALLOC(s - line + 1);
  112.     if (p == 0) no_space();
  113.  
  114.     s = line;
  115.     t = p;
  116.     while ((*t++ = *s++) != '\n') continue;
  117.     return (p);
  118. }
  119.  
  120.  
  121. skip_comment()
  122. {
  123.     register char *s;
  124.  
  125.     int st_lineno = lineno;
  126.     char *st_line = dup_line();
  127.     char *st_cptr = st_line + (cptr - line);
  128.  
  129.     s = cptr + 2;
  130.     for (;;)
  131.     {
  132.     if (*s == '*' && s[1] == '/')
  133.     {
  134.         cptr = s + 2;
  135.         FREE(st_line);
  136.         return;
  137.     }
  138.     if (*s == '\n')
  139.     {
  140.         get_line();
  141.         if (line == 0)
  142.         unterminated_comment(st_lineno, st_line, st_cptr);
  143.         s = cptr;
  144.     }
  145.     else
  146.         ++s;
  147.     }
  148. }
  149.  
  150.  
  151. int
  152. nextc()
  153. {
  154.     register char *s;
  155.  
  156.     if (line == 0)
  157.     {
  158.     get_line();
  159.     if (line == 0)
  160.         return (EOF);
  161.     }
  162.  
  163.     s = cptr;
  164.     for (;;)
  165.     {
  166.     switch (*s)
  167.     {
  168.     case '\n':
  169.         get_line();
  170.         if (line == 0) return (EOF);
  171.         s = cptr;
  172.         break;
  173.  
  174.     case ' ':
  175.     case '\t':
  176.     case '\f':
  177.     case '\r':
  178.     case '\v':
  179.     case ',':
  180.     case ';':
  181.         ++s;
  182.         break;
  183.  
  184.     case '\\':
  185.         cptr = s;
  186.         return ('%');
  187.  
  188.     case '#':
  189.         if (language == PERL) {
  190.         get_line();
  191.         if (line == 0) return (EOF);
  192.         s = cptr;
  193.         break;
  194.         }
  195.         cptr = s;
  196.         return (*s);
  197.  
  198.     case '/':
  199.         if (s[1] == '*')
  200.         {
  201.         cptr = s;
  202.         skip_comment();
  203.         s = cptr;
  204.         break;
  205.         }
  206.         else if (s[1] == '/')
  207.         {
  208.         get_line();
  209.         if (line == 0) return (EOF);
  210.         s = cptr;
  211.         break;
  212.         }
  213.         cptr = s;
  214.         return (*s);
  215.  
  216.     default:
  217.         cptr = s;
  218.         return (*s);
  219.     }
  220.     }
  221. }
  222.  
  223.  
  224. int
  225. keyword()
  226. {
  227.     register int c;
  228.     char *t_cptr = cptr;
  229.  
  230.     c = *++cptr;
  231.     if (isalpha(c))
  232.     {
  233.     cinc = 0;
  234.     for (;;)
  235.     {
  236.         if (isalpha(c))
  237.         {
  238.         if (isupper(c)) c = tolower(c);
  239.         cachec(c);
  240.         }
  241.         else if (isdigit(c) || c == '_' || c == '.' || (dollar_ok() && c == '$'))
  242.         cachec(c);
  243.         else
  244.         break;
  245.         c = *++cptr;
  246.     }
  247.     cachec(NUL);
  248.  
  249.     if (strcmp(cache, "token") == 0 || strcmp(cache, "term") == 0)
  250.         return (TOKEN);
  251.     if (strcmp(cache, "type") == 0)
  252.         return (TYPE);
  253.     if (strcmp(cache, "left") == 0)
  254.         return (LEFT);
  255.     if (strcmp(cache, "right") == 0)
  256.         return (RIGHT);
  257.     if (strcmp(cache, "nonassoc") == 0 || strcmp(cache, "binary") == 0)
  258.         return (NONASSOC);
  259.     if (strcmp(cache, "start") == 0)
  260.         return (START);
  261.     if (strcmp(cache, "union") == 0)
  262.         return (UNION);
  263.     if (strcmp(cache, "ident") == 0)
  264.         return (IDENT);
  265.     }
  266.     else
  267.     {
  268.     ++cptr;
  269.     if (c == '{')
  270.         return (TEXT);
  271.     if (c == '%' || c == '\\')
  272.         return (MARK);
  273.     if (c == '<')
  274.         return (LEFT);
  275.     if (c == '>')
  276.         return (RIGHT);
  277.     if (c == '0')
  278.         return (TOKEN);
  279.     if (c == '2')
  280.         return (NONASSOC);
  281.     }
  282.     syntax_error(lineno, line, t_cptr);
  283.     /*NOTREACHED*/
  284. }
  285.  
  286.  
  287. copy_ident()
  288. {
  289.     register int c;
  290.     register FILE *f = output_file;
  291.  
  292.     c = nextc();
  293.     if (c == EOF) unexpected_EOF();
  294.     if (c != '"') syntax_error(lineno, line, cptr);
  295.     ++outline;
  296.     fprintf(f, "#ident \"");
  297.     for (;;)
  298.     {
  299.     c = *++cptr;
  300.     if (c == '\n')
  301.     {
  302.         fprintf(f, "\"\n");
  303.         return;
  304.     }
  305.     putc(c, f);
  306.     if (c == '"')
  307.     {
  308.         putc('\n', f);
  309.         ++cptr;
  310.         return;
  311.     }
  312.     }
  313. }
  314.  
  315.  
  316. copy_text()
  317. {
  318.     register int c;
  319.     int quote;
  320.     register FILE *f = text_file;
  321.     int need_newline = 0;
  322.     int t_lineno = lineno;
  323.     char *t_line = dup_line();
  324.     char *t_cptr = t_line + (cptr - line - 2);
  325.  
  326.     if (*cptr == '\n')
  327.     {
  328.     get_line();
  329.     if (line == 0)
  330.         unterminated_text(t_lineno, t_line, t_cptr);
  331.     }
  332.     if (!lflag) fprintf(f, line_format, lineno, input_file_name);
  333.  
  334. loop:
  335.     c = *cptr++;
  336.     switch (c)
  337.     {
  338.     case '\n':
  339.     next_line:
  340.     putc('\n', f);
  341.     need_newline = 0;
  342.     get_line();
  343.     if (line) goto loop;
  344.     unterminated_text(t_lineno, t_line, t_cptr);
  345.  
  346.     case '\'':
  347.     case '"':
  348.     {
  349.         int s_lineno = lineno;
  350.         char *s_line = dup_line();
  351.         char *s_cptr = s_line + (cptr - line - 1);
  352.  
  353.         quote = c;
  354.         putc(c, f);
  355.         for (;;)
  356.         {
  357.         c = *cptr++;
  358.         putc(c, f);
  359.         if (c == quote)
  360.         {
  361.             need_newline = 1;
  362.             FREE(s_line);
  363.             goto loop;
  364.         }
  365.         if (c == '\n')
  366.             unterminated_string(s_lineno, s_line, s_cptr);
  367.         if (c == '\\')
  368.         {
  369.             c = *cptr++;
  370.             putc(c, f);
  371.             if (c == '\n')
  372.             {
  373.             get_line();
  374.             if (line == 0)
  375.                 unterminated_string(s_lineno, s_line, s_cptr);
  376.             }
  377.         }
  378.         }
  379.     }
  380.  
  381.     case '/':
  382.     need_newline = 1;
  383.     c = *cptr;
  384.     if (c == '/')
  385.     {
  386.         if (language == PERL)
  387.         fprintf(f, (cptr == line + 1) ? ";#" : "#");
  388.         else
  389.         fprintf(f, "/*");
  390.         while ((c = *++cptr) != '\n')
  391.         {
  392.         if (c == '*' && cptr[1] == '/')
  393.             fprintf(f, "* ");
  394.         else
  395.             putc(c, f);
  396.         }
  397.         if (language == C)
  398.         fprintf(f, "*/");
  399.         goto next_line;
  400.     }
  401.     else if (c == '*')
  402.     {
  403.         int c_lineno = lineno;
  404.         char *c_line = dup_line();
  405.         char *c_cptr = c_line + (cptr - line - 1);
  406.  
  407.         if (language == PERL)
  408.         fprintf(f, (cptr == line + 1) ? ";#" : "#");
  409.         else
  410.         fprintf(f, "/*");
  411.         ++cptr;
  412.         for (;;)
  413.         {
  414.         c = *cptr++;
  415.         putc(c, f);
  416.         if (c == '*' && *cptr == '/')
  417.         {
  418.             if (language == C)
  419.             putc('/', f);
  420.             ++cptr;
  421.             FREE(c_line);
  422.             goto loop;
  423.         }
  424.         if (c == '\n')
  425.         {
  426.             get_line();
  427.             if (line == 0)
  428.             unterminated_comment(c_lineno, c_line, c_cptr);
  429.         }
  430.         }
  431.     }
  432.     else
  433.         putc('/', f);
  434.     goto loop;
  435.  
  436.     case '%':
  437.     case '\\':
  438.     if (*cptr == '}')
  439.     {
  440.         if (need_newline) putc('\n', f);
  441.         ++cptr;
  442.         FREE(t_line);
  443.         return;
  444.     }
  445.     putc(c, f);
  446.     need_newline = 1;
  447.     goto loop;
  448.  
  449.     case '#':
  450.     if (language == PERL) {
  451.         fprintf(f, (cptr == line + 1) ? ";#" : "#");
  452.         need_newline = 1;
  453.         while ((c = *cptr++) != '\n')
  454.         putc(c, f);
  455.         goto next_line;
  456.     }
  457.     putc(c, f);
  458.     need_newline = 1;
  459.     goto loop;
  460.     
  461.     default:
  462.     putc(c, f);
  463.     need_newline = 1;
  464.     goto loop;
  465.     }
  466. }
  467.  
  468. static perl_comment(text_file, other_file)
  469. FILE *text_file;
  470. FILE *other_file;
  471. {
  472.     if (language == PERL)
  473.     {
  474.     fprintf(text_file, (cptr == line + 1) ? ";#" : "#");
  475.     if (dflag)
  476.         fprintf(other_file, (cptr == line + 1) ? ";#" : "#");
  477.     }
  478. }
  479.   
  480. copy_union()
  481. {
  482.     register int c;
  483.     int quote;
  484.     int depth;
  485.     int u_lineno = lineno;
  486.     char *u_line = dup_line();
  487.     char *u_cptr = u_line + (cptr - line - 6);
  488.  
  489.     if (unionized) over_unionized(cptr - 6);
  490.     unionized = 1;
  491.  
  492.     if (!lflag)
  493.     fprintf(text_file, line_format, lineno, input_file_name);
  494.  
  495.     perl_comment(text_file, union_file);
  496.     fprintf(text_file, "typedef union");
  497.     if (dflag) fprintf(union_file, "typedef union");
  498.  
  499.     depth = 0;
  500. loop:
  501.     c = *cptr++;
  502.     putc(c, text_file);
  503.     if (dflag) putc(c, union_file);
  504.     switch (c)
  505.     {
  506.     case '\n':
  507.     next_line:
  508.     get_line();
  509.     if (line == 0) unterminated_union(u_lineno, u_line, u_cptr);
  510.     perl_comment(text_file, union_file);
  511.     goto loop;
  512.  
  513.     case '{':
  514.     ++depth;
  515.     goto loop;
  516.  
  517.     case '}':
  518.     if (--depth == 0)
  519.     {
  520.         fprintf(text_file, " YYSTYPE;\n");
  521.         FREE(u_line);
  522.         return;
  523.     }
  524.     goto loop;
  525.  
  526.     case '\'':
  527.     case '"':
  528.     {
  529.         int s_lineno = lineno;
  530.         char *s_line = dup_line();
  531.         char *s_cptr = s_line + (cptr - line - 1);
  532.  
  533.         quote = c;
  534.         for (;;)
  535.         {
  536.         c = *cptr++;
  537.         putc(c, text_file);
  538.         if (dflag) putc(c, union_file);
  539.         if (c == quote)
  540.         {
  541.             FREE(s_line);
  542.             goto loop;
  543.         }
  544.         if (c == '\n')
  545.             unterminated_string(s_lineno, s_line, s_cptr);
  546.         if (c == '\\')
  547.         {
  548.             c = *cptr++;
  549.             putc(c, text_file);
  550.             if (dflag) putc(c, union_file);
  551.             if (c == '\n')
  552.             {
  553.             get_line();
  554.             if (line == 0)
  555.                 unterminated_string(s_lineno, s_line, s_cptr);
  556.             }
  557.         }
  558.         }
  559.     }
  560.  
  561.     case '/':
  562.     c = *cptr;
  563.     if (c == '/')
  564.     {
  565.         putc('*', text_file);
  566.         if (dflag) putc('*', union_file);
  567.         while ((c = *++cptr) != '\n')
  568.         {
  569.         if (c == '*' && cptr[1] == '/')
  570.         {
  571.             fprintf(text_file, "* ");
  572.             if (dflag) fprintf(union_file, "* ");
  573.         }
  574.         else
  575.         {
  576.             putc(c, text_file);
  577.             if (dflag) putc(c, union_file);
  578.         }
  579.         }
  580.         fprintf(text_file, "*/\n");
  581.         if (dflag) fprintf(union_file, "*/\n");
  582.         goto next_line;
  583.     }
  584.     if (c == '*')
  585.     {
  586.         int c_lineno = lineno;
  587.         char *c_line = dup_line();
  588.         char *c_cptr = c_line + (cptr - line - 1);
  589.  
  590.         putc('*', text_file);
  591.         if (dflag) putc('*', union_file);
  592.         ++cptr;
  593.         for (;;)
  594.         {
  595.         c = *cptr++;
  596.         putc(c, text_file);
  597.         if (dflag) putc(c, union_file);
  598.         if (c == '*' && *cptr == '/')
  599.         {
  600.             putc('/', text_file);
  601.             if (dflag) putc('/', union_file);
  602.             ++cptr;
  603.             FREE(c_line);
  604.             goto loop;
  605.         }
  606.         if (c == '\n')
  607.         {
  608.             get_line();
  609.             if (line == 0)
  610.             unterminated_comment(c_lineno, c_line, c_cptr);
  611.         }
  612.         }
  613.     }
  614.     goto loop;
  615.  
  616.     default:
  617.     goto loop;
  618.     }
  619. }
  620.  
  621.  
  622. int
  623. hexval(c)
  624. int c;
  625. {
  626.     if (c >= '0' && c <= '9')
  627.     return (c - '0');
  628.     if (c >= 'A' && c <= 'F')
  629.     return (c - 'A' + 10);
  630.     if (c >= 'a' && c <= 'f')
  631.     return (c - 'a' + 10);
  632.     return (-1);
  633. }
  634.  
  635.  
  636. bucket *
  637. get_literal()
  638. {
  639.     register int c, quote;
  640.     register int i;
  641.     register int n;
  642.     register char *s;
  643.     register bucket *bp;
  644.     int s_lineno = lineno;
  645.     char *s_line = dup_line();
  646.     char *s_cptr = s_line + (cptr - line);
  647.  
  648.     quote = *cptr++;
  649.     cinc = 0;
  650.     for (;;)
  651.     {
  652.     c = *cptr++;
  653.     if (c == quote) break;
  654.     if (c == '\n') unterminated_string(s_lineno, s_line, s_cptr);
  655.     if (c == '\\')
  656.     {
  657.         char *c_cptr = cptr - 1;
  658.  
  659.         c = *cptr++;
  660.         switch (c)
  661.         {
  662.         case '\n':
  663.         get_line();
  664.         if (line == 0) unterminated_string(s_lineno, s_line, s_cptr);
  665.         continue;
  666.  
  667.         case '0': case '1': case '2': case '3':
  668.         case '4': case '5': case '6': case '7':
  669.         n = c - '0';
  670.         c = *cptr;
  671.         if (IS_OCTAL(c))
  672.         {
  673.             n = (n << 3) + (c - '0');
  674.             c = *++cptr;
  675.             if (IS_OCTAL(c))
  676.             {
  677.             n = (n << 3) + (c - '0');
  678.             ++cptr;
  679.             }
  680.         }
  681.         if (n > MAXCHAR) illegal_character(c_cptr);
  682.         c = n;
  683.             break;
  684.  
  685.         case 'x':
  686.         c = *cptr++;
  687.         n = hexval(c);
  688.         if (n < 0 || n >= 16)
  689.             illegal_character(c_cptr);
  690.         for (;;)
  691.         {
  692.             c = *cptr;
  693.             i = hexval(c);
  694.             if (i < 0 || i >= 16) break;
  695.             ++cptr;
  696.             n = (n << 4) + i;
  697.             if (n > MAXCHAR) illegal_character(c_cptr);
  698.         }
  699.         c = n;
  700.         break;
  701.  
  702.         case 'a': c = 7; break;
  703.         case 'b': c = '\b'; break;
  704.         case 'f': c = '\f'; break;
  705.         case 'n': c = '\n'; break;
  706.         case 'r': c = '\r'; break;
  707.         case 't': c = '\t'; break;
  708.         case 'v': c = '\v'; break;
  709.         }
  710.     }
  711.     cachec(c);
  712.     }
  713.     FREE(s_line);
  714.  
  715.     n = cinc;
  716.     s = MALLOC(n);
  717.     if (s == 0) no_space();
  718.     
  719.     for (i = 0; i < n; ++i)
  720.     s[i] = cache[i];
  721.  
  722.     cinc = 0;
  723.     if (n == 1)
  724.     cachec('\'');
  725.     else
  726.     cachec('"');
  727.  
  728.     for (i = 0; i < n; ++i)
  729.     {
  730.     c = ((unsigned char *)s)[i];
  731.     if (c == '\\' || c == cache[0])
  732.     {
  733.         cachec('\\');
  734.         cachec(c);
  735.     }
  736.     else if (isprint(c))
  737.         cachec(c);
  738.     else
  739.     {
  740.         cachec('\\');
  741.         switch (c)
  742.         {
  743.         case 7: cachec('a'); break;
  744.         case '\b': cachec('b'); break;
  745.         case '\f': cachec('f'); break;
  746.         case '\n': cachec('n'); break;
  747.         case '\r': cachec('r'); break;
  748.         case '\t': cachec('t'); break;
  749.         case '\v': cachec('v'); break;
  750.         default:
  751.         cachec(((c >> 6) & 7) + '0');
  752.         cachec(((c >> 3) & 7) + '0');
  753.         cachec((c & 7) + '0');
  754.         break;
  755.         }
  756.     }
  757.     }
  758.  
  759.     if (n == 1)
  760.     cachec('\'');
  761.     else
  762.     cachec('"');
  763.  
  764.     cachec(NUL);
  765.     bp = lookup(cache);
  766.     bp->class = TERM;
  767.     if (n == 1 && bp->value == UNDEFINED)
  768.     bp->value = *(unsigned char *)s;
  769.     FREE(s);
  770.  
  771.     return (bp);
  772. }
  773.  
  774.  
  775. int
  776. is_reserved(name)
  777. char *name;
  778. {
  779.     char *s;
  780.  
  781.     if (strcmp(name, ".") == 0 ||
  782.         strcmp(name, "$accept") == 0 ||
  783.         strcmp(name, "$end") == 0)
  784.     return (1);
  785.  
  786.     if (name[0] == '$' && name[1] == '$' && isdigit(name[2]))
  787.     {
  788.     s = name + 3;
  789.     while (isdigit(*s)) ++s;
  790.     if (*s == NUL) return (1);
  791.     }
  792.  
  793.     return (0);
  794. }
  795.  
  796.  
  797. bucket *
  798. get_name()
  799. {
  800.     register int c;
  801.  
  802.     cinc = 0;
  803.     for (c = *cptr; IS_IDENT(c); c = *++cptr)
  804.     cachec(c);
  805.     cachec(NUL);
  806.  
  807.     if (is_reserved(cache)) used_reserved(cache);
  808.  
  809.     return (lookup(cache));
  810. }
  811.  
  812.  
  813. int
  814. get_number()
  815. {
  816.     register int c;
  817.     register int n;
  818.  
  819.     n = 0;
  820.     for (c = *cptr; isdigit(c); c = *++cptr)
  821.     n = 10*n + (c - '0');
  822.  
  823.     return (n);
  824. }
  825.  
  826.  
  827. char *
  828. get_tag()
  829. {
  830.     register int c;
  831.     register int i;
  832.     register char *s;
  833.     int t_lineno = lineno;
  834.     char *t_line = dup_line();
  835.     char *t_cptr = t_line + (cptr - line);
  836.  
  837.     ++cptr;
  838.     c = nextc();
  839.     if (c == EOF) unexpected_EOF();
  840.     if (!isalpha(c) && c != '_' && c != '$')
  841.     illegal_tag(t_lineno, t_line, t_cptr);
  842.     else if (! dollar_ok() && c == '$')
  843.     illegal_tag(t_lineno, t_line, t_cptr);
  844.  
  845.     cinc = 0;
  846.     do { cachec(c); c = *++cptr; } while (IS_IDENT(c));
  847.     cachec(NUL);
  848.  
  849.     c = nextc();
  850.     if (c == EOF) unexpected_EOF();
  851.     if (c != '>')
  852.     illegal_tag(t_lineno, t_line, t_cptr);
  853.     ++cptr;
  854.  
  855.     for (i = 0; i < ntags; ++i)
  856.     {
  857.     if (strcmp(cache, tag_table[i]) == 0)
  858.         return (tag_table[i]);
  859.     }
  860.  
  861.     if (ntags >= tagmax)
  862.     {
  863.     tagmax += 16;
  864.     tag_table = (char **)
  865.             (tag_table ? REALLOC(tag_table, tagmax*sizeof(char *))
  866.                    : MALLOC(tagmax*sizeof(char *)));
  867.     if (tag_table == 0) no_space();
  868.     }
  869.  
  870.     s = MALLOC(cinc);
  871.     if  (s == 0) no_space();
  872.     strcpy(s, cache);
  873.     tag_table[ntags] = s;
  874.     ++ntags;
  875.     FREE(t_line);
  876.     return (s);
  877. }
  878.  
  879.  
  880. declare_tokens(assoc)
  881. int assoc;
  882. {
  883.     register int c;
  884.     register bucket *bp;
  885.     int value;
  886.     char *tag = 0;
  887.  
  888.     if (assoc != TOKEN) ++prec;
  889.  
  890.     c = nextc();
  891.     if (c == EOF) unexpected_EOF();
  892.     if (c == '<')
  893.     {
  894.     tag = get_tag();
  895.     c = nextc();
  896.     if (c == EOF) unexpected_EOF();
  897.     }
  898.  
  899.     for (;;)
  900.     {
  901.     if (isalpha(c) || c == '_' || c == '.' || (dollar_ok() && c == '$'))
  902.         bp = get_name();
  903.     else if (c == '\'' || c == '"')
  904.         bp = get_literal();
  905.     else
  906.         return;
  907.  
  908.     if (bp == goal) tokenized_start(bp->name);
  909.     bp->class = TERM;
  910.  
  911.     if (tag)
  912.     {
  913.         if (bp->tag && tag != bp->tag)
  914.         retyped_warning(bp->name);
  915.         bp->tag = tag;
  916.     }
  917.  
  918.     if (assoc != TOKEN)
  919.     {
  920.         if (bp->prec && prec != bp->prec)
  921.         reprec_warning(bp->name);
  922.         bp->assoc = assoc;
  923.         bp->prec = prec;
  924.     }
  925.  
  926.     c = nextc();
  927.     if (c == EOF) unexpected_EOF();
  928.     value = UNDEFINED;
  929.     if (isdigit(c))
  930.     {
  931.         value = get_number();
  932.         if (bp->value != UNDEFINED && value != bp->value)
  933.         revalued_warning(bp->name);
  934.         bp->value = value;
  935.         c = nextc();
  936.         if (c == EOF) unexpected_EOF();
  937.     }
  938.     }
  939. }
  940.  
  941.  
  942. declare_types()
  943. {
  944.     register int c;
  945.     register bucket *bp;
  946.     char *tag;
  947.  
  948.     c = nextc();
  949.     if (c == EOF) unexpected_EOF();
  950.     if (c != '<') syntax_error(lineno, line, cptr);
  951.     tag = get_tag();
  952.  
  953.     for (;;)
  954.     {
  955.     c = nextc();
  956.     if (isalpha(c) || c == '_' || c == '.' || (dollar_ok() && c == '$'))
  957.         bp = get_name();
  958.     else if (c == '\'' || c == '"')
  959.         bp = get_literal();
  960.     else
  961.         return;
  962.  
  963.     if (bp->tag && tag != bp->tag)
  964.         retyped_warning(bp->name);
  965.     bp->tag = tag;
  966.     }
  967. }
  968.  
  969.  
  970. declare_start()
  971. {
  972.     register int c;
  973.     register bucket *bp;
  974.  
  975.     c = nextc();
  976.     if (c == EOF) unexpected_EOF();
  977.     if (!isalpha(c) && c != '_' && c != '.' && c != '$')
  978.     syntax_error(lineno, line, cptr);
  979.     else if (! dollar_ok() && c == '$')
  980.     syntax_error(lineno, line, cptr);
  981.     bp = get_name();
  982.     if (bp->class == TERM)
  983.     terminal_start(bp->name);
  984.     if (goal && goal != bp)
  985.     restarted_warning();
  986.     goal = bp;
  987. }
  988.  
  989.  
  990. read_declarations()
  991. {
  992.     register int c, k;
  993.  
  994.     cache_size = 256;
  995.     cache = MALLOC(cache_size);
  996.     if (cache == 0) no_space();
  997.  
  998.     for (;;)
  999.     {
  1000.     c = nextc();
  1001.     if (c == EOF) unexpected_EOF();
  1002.     if (c != '%') syntax_error(lineno, line, cptr);
  1003.     switch (k = keyword())
  1004.     {
  1005.     case MARK:
  1006.         return;
  1007.  
  1008.     case IDENT:
  1009.         copy_ident();
  1010.         break;
  1011.  
  1012.     case TEXT:
  1013.         copy_text();
  1014.         break;
  1015.  
  1016.     case UNION:
  1017.         copy_union();
  1018.         break;
  1019.  
  1020.     case TOKEN:
  1021.     case LEFT:
  1022.     case RIGHT:
  1023.     case NONASSOC:
  1024.         declare_tokens(k);
  1025.         break;
  1026.  
  1027.     case TYPE:
  1028.         declare_types();
  1029.         break;
  1030.  
  1031.     case START:
  1032.         declare_start();
  1033.         break;
  1034.     }
  1035.     }
  1036. }
  1037.  
  1038.  
  1039. initialize_grammar()
  1040. {
  1041.     nitems = 4;
  1042.     maxitems = 300;
  1043.     pitem = (bucket **) MALLOC(maxitems*sizeof(bucket *));
  1044.     if (pitem == 0) no_space();
  1045.     pitem[0] = 0;
  1046.     pitem[1] = 0;
  1047.     pitem[2] = 0;
  1048.     pitem[3] = 0;
  1049.  
  1050.     nrules = 3;
  1051.     maxrules = 100;
  1052.     plhs = (bucket **) MALLOC(maxrules*sizeof(bucket *));
  1053.     if (plhs == 0) no_space();
  1054.     plhs[0] = 0;
  1055.     plhs[1] = 0;
  1056.     plhs[2] = 0;
  1057.     rprec = (short *) MALLOC(maxrules*sizeof(short));
  1058.     if (rprec == 0) no_space();
  1059.     rprec[0] = 0;
  1060.     rprec[1] = 0;
  1061.     rprec[2] = 0;
  1062.     rassoc = (char *) MALLOC(maxrules*sizeof(char));
  1063.     if (rassoc == 0) no_space();
  1064.     rassoc[0] = TOKEN;
  1065.     rassoc[1] = TOKEN;
  1066.     rassoc[2] = TOKEN;
  1067. }
  1068.  
  1069.  
  1070. expand_items()
  1071. {
  1072.     maxitems += 300;
  1073.     pitem = (bucket **) REALLOC(pitem, maxitems*sizeof(bucket *));
  1074.     if (pitem == 0) no_space();
  1075. }
  1076.  
  1077.  
  1078. expand_rules()
  1079. {
  1080.     maxrules += 100;
  1081.     plhs = (bucket **) REALLOC(plhs, maxrules*sizeof(bucket *));
  1082.     if (plhs == 0) no_space();
  1083.     rprec = (short *) REALLOC(rprec, maxrules*sizeof(short));
  1084.     if (rprec == 0) no_space();
  1085.     rassoc = (char *) REALLOC(rassoc, maxrules*sizeof(char));
  1086.     if (rassoc == 0) no_space();
  1087. }
  1088.  
  1089.  
  1090. advance_to_start()
  1091. {
  1092.     register int c;
  1093.     register bucket *bp;
  1094.     char *s_cptr;
  1095.     int s_lineno;
  1096.  
  1097.     for (;;)
  1098.     {
  1099.     c = nextc();
  1100.     if (c != '%') break;
  1101.     s_cptr = cptr;
  1102.     switch (keyword())
  1103.     {
  1104.     case MARK:
  1105.         no_grammar();
  1106.  
  1107.     case TEXT:
  1108.         copy_text();
  1109.         break;
  1110.  
  1111.     case START:
  1112.         declare_start();
  1113.         break;
  1114.  
  1115.     default:
  1116.         syntax_error(lineno, line, s_cptr);
  1117.     }
  1118.     }
  1119.  
  1120.     c = nextc();
  1121.     if (!isalpha(c) && c != '_' && c != '.')
  1122.     syntax_error(lineno, line, cptr);
  1123.     bp = get_name();
  1124.     if (goal == 0)
  1125.     {
  1126.     if (bp->class == TERM)
  1127.         terminal_start(bp->name);
  1128.     goal = bp;
  1129.     }
  1130.  
  1131.     s_lineno = lineno;
  1132.     c = nextc();
  1133.     if (c == EOF) unexpected_EOF();
  1134.     if (c != ':') syntax_error(lineno, line, cptr);
  1135.     start_rule(bp, s_lineno);
  1136.     ++cptr;
  1137. }
  1138.  
  1139.  
  1140. start_rule(bp, s_lineno)
  1141. register bucket *bp;
  1142. int s_lineno;
  1143. {
  1144.     if (bp->class == TERM)
  1145.     terminal_lhs(s_lineno);
  1146.     bp->class = NONTERM;
  1147.     if (nrules >= maxrules)
  1148.     expand_rules();
  1149.     plhs[nrules] = bp;
  1150.     rprec[nrules] = UNDEFINED;
  1151.     rassoc[nrules] = TOKEN;
  1152. }
  1153.  
  1154.  
  1155. end_rule()
  1156. {
  1157.     register int i;
  1158.  
  1159.     if (!last_was_action && plhs[nrules]->tag)
  1160.     {
  1161.     for (i = nitems - 1; pitem[i]; --i) continue;
  1162.     if (pitem[i+1] == 0 || pitem[i+1]->tag != plhs[nrules]->tag)
  1163.         default_action_warning();
  1164.     }
  1165.  
  1166.     last_was_action = 0;
  1167.     if (nitems >= maxitems) expand_items();
  1168.     pitem[nitems] = 0;
  1169.     ++nitems;
  1170.     ++nrules;
  1171. }
  1172.  
  1173.  
  1174. insert_empty_rule()
  1175. {
  1176.     register bucket *bp, **bpp;
  1177.  
  1178.     assert(cache);
  1179.     sprintf(cache, "$$%d", ++gensym);
  1180.     bp = make_bucket(cache);
  1181.     last_symbol->next = bp;
  1182.     last_symbol = bp;
  1183.     bp->tag = plhs[nrules]->tag;
  1184.     bp->class = NONTERM;
  1185.  
  1186.     if ((nitems += 2) > maxitems)
  1187.     expand_items();
  1188.     bpp = pitem + nitems - 1;
  1189.     *bpp-- = bp;
  1190.     while (bpp[0] = bpp[-1]) --bpp;
  1191.  
  1192.     if (++nrules >= maxrules)
  1193.     expand_rules();
  1194.     plhs[nrules] = plhs[nrules-1];
  1195.     plhs[nrules-1] = bp;
  1196.     rprec[nrules] = rprec[nrules-1];
  1197.     rprec[nrules-1] = 0;
  1198.     rassoc[nrules] = rassoc[nrules-1];
  1199.     rassoc[nrules-1] = TOKEN;
  1200. }
  1201.  
  1202.  
  1203. add_symbol()
  1204. {
  1205.     register int c;
  1206.     register bucket *bp;
  1207.     int s_lineno = lineno;
  1208.  
  1209.     c = *cptr;
  1210.     if (c == '\'' || c == '"')
  1211.     bp = get_literal();
  1212.     else
  1213.     bp = get_name();
  1214.  
  1215.     c = nextc();
  1216.     if (c == ':')
  1217.     {
  1218.     end_rule();
  1219.     start_rule(bp, s_lineno);
  1220.     ++cptr;
  1221.     return;
  1222.     }
  1223.  
  1224.     if (last_was_action)
  1225.     insert_empty_rule();
  1226.     last_was_action = 0;
  1227.  
  1228.     if (++nitems > maxitems)
  1229.     expand_items();
  1230.     pitem[nitems-1] = bp;
  1231. }
  1232.  
  1233.  
  1234. copy_action()
  1235. {
  1236.     register int c;
  1237.     register int i, n;
  1238.     int depth;
  1239.     int quote;
  1240.     char *tag;
  1241.     register FILE *f = action_file;
  1242.     int a_lineno = lineno;
  1243.     char *a_line = dup_line();
  1244.     char *a_cptr = a_line + (cptr - line);
  1245.  
  1246.  
  1247.     if (last_was_action)
  1248.     insert_empty_rule();
  1249.     last_was_action = 1;
  1250.  
  1251.     if (language == PERL)
  1252.     fprintf(f, "if ($yyn == %d) {\n", nrules - 2);
  1253.     else
  1254.     fprintf(f, "case %d:\n", nrules - 2);
  1255.     if (!lflag)
  1256.     fprintf(f, line_format, lineno, input_file_name);
  1257.     if (*cptr == '=') ++cptr;
  1258.  
  1259.     n = 0;
  1260.     for (i = nitems - 1; pitem[i]; --i) ++n;
  1261.  
  1262.     depth = 0;
  1263. loop:
  1264.     c = *cptr;
  1265.     if (c == '$')
  1266.     {
  1267.     if (cptr[1] == '<')
  1268.     {
  1269.         int d_lineno = lineno;
  1270.         char *d_line = dup_line();
  1271.         char *d_cptr = d_line + (cptr - line);
  1272.  
  1273.         ++cptr;
  1274.         tag = get_tag();
  1275.         c = *cptr;
  1276.         if (c == '$')
  1277.         {
  1278.         if (language == PERL)
  1279.             fprintf(f, "$yyval");
  1280.         else
  1281.             fprintf(f, "yyval.%s", tag);
  1282.         ++cptr;
  1283.         FREE(d_line);
  1284.         goto loop;
  1285.         }
  1286.         else if (isdigit(c))
  1287.         {
  1288.         i = get_number();
  1289.         if (i > n) dollar_warning(d_lineno, i);
  1290.         if (language == PERL)
  1291.             fprintf(f, "$yyvs[$yyvsp-%d]", n - i);
  1292.         else
  1293.             fprintf(f, "yyvsp[%d].%s", i - n, tag);
  1294.         FREE(d_line);
  1295.         goto loop;
  1296.         }
  1297.         else if (c == '-' && isdigit(cptr[1]))
  1298.         {
  1299.         ++cptr;
  1300.         i = -get_number() - n;
  1301.         if (language == PERL)
  1302.             fprintf(f, "$yyvsp[$yyvsp-%d]", -i);
  1303.         else
  1304.             fprintf(f, "yyvsp[%d].%s", i, tag);
  1305.         FREE(d_line);
  1306.         goto loop;
  1307.         }
  1308.         else
  1309.         dollar_error(d_lineno, d_line, d_cptr);
  1310.     }
  1311.     else if (cptr[1] == '$')
  1312.     {
  1313.         if (ntags)
  1314.         {
  1315.         tag = plhs[nrules]->tag;
  1316.         if (tag == 0) untyped_lhs();
  1317.         if (language == PERL)
  1318.             fprintf(f, "$yyval", tag);
  1319.         else
  1320.             fprintf(f, "yyval.%s", tag);
  1321.         }
  1322.         else if (language == PERL)
  1323.         fprintf(f, "$yyval");
  1324.         else
  1325.         fprintf(f, "yyval");
  1326.         cptr += 2;
  1327.         goto loop;
  1328.     }
  1329.     else if (isdigit(cptr[1]))
  1330.     {
  1331.         ++cptr;
  1332.         i = get_number();
  1333.         if (ntags)
  1334.         {
  1335.         if (i <= 0 || i > n)
  1336.             unknown_rhs(i);
  1337.         tag = pitem[nitems + i - n - 1]->tag;
  1338.         if (tag == 0) untyped_rhs(i, pitem[nitems + i - n - 1]->name);
  1339.         if (language == PERL)
  1340.             fprintf(f, "$yyvs[$yyvsp-%d]", n - i);
  1341.         else
  1342.             fprintf(f, "yyvsp[%d].%s", i - n, tag);
  1343.         }
  1344.         else
  1345.         {
  1346.         if (i > n)
  1347.             dollar_warning(lineno, i);
  1348.         if (language == PERL)
  1349.             fprintf(f, "$yyvs[$yyvsp-%d]", n - i);
  1350.         else
  1351.             fprintf(f, "yyvsp[%d]", i - n);
  1352.         }
  1353.         goto loop;
  1354.     }
  1355.     else if (cptr[1] == '-')
  1356.     {
  1357.         cptr += 2;
  1358.         i = get_number();
  1359.         if (ntags)
  1360.         unknown_rhs(-i);
  1361.         if (language == PERL)
  1362.         fprintf(f, "$yyvs[$yyvsp-%d]", i + n);
  1363.         else
  1364.         fprintf(f, "yyvsp[%d]", -i - n);
  1365.         goto loop;
  1366.     }
  1367.     }
  1368.     if (isalpha(c) || c == '_' || (dollar_ok() && c == '$'))
  1369.     {
  1370.     do
  1371.     {
  1372.         putc(c, f);
  1373.         c = *++cptr;
  1374.     } while (isalnum(c) || c == '_' || (dollar_ok() && c == '$'));
  1375.     goto loop;
  1376.     }
  1377.     ++cptr;
  1378.     switch (c)
  1379.     {
  1380.     case '\n':
  1381.     putc(c, f);
  1382. next_line:
  1383.     get_line();
  1384.     if (line) goto loop;
  1385.     unterminated_action(a_lineno, a_line, a_cptr);
  1386.  
  1387.     case ';':
  1388.     putc(c, f);
  1389.     if (depth > 0) goto loop;
  1390.     if (language == PERL)
  1391.         fprintf(f, "\nlast switch; }\n");
  1392.     else
  1393.         fprintf(f, "\nbreak;\n");
  1394.     return;
  1395.  
  1396.     case '{':
  1397.      putc(c, f);
  1398.     ++depth;
  1399.     goto loop;
  1400.  
  1401.     case '}':
  1402.     if (--depth > 0) {
  1403.         putc(c, f);
  1404.         goto loop;
  1405.     }
  1406.  
  1407.     if (language == PERL)
  1408.         fprintf(f, "\nlast switch;\n} }\n");
  1409.     else
  1410.         fprintf(f, "}\nbreak;\n");
  1411.     return;
  1412.  
  1413.     case '\'':
  1414.     case '"':
  1415.     {
  1416.         int s_lineno = lineno;
  1417.         char *s_line = dup_line();
  1418.         char *s_cptr = s_line + (cptr - line - 1);
  1419.  
  1420.         putc(c, f);
  1421.         quote = c;
  1422.         for (;;)
  1423.         {
  1424.         c = *cptr++;
  1425.         putc(c, f);
  1426.         if (c == quote)
  1427.         {
  1428.             FREE(s_line);
  1429.             goto loop;
  1430.         }
  1431.         if (c == '\n')
  1432.             unterminated_string(s_lineno, s_line, s_cptr);
  1433.         if (c == '\\')
  1434.         {
  1435.             c = *cptr++;
  1436.             putc(c, f);
  1437.             if (c == '\n')
  1438.             {
  1439.             get_line();
  1440.             if (line == 0)
  1441.                 unterminated_string(s_lineno, s_line, s_cptr);
  1442.             }
  1443.         }
  1444.         }
  1445.     }
  1446.  
  1447.     case '/':
  1448.     c = *cptr;
  1449.     if (c == '/')
  1450.     {
  1451.         if (language == PERL) {
  1452.         ++cptr;
  1453.         goto perl_comment;
  1454.         }
  1455.         fprintf(f, "/*");
  1456.         while ((c = *++cptr) != '\n')
  1457.         {
  1458.         if (c == '*' && cptr[1] == '/')
  1459.             fprintf(f, "* ");
  1460.         else
  1461.             putc(c, f);
  1462.         }
  1463.         fprintf(f, "*/\n");
  1464.         goto next_line;
  1465.     }
  1466.     if (c != '*')
  1467.     {
  1468.         putc('/', f);
  1469.     }
  1470.     else
  1471.     {
  1472.         int c_lineno = lineno;
  1473.         char *c_line = dup_line();
  1474.         char *c_cptr = c_line + (cptr - line - 1);
  1475.  
  1476.         if (language == PERL)
  1477.         fprintf(f, (cptr == line + 1) ? ";#" : "#");
  1478.         else
  1479.         fprintf(f, "/*");
  1480.         ++cptr;
  1481.         for (;;)
  1482.         {
  1483.         c = *cptr++;
  1484.         if (language == PERL && c == '*' && *cptr == '/')
  1485.         {
  1486.             putc('\n', f);
  1487.             ++cptr;
  1488.             FREE(c_line);
  1489.             goto loop;
  1490.         }
  1491.         putc(c, f);
  1492.         if (c == '*' && *cptr == '/')
  1493.         {
  1494.             putc('/', f);
  1495.             ++cptr;
  1496.             FREE(c_line);
  1497.             goto loop;
  1498.         }
  1499.         if (c == '\n')
  1500.         {
  1501.             get_line();
  1502.             if (line == 0)
  1503.             unterminated_comment(c_lineno, c_line, c_cptr);
  1504.             if (language == PERL)
  1505.             fprintf(f, ";# ");
  1506.         }
  1507.         }
  1508.     }
  1509.     goto loop;
  1510.  
  1511.     case '#':
  1512. perl_comment:
  1513.     if (language == PERL)
  1514.     {
  1515.         putc('#', f);
  1516.         do {
  1517.         putc(*cptr, f);
  1518.         } while (*cptr++ != '\n');
  1519.         goto next_line;
  1520.     }
  1521.     else
  1522.     {
  1523.         putc(c, f);
  1524.     }
  1525.     goto loop;
  1526.  
  1527.     default:
  1528.     putc(c, f);
  1529.     goto loop;
  1530.     }
  1531. }
  1532.  
  1533.  
  1534. int
  1535. mark_symbol()
  1536. {
  1537.     register int c;
  1538.     register bucket *bp;
  1539.  
  1540.     c = cptr[1];
  1541.     if (c == '%' || c == '\\')
  1542.     {
  1543.     cptr += 2;
  1544.     return (1);
  1545.     }
  1546.  
  1547.     if (c == '=')
  1548.     cptr += 2;
  1549.     else if ((c == 'p' || c == 'P') &&
  1550.          ((c = cptr[2]) == 'r' || c == 'R') &&
  1551.          ((c = cptr[3]) == 'e' || c == 'E') &&
  1552.          ((c = cptr[4]) == 'c' || c == 'C') &&
  1553.          ((c = cptr[5], !IS_IDENT(c))))
  1554.     cptr += 5;
  1555.     else
  1556.     syntax_error(lineno, line, cptr);
  1557.  
  1558.     c = nextc();
  1559.     if (isalpha(c) || c == '_' || c == '.' || (dollar_ok() && c == '$'))
  1560.     bp = get_name();
  1561.     else if (c == '\'' || c == '"')
  1562.     bp = get_literal();
  1563.     else
  1564.     {
  1565.     syntax_error(lineno, line, cptr);
  1566.     /*NOTREACHED*/
  1567.     }
  1568.  
  1569.     if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
  1570.     prec_redeclared();
  1571.  
  1572.     rprec[nrules] = bp->prec;
  1573.     rassoc[nrules] = bp->assoc;
  1574.     return (0);
  1575. }
  1576.  
  1577.  
  1578. read_grammar()
  1579. {
  1580.     register int c;
  1581.  
  1582.     initialize_grammar();
  1583.     advance_to_start();
  1584.  
  1585.     for (;;)
  1586.     {
  1587.     c = nextc();
  1588.     if (c == EOF) break;
  1589.     if (isalpha(c) || c == '_' || c == '.' || (dollar_ok() && c == '$') || c == '\'' ||
  1590.         c == '"')
  1591.         add_symbol();
  1592.     else if (c == '{' || c == '=')
  1593.         copy_action();
  1594.     else if (c == '|')
  1595.     {
  1596.         end_rule();
  1597.         start_rule(plhs[nrules-1], 0);
  1598.         ++cptr;
  1599.     }
  1600.     else if (c == '%')
  1601.     {
  1602.         if (mark_symbol()) break;
  1603.     }
  1604.     else
  1605.         syntax_error(lineno, line, cptr);
  1606.     }
  1607.     end_rule();
  1608. }
  1609.  
  1610.  
  1611. free_tags()
  1612. {
  1613.     register int i;
  1614.  
  1615.     if (tag_table == 0) return;
  1616.  
  1617.     for (i = 0; i < ntags; ++i)
  1618.     {
  1619.     assert(tag_table[i]);
  1620.     FREE(tag_table[i]);
  1621.     }
  1622.     FREE(tag_table);
  1623. }
  1624.  
  1625.  
  1626. pack_names()
  1627. {
  1628.     register bucket *bp;
  1629.     register char *p, *s, *t;
  1630.  
  1631.     name_pool_size = sizeof("$end") + sizeof("$accept");
  1632.     for (bp = first_symbol; bp; bp = bp->next)
  1633.     name_pool_size += strlen(bp->name) + 1;
  1634.     name_pool = MALLOC(name_pool_size);
  1635.     if (name_pool == 0) no_space();
  1636.  
  1637.     strcpy(name_pool, "$accept");
  1638.     strcpy(name_pool+8, "$end");
  1639.     t = name_pool + 13;
  1640.     for (bp = first_symbol; bp; bp = bp->next)
  1641.     {
  1642.     p = t;
  1643.     s = bp->name;
  1644.     while (*t++ = *s++) continue;
  1645.     FREE(bp->name);
  1646.     bp->name = p;
  1647.     }
  1648. }
  1649.  
  1650.  
  1651. check_symbols()
  1652. {
  1653.     register bucket *bp;
  1654.  
  1655.     if (goal->class == UNKNOWN)
  1656.     undefined_goal(goal->name);
  1657.  
  1658.     for (bp = first_symbol; bp; bp = bp->next)
  1659.     {
  1660.     if (bp->class == UNKNOWN)
  1661.     {
  1662.         undefined_symbol_warning(bp->name);
  1663.         bp->class = TERM;
  1664.     }
  1665.     }
  1666. }
  1667.  
  1668.  
  1669. pack_symbols()
  1670. {
  1671.     register bucket *bp;
  1672.     register bucket **v;
  1673.     register int i, j, k, n;
  1674.  
  1675.     nsyms = 2;
  1676.     ntokens = 1;
  1677.     for (bp = first_symbol; bp; bp = bp->next)
  1678.     {
  1679.     ++nsyms;
  1680.     if (bp->class == TERM) ++ntokens;
  1681.     }
  1682.     start_symbol = ntokens;
  1683.     nvars = nsyms - ntokens;
  1684.  
  1685.     symbol_name = (char **) MALLOC(nsyms*sizeof(char *));
  1686.     if (symbol_name == 0) no_space();
  1687.     symbol_value = (short *) MALLOC(nsyms*sizeof(short));
  1688.     if (symbol_value == 0) no_space();
  1689.     symbol_prec = (short *) MALLOC(nsyms*sizeof(short));
  1690.     if (symbol_prec == 0) no_space();
  1691.     symbol_assoc = MALLOC(nsyms);
  1692.     if (symbol_assoc == 0) no_space();
  1693.  
  1694.     v = (bucket **) MALLOC(nsyms*sizeof(bucket *));
  1695.     if (v == 0) no_space();
  1696.  
  1697.     v[0] = 0;
  1698.     v[start_symbol] = 0;
  1699.  
  1700.     i = 1;
  1701.     j = start_symbol + 1;
  1702.     for (bp = first_symbol; bp; bp = bp->next)
  1703.     {
  1704.     if (bp->class == TERM)
  1705.         v[i++] = bp;
  1706.     else
  1707.         v[j++] = bp;
  1708.     }
  1709.     assert(i == ntokens && j == nsyms);
  1710.  
  1711.     for (i = 1; i < ntokens; ++i)
  1712.     v[i]->index = i;
  1713.  
  1714.     goal->index = start_symbol + 1;
  1715.     k = start_symbol + 2;
  1716.     while (++i < nsyms)
  1717.     if (v[i] != goal)
  1718.     {
  1719.         v[i]->index = k;
  1720.         ++k;
  1721.     }
  1722.  
  1723.     goal->value = 0;
  1724.     k = 1;
  1725.     for (i = start_symbol + 1; i < nsyms; ++i)
  1726.     {
  1727.     if (v[i] != goal)
  1728.     {
  1729.         v[i]->value = k;
  1730.         ++k;
  1731.     }
  1732.     }
  1733.  
  1734.     k = 0;
  1735.     for (i = 1; i < ntokens; ++i)
  1736.     {
  1737.     n = v[i]->value;
  1738.     if (n > 256)
  1739.     {
  1740.         for (j = k++; j > 0 && symbol_value[j-1] > n; --j)
  1741.         symbol_value[j] = symbol_value[j-1];
  1742.         symbol_value[j] = n;
  1743.     }
  1744.     }
  1745.  
  1746.     if (v[1]->value == UNDEFINED)
  1747.     v[1]->value = 256;
  1748.  
  1749.     j = 0;
  1750.     n = 257;
  1751.     for (i = 2; i < ntokens; ++i)
  1752.     {
  1753.     if (v[i]->value == UNDEFINED)
  1754.     {
  1755.         while (j < k && n == symbol_value[j])
  1756.         {
  1757.         while (++j < k && n == symbol_value[j]) continue;
  1758.         ++n;
  1759.         }
  1760.         v[i]->value = n;
  1761.         ++n;
  1762.     }
  1763.     }
  1764.  
  1765.     symbol_name[0] = name_pool + 8;
  1766.     symbol_value[0] = 0;
  1767.     symbol_prec[0] = 0;
  1768.     symbol_assoc[0] = TOKEN;
  1769.     for (i = 1; i < ntokens; ++i)
  1770.     {
  1771.     symbol_name[i] = v[i]->name;
  1772.     symbol_value[i] = v[i]->value;
  1773.     symbol_prec[i] = v[i]->prec;
  1774.     symbol_assoc[i] = v[i]->assoc;
  1775.     }
  1776.     symbol_name[start_symbol] = name_pool;
  1777.     symbol_value[start_symbol] = -1;
  1778.     symbol_prec[start_symbol] = 0;
  1779.     symbol_assoc[start_symbol] = TOKEN;
  1780.     for (++i; i < nsyms; ++i)
  1781.     {
  1782.     k = v[i]->index;
  1783.     symbol_name[k] = v[i]->name;
  1784.     symbol_value[k] = v[i]->value;
  1785.     symbol_prec[k] = v[i]->prec;
  1786.     symbol_assoc[k] = v[i]->assoc;
  1787.     }
  1788.  
  1789.     FREE(v);
  1790. }
  1791.  
  1792.  
  1793. pack_grammar()
  1794. {
  1795.     register int i, j;
  1796.     int assoc, prec;
  1797.  
  1798.     ritem = (short *) MALLOC(nitems*sizeof(short));
  1799.     if (ritem == 0) no_space();
  1800.     rlhs = (short *) MALLOC(nrules*sizeof(short));
  1801.     if (rlhs == 0) no_space();
  1802.     rrhs = (short *) MALLOC((nrules+1)*sizeof(short));
  1803.     if (rrhs == 0) no_space();
  1804.     rprec = (short *) REALLOC(rprec, nrules*sizeof(short));
  1805.     if (rprec == 0) no_space();
  1806.     rassoc = REALLOC(rassoc, nrules);
  1807.     if (rassoc == 0) no_space();
  1808.  
  1809.     ritem[0] = -1;
  1810.     ritem[1] = goal->index;
  1811.     ritem[2] = 0;
  1812.     ritem[3] = -2;
  1813.     rlhs[0] = 0;
  1814.     rlhs[1] = 0;
  1815.     rlhs[2] = start_symbol;
  1816.     rrhs[0] = 0;
  1817.     rrhs[1] = 0;
  1818.     rrhs[2] = 1;
  1819.  
  1820.     j = 4;
  1821.     for (i = 3; i < nrules; ++i)
  1822.     {
  1823.     rlhs[i] = plhs[i]->index;
  1824.     rrhs[i] = j;
  1825.     assoc = TOKEN;
  1826.     prec = 0;
  1827.     while (pitem[j])
  1828.     {
  1829.         ritem[j] = pitem[j]->index;
  1830.         if (pitem[j]->class == TERM)
  1831.         {
  1832.         prec = pitem[j]->prec;
  1833.         assoc = pitem[j]->assoc;
  1834.         }
  1835.         ++j;
  1836.     }
  1837.     ritem[j] = -i;
  1838.     ++j;
  1839.     if (rprec[i] == UNDEFINED)
  1840.     {
  1841.         rprec[i] = prec;
  1842.         rassoc[i] = assoc;
  1843.     }
  1844.     }
  1845.     rrhs[i] = j;
  1846.  
  1847.     FREE(plhs);
  1848.     FREE(pitem);
  1849. }
  1850.  
  1851.  
  1852. print_grammar()
  1853. {
  1854.     register int i, j, k;
  1855.     int spacing;
  1856.     register FILE *f = verbose_file;
  1857.  
  1858.     if (!vflag) return;
  1859.  
  1860.     k = 1;
  1861.     for (i = 2; i < nrules; ++i)
  1862.     {
  1863.     if (rlhs[i] != rlhs[i-1])
  1864.     {
  1865.         if (i != 2) fprintf(f, "\n");
  1866.         fprintf(f, "%4d  %s :", i - 2, symbol_name[rlhs[i]]);
  1867.         spacing = strlen(symbol_name[rlhs[i]]) + 1;
  1868.     }
  1869.     else
  1870.     {
  1871.         fprintf(f, "%4d  ", i - 2);
  1872.         j = spacing;
  1873.         while (--j >= 0) putc(' ', f);
  1874.         putc('|', f);
  1875.     }
  1876.  
  1877.     while (ritem[k] >= 0)
  1878.     {
  1879.         fprintf(f, " %s", symbol_name[ritem[k]]);
  1880.         ++k;
  1881.     }
  1882.     ++k;
  1883.     putc('\n', f);
  1884.     }
  1885. }
  1886.  
  1887.  
  1888. reader()
  1889. {
  1890.     write_section(banner);
  1891.                                 Cooperate();
  1892.     create_symbol_table();
  1893.                                 Cooperate();
  1894.     read_declarations();
  1895.                                 Cooperate();
  1896.     read_grammar();
  1897.                                 Cooperate();
  1898.     free_symbol_table();
  1899.                                 Cooperate();
  1900.     free_tags();
  1901.                                 Cooperate();
  1902.     pack_names();
  1903.                                 Cooperate();
  1904.     check_symbols();
  1905.                                 Cooperate();
  1906.     pack_symbols();
  1907.                                 Cooperate();
  1908.     pack_grammar();
  1909.                                 Cooperate();
  1910.     free_symbols();
  1911.                                 Cooperate();
  1912.     print_grammar();
  1913.                                 Cooperate();
  1914. }
  1915.