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