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