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