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