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