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