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