]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - usr.bin/yacc/reader.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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  * 4. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 #if 0
34 #ifndef lint
35 static char sccsid[] = "@(#)reader.c    5.7 (Berkeley) 1/20/91";
36 #endif
37 #endif
38
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
41
42 #include <limits.h>
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(void);
81 static void advance_to_start(void);
82 static void cachec(int);
83 static void check_symbols(void);
84 static void copy_action(void);
85 static void copy_ident(void);
86 static void copy_text(void);
87 static void copy_union(void);
88 static void declare_expect(int);
89 static void declare_start(void);
90 static void declare_tokens(int);
91 static void declare_types(void);
92 static char *dup_line(void);
93 static void end_rule(void);
94 static void expand_items(void);
95 static void expand_rules(void);
96 static void free_tags(void);
97 static void get_line(void);
98 static bucket *get_literal(void);
99 static bucket *get_name(void);
100 static int get_number(void);
101 static char *get_tag(void);
102 static int hexval(int);
103 static void initialize_grammar(void);
104 static void insert_empty_rule(void);
105 static int is_reserved(char *);
106 static int keyword(void);
107 static int mark_symbol(void);
108 static int nextc(void);
109 static void pack_grammar(void);
110 static void pack_names(void);
111 static void pack_symbols(void);
112 static void print_grammar(void);
113 static void read_declarations(void);
114 static void read_grammar(void);
115 static void skip_comment(void);
116 static void start_rule(bucket *, int);
117
118 static void
119 cachec(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(void)
135 {
136     FILE *f = input_file;
137     int c;
138     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(void)
182 {
183     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(void)
200 {
201     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(void)
231 {
232     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             /* FALLTHROUGH */
282
283         default:
284             cptr = s;
285             return (*s);
286         }
287     }
288 }
289
290
291 static int
292 keyword(void)
293 {
294     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(void)
359 {
360     int c;
361     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(void)
389 {
390     int c;
391     int quote;
392     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         /* FALLTHROUGH */
510
511     default:
512         putc(c, f);
513         need_newline = 1;
514         goto loop;
515     }
516 }
517
518
519 static void
520 copy_union(void)
521 {
522     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(int c)
662 {
663     if (c >= '0' && c <= '9')
664         return (c - '0');
665     if (c >= 'A' && c <= 'F')
666         return (c - 'A' + 10);
667     if (c >= 'a' && c <= 'f')
668         return (c - 'a' + 10);
669     return (-1);
670 }
671
672
673 static bucket *
674 get_literal(void)
675 {
676     int c, quote;
677     int i;
678     int n;
679     char *s;
680     bucket *bp;
681     int s_lineno = lineno;
682     char *s_line = dup_line();
683     char *s_cptr = s_line + (cptr - line);
684
685     quote = *cptr++;
686     cinc = 0;
687     for (;;)
688     {
689         c = *cptr++;
690         if (c == quote) break;
691         if (c == '\n') unterminated_string(s_lineno, s_line, s_cptr);
692         if (c == '\\')
693         {
694             char *c_cptr = cptr - 1;
695
696             c = *cptr++;
697             switch (c)
698             {
699             case '\n':
700                 get_line();
701                 if (line == 0) unterminated_string(s_lineno, s_line, s_cptr);
702                 continue;
703
704             case '0': case '1': case '2': case '3':
705             case '4': case '5': case '6': case '7':
706                 n = c - '0';
707                 c = *cptr;
708                 if (IS_OCTAL(c))
709                 {
710                     n = (n << 3) + (c - '0');
711                     c = *++cptr;
712                     if (IS_OCTAL(c))
713                     {
714                         n = (n << 3) + (c - '0');
715                         ++cptr;
716                     }
717                 }
718                 if (n > (int)UCHAR_MAX) illegal_character(c_cptr);
719                 c = n;
720                 break;
721
722             case 'x':
723                 c = *cptr++;
724                 n = hexval(c);
725                 if (n < 0 || n >= 16)
726                     illegal_character(c_cptr);
727                 for (;;)
728                 {
729                     c = *cptr;
730                     i = hexval(c);
731                     if (i < 0 || i >= 16) break;
732                     ++cptr;
733                     n = (n << 4) + i;
734                     if (n > (int)UCHAR_MAX) illegal_character(c_cptr);
735                 }
736                 c = n;
737                 break;
738
739             case 'a': c = 7; break;
740             case 'b': c = '\b'; break;
741             case 'f': c = '\f'; break;
742             case 'n': c = '\n'; break;
743             case 'r': c = '\r'; break;
744             case 't': c = '\t'; break;
745             case 'v': c = '\v'; break;
746             }
747         }
748         cachec(c);
749     }
750     free(s_line);
751
752     n = cinc;
753     s = malloc(n);
754     if (s == 0) no_space();
755
756     for (i = 0; i < n; ++i)
757         s[i] = cache[i];
758
759     cinc = 0;
760     if (n == 1)
761         cachec('\'');
762     else
763         cachec('"');
764
765     for (i = 0; i < n; ++i)
766     {
767         c = ((unsigned char *)s)[i];
768         if (c == '\\' || c == cache[0])
769         {
770             cachec('\\');
771             cachec(c);
772         }
773         else if (isprint(c))
774             cachec(c);
775         else
776         {
777             cachec('\\');
778             switch (c)
779             {
780             case 7: cachec('a'); break;
781             case '\b': cachec('b'); break;
782             case '\f': cachec('f'); break;
783             case '\n': cachec('n'); break;
784             case '\r': cachec('r'); break;
785             case '\t': cachec('t'); break;
786             case '\v': cachec('v'); break;
787             default:
788                 cachec(((c >> 6) & 7) + '0');
789                 cachec(((c >> 3) & 7) + '0');
790                 cachec((c & 7) + '0');
791                 break;
792             }
793         }
794     }
795
796     if (n == 1)
797         cachec('\'');
798     else
799         cachec('"');
800
801     cachec(NUL);
802     bp = lookup(cache);
803     bp->class = TERM;
804     if (n == 1 && bp->value == UNDEFINED)
805         bp->value = *(unsigned char *)s;
806     free(s);
807
808     return (bp);
809 }
810
811
812 static int
813 is_reserved(char *name)
814 {
815     char *s;
816
817     if (strcmp(name, ".") == 0 ||
818             strcmp(name, "$accept") == 0 ||
819             strcmp(name, "$end") == 0)
820         return (1);
821
822     if (name[0] == '$' && name[1] == '$' && isdigit(name[2]))
823     {
824         s = name + 3;
825         while (isdigit(*s)) ++s;
826         if (*s == NUL) return (1);
827     }
828
829     return (0);
830 }
831
832
833 static bucket *
834 get_name(void)
835 {
836     int c;
837
838     cinc = 0;
839     for (c = *cptr; IS_IDENT(c); c = *++cptr)
840         cachec(c);
841     cachec(NUL);
842
843     if (is_reserved(cache)) used_reserved(cache);
844
845     return (lookup(cache));
846 }
847
848
849 static int
850 get_number(void)
851 {
852     int c;
853     int n;
854
855     n = 0;
856     for (c = *cptr; isdigit(c); c = *++cptr)
857         n = 10*n + (c - '0');
858
859     return (n);
860 }
861
862
863 static char *
864 get_tag(void)
865 {
866     int c;
867     int i;
868     char *s;
869     int t_lineno = lineno;
870     char *t_line = dup_line();
871     char *t_cptr = t_line + (cptr - line);
872
873     ++cptr;
874     c = nextc();
875     if (c == EOF) unexpected_EOF();
876     if (!isalpha(c) && c != '_' && c != '$')
877         illegal_tag(t_lineno, t_line, t_cptr);
878
879     cinc = 0;
880     do { cachec(c); c = *++cptr; } while (IS_IDENT(c));
881     cachec(NUL);
882
883     c = nextc();
884     if (c == EOF) unexpected_EOF();
885     if (c != '>')
886         illegal_tag(t_lineno, t_line, t_cptr);
887     ++cptr;
888
889     for (i = 0; i < ntags; ++i)
890     {
891         if (strcmp(cache, tag_table[i]) == 0)
892             return (tag_table[i]);
893     }
894
895     if (ntags >= tagmax)
896     {
897         tagmax += 16;
898         tag_table = (char **)
899                         (tag_table ? realloc(tag_table, tagmax*sizeof(char *))
900                                    : malloc(tagmax*sizeof(char *)));
901         if (tag_table == 0) no_space();
902     }
903
904     s = malloc(cinc);
905     if  (s == 0) no_space();
906     strcpy(s, cache);
907     tag_table[ntags] = s;
908     ++ntags;
909     free(t_line);
910     return (s);
911 }
912
913
914 static void
915 declare_tokens(int assoc)
916 {
917     int c;
918     bucket *bp;
919     int value;
920     char *tag = 0;
921
922     if (assoc != TOKEN) ++prec;
923
924     c = nextc();
925     if (c == EOF) unexpected_EOF();
926     if (c == '<')
927     {
928         tag = get_tag();
929         c = nextc();
930         if (c == EOF) unexpected_EOF();
931     }
932
933     for (;;)
934     {
935         if (isalpha(c) || c == '_' || c == '.' || c == '$')
936             bp = get_name();
937         else if (c == '\'' || c == '"')
938             bp = get_literal();
939         else
940             return;
941
942         if (bp == goal) tokenized_start(bp->name);
943         bp->class = TERM;
944
945         if (tag)
946         {
947             if (bp->tag && tag != bp->tag)
948                 retyped_warning(bp->name);
949             bp->tag = tag;
950         }
951
952         if (assoc != TOKEN)
953         {
954             if (bp->prec && prec != bp->prec)
955                 reprec_warning(bp->name);
956             bp->assoc = assoc;
957             bp->prec = prec;
958         }
959
960         c = nextc();
961         if (c == EOF) unexpected_EOF();
962         value = UNDEFINED;
963         if (isdigit(c))
964         {
965             value = get_number();
966             if (bp->value != UNDEFINED && value != bp->value)
967                 revalued_warning(bp->name);
968             bp->value = value;
969             c = nextc();
970             if (c == EOF) unexpected_EOF();
971         }
972     }
973 }
974
975
976 /*
977  * %expect requires special handling
978  * as it really isn't part of the yacc
979  * grammar only a flag for yacc proper.
980  */
981 static void
982 declare_expect(int assoc)
983 {
984     int c;
985
986     if (assoc != EXPECT) ++prec;
987
988     /*
989      * Stay away from nextc - doesn't
990      * detect EOL and will read to EOF.
991      */
992     c = *++cptr;
993     if (c == EOF) unexpected_EOF();
994
995     for(;;)
996     {
997         if (isdigit(c))
998         {
999             SRexpect = get_number();
1000             break;
1001         }
1002         /*
1003          * Looking for number before EOL.
1004          * Spaces, tabs, and numbers are ok,
1005          * words, punc., etc. are syntax errors.
1006          */
1007         else if (c == '\n' || isalpha(c) || !isspace(c))
1008         {
1009             syntax_error(lineno, line, cptr);
1010         }
1011         else
1012         {
1013             c = *++cptr;
1014             if (c == EOF) unexpected_EOF();
1015         }
1016     }
1017 }
1018
1019
1020 static void
1021 declare_types(void)
1022 {
1023     int c;
1024     bucket *bp;
1025     char *tag;
1026
1027     c = nextc();
1028     if (c == EOF) unexpected_EOF();
1029     if (c != '<') syntax_error(lineno, line, cptr);
1030     tag = get_tag();
1031
1032     for (;;)
1033     {
1034         c = nextc();
1035         if (isalpha(c) || c == '_' || c == '.' || c == '$')
1036             bp = get_name();
1037         else if (c == '\'' || c == '"')
1038             bp = get_literal();
1039         else
1040             return;
1041
1042         if (bp->tag && tag != bp->tag)
1043             retyped_warning(bp->name);
1044         bp->tag = tag;
1045     }
1046 }
1047
1048
1049 static void
1050 declare_start(void)
1051 {
1052     int c;
1053     bucket *bp;
1054
1055     c = nextc();
1056     if (c == EOF) unexpected_EOF();
1057     if (!isalpha(c) && c != '_' && c != '.' && c != '$')
1058         syntax_error(lineno, line, cptr);
1059     bp = get_name();
1060     if (bp->class == TERM)
1061         terminal_start(bp->name);
1062     if (goal && goal != bp)
1063         restarted_warning();
1064     goal = bp;
1065 }
1066
1067
1068 static void
1069 read_declarations(void)
1070 {
1071     int c, k;
1072
1073     cache_size = 256;
1074     cache = malloc(cache_size);
1075     if (cache == 0) no_space();
1076
1077     for (;;)
1078     {
1079         c = nextc();
1080         if (c == EOF) unexpected_EOF();
1081         if (c != '%') syntax_error(lineno, line, cptr);
1082         switch (k = keyword())
1083         {
1084         case MARK:
1085             return;
1086
1087         case IDENT:
1088             copy_ident();
1089             break;
1090
1091         case TEXT:
1092             copy_text();
1093             break;
1094
1095         case UNION:
1096             copy_union();
1097             break;
1098
1099         case TOKEN:
1100         case LEFT:
1101         case RIGHT:
1102         case NONASSOC:
1103             declare_tokens(k);
1104             break;
1105
1106         case EXPECT:
1107             declare_expect(k);
1108             break;
1109
1110         case TYPE:
1111             declare_types();
1112             break;
1113
1114         case START:
1115             declare_start();
1116             break;
1117         }
1118     }
1119 }
1120
1121
1122 static void
1123 initialize_grammar(void)
1124 {
1125     nitems = 4;
1126     maxitems = 300;
1127     pitem = malloc(maxitems*sizeof(bucket *));
1128     if (pitem == 0) no_space();
1129     pitem[0] = 0;
1130     pitem[1] = 0;
1131     pitem[2] = 0;
1132     pitem[3] = 0;
1133
1134     nrules = 3;
1135     maxrules = 100;
1136     plhs = malloc(maxrules*sizeof(bucket *));
1137     if (plhs == 0) no_space();
1138     plhs[0] = 0;
1139     plhs[1] = 0;
1140     plhs[2] = 0;
1141     rprec = malloc(maxrules*sizeof(short));
1142     if (rprec == 0) no_space();
1143     rprec[0] = 0;
1144     rprec[1] = 0;
1145     rprec[2] = 0;
1146     rassoc = malloc(maxrules*sizeof(char));
1147     if (rassoc == 0) no_space();
1148     rassoc[0] = TOKEN;
1149     rassoc[1] = TOKEN;
1150     rassoc[2] = TOKEN;
1151 }
1152
1153
1154 static void
1155 expand_items(void)
1156 {
1157     maxitems += 300;
1158     pitem = realloc(pitem, maxitems*sizeof(bucket *));
1159     if (pitem == 0) no_space();
1160 }
1161
1162
1163 static void
1164 expand_rules(void)
1165 {
1166     maxrules += 100;
1167     plhs = realloc(plhs, maxrules*sizeof(bucket *));
1168     if (plhs == 0) no_space();
1169     rprec = realloc(rprec, maxrules*sizeof(short));
1170     if (rprec == 0) no_space();
1171     rassoc = realloc(rassoc, maxrules*sizeof(char));
1172     if (rassoc == 0) no_space();
1173 }
1174
1175
1176 static void
1177 advance_to_start(void)
1178 {
1179     int c;
1180     bucket *bp;
1181     char *s_cptr;
1182     int s_lineno;
1183
1184     for (;;)
1185     {
1186         c = nextc();
1187         if (c != '%') break;
1188         s_cptr = cptr;
1189         switch (keyword())
1190         {
1191         case MARK:
1192             no_grammar();
1193
1194         case TEXT:
1195             copy_text();
1196             break;
1197
1198         case START:
1199             declare_start();
1200             break;
1201
1202         default:
1203             syntax_error(lineno, line, s_cptr);
1204         }
1205     }
1206
1207     c = nextc();
1208     if (!isalpha(c) && c != '_' && c != '.' && c != '_')
1209         syntax_error(lineno, line, cptr);
1210     bp = get_name();
1211     if (goal == 0)
1212     {
1213         if (bp->class == TERM)
1214             terminal_start(bp->name);
1215         goal = bp;
1216     }
1217
1218     s_lineno = lineno;
1219     c = nextc();
1220     if (c == EOF) unexpected_EOF();
1221     if (c != ':') syntax_error(lineno, line, cptr);
1222     start_rule(bp, s_lineno);
1223     ++cptr;
1224 }
1225
1226
1227 static void
1228 start_rule(bucket *bp, int s_lineno)
1229 {
1230     if (bp->class == TERM)
1231         terminal_lhs(s_lineno);
1232     bp->class = NONTERM;
1233     if (nrules >= maxrules)
1234         expand_rules();
1235     plhs[nrules] = bp;
1236     rprec[nrules] = UNDEFINED;
1237     rassoc[nrules] = TOKEN;
1238 }
1239
1240
1241 static void
1242 end_rule(void)
1243 {
1244     int i;
1245
1246     if (!last_was_action && plhs[nrules]->tag)
1247     {
1248         for (i = nitems - 1; pitem[i]; --i) continue;
1249         if (pitem[i+1] == 0 || pitem[i+1]->tag != plhs[nrules]->tag)
1250             default_action_warning();
1251     }
1252
1253     last_was_action = 0;
1254     if (nitems >= maxitems) expand_items();
1255     pitem[nitems] = 0;
1256     ++nitems;
1257     ++nrules;
1258 }
1259
1260
1261 static void
1262 insert_empty_rule(void)
1263 {
1264     bucket *bp, **bpp;
1265
1266     assert(cache);
1267     sprintf(cache, "$$%d", ++gensym);
1268     bp = make_bucket(cache);
1269     last_symbol->next = bp;
1270     last_symbol = bp;
1271     bp->tag = plhs[nrules]->tag;
1272     bp->class = NONTERM;
1273
1274     if ((nitems += 2) > maxitems)
1275         expand_items();
1276     bpp = pitem + nitems - 1;
1277     *bpp-- = bp;
1278     while ((bpp[0] = bpp[-1])) --bpp;
1279
1280     if (++nrules >= maxrules)
1281         expand_rules();
1282     plhs[nrules] = plhs[nrules-1];
1283     plhs[nrules-1] = bp;
1284     rprec[nrules] = rprec[nrules-1];
1285     rprec[nrules-1] = 0;
1286     rassoc[nrules] = rassoc[nrules-1];
1287     rassoc[nrules-1] = TOKEN;
1288 }
1289
1290
1291 static void
1292 add_symbol(void)
1293 {
1294     int c;
1295     bucket *bp;
1296     int s_lineno = lineno;
1297
1298     c = *cptr;
1299     if (c == '\'' || c == '"')
1300         bp = get_literal();
1301     else
1302         bp = get_name();
1303
1304     c = nextc();
1305     if (c == ':')
1306     {
1307         end_rule();
1308         start_rule(bp, s_lineno);
1309         ++cptr;
1310         return;
1311     }
1312
1313     if (last_was_action)
1314         insert_empty_rule();
1315     last_was_action = 0;
1316
1317     if (++nitems > maxitems)
1318         expand_items();
1319     pitem[nitems-1] = bp;
1320 }
1321
1322
1323 static void
1324 copy_action(void)
1325 {
1326     int c;
1327     int i, n;
1328     int depth;
1329     int quote;
1330     char *tag;
1331     FILE *f = action_file;
1332     int a_lineno = lineno;
1333     char *a_line = dup_line();
1334     char *a_cptr = a_line + (cptr - line);
1335
1336     if (last_was_action)
1337         insert_empty_rule();
1338     last_was_action = 1;
1339
1340     fprintf(f, "case %d:\n", nrules - 2);
1341     if (!lflag)
1342         fprintf(f, line_format, lineno, input_file_name);
1343     if (*cptr == '=') ++cptr;
1344
1345     n = 0;
1346     for (i = nitems - 1; pitem[i]; --i) ++n;
1347
1348     depth = 0;
1349 loop:
1350     c = *cptr;
1351     if (c == '$')
1352     {
1353         if (cptr[1] == '<')
1354         {
1355             int d_lineno = lineno;
1356             char *d_line = dup_line();
1357             char *d_cptr = d_line + (cptr - line);
1358
1359             ++cptr;
1360             tag = get_tag();
1361             c = *cptr;
1362             if (c == '$')
1363             {
1364                 fprintf(f, "yyval.%s", tag);
1365                 ++cptr;
1366                 free(d_line);
1367                 goto loop;
1368             }
1369             else if (isdigit(c))
1370             {
1371                 i = get_number();
1372                 if (i > n) dollar_warning(d_lineno, i);
1373                 fprintf(f, "yyvsp[%d].%s", i - n, tag);
1374                 free(d_line);
1375                 goto loop;
1376             }
1377             else if (c == '-' && isdigit(cptr[1]))
1378             {
1379                 ++cptr;
1380                 i = -get_number() - n;
1381                 fprintf(f, "yyvsp[%d].%s", i, tag);
1382                 free(d_line);
1383                 goto loop;
1384             }
1385             else
1386                 dollar_error(d_lineno, d_line, d_cptr);
1387         }
1388         else if (cptr[1] == '$')
1389         {
1390             if (ntags)
1391             {
1392                 tag = plhs[nrules]->tag;
1393                 if (tag == 0) untyped_lhs();
1394                 fprintf(f, "yyval.%s", tag);
1395             }
1396             else
1397                 fprintf(f, "yyval");
1398             cptr += 2;
1399             goto loop;
1400         }
1401         else if (isdigit(cptr[1]))
1402         {
1403             ++cptr;
1404             i = get_number();
1405             if (ntags)
1406             {
1407                 if (i <= 0 || i > n)
1408                     unknown_rhs(i);
1409                 tag = pitem[nitems + i - n - 1]->tag;
1410                 if (tag == 0) untyped_rhs(i, pitem[nitems + i - n - 1]->name);
1411                 fprintf(f, "yyvsp[%d].%s", i - n, tag);
1412             }
1413             else
1414             {
1415                 if (i > n)
1416                     dollar_warning(lineno, i);
1417                 fprintf(f, "yyvsp[%d]", i - n);
1418             }
1419             goto loop;
1420         }
1421         else if (cptr[1] == '-')
1422         {
1423             cptr += 2;
1424             i = get_number();
1425             if (ntags)
1426                 unknown_rhs(-i);
1427             fprintf(f, "yyvsp[%d]", -i - n);
1428             goto loop;
1429         }
1430     }
1431     if (isalpha(c) || c == '_' || c == '$')
1432     {
1433         do
1434         {
1435             putc(c, f);
1436             c = *++cptr;
1437         } while (isalnum(c) || c == '_' || c == '$');
1438         goto loop;
1439     }
1440     putc(c, f);
1441     ++cptr;
1442     switch (c)
1443     {
1444     case '\n':
1445     next_line:
1446         get_line();
1447         if (line) goto loop;
1448         unterminated_action(a_lineno, a_line, a_cptr);
1449
1450     case ';':
1451         if (depth > 0) goto loop;
1452         fprintf(f, "\nbreak;\n");
1453         return;
1454
1455     case '{':
1456         ++depth;
1457         goto loop;
1458
1459     case '}':
1460         if (--depth > 0) goto loop;
1461         fprintf(f, "\nbreak;\n");
1462         return;
1463
1464     case '\'':
1465     case '"':
1466         {
1467             int s_lineno = lineno;
1468             char *s_line = dup_line();
1469             char *s_cptr = s_line + (cptr - line - 1);
1470
1471             quote = c;
1472             for (;;)
1473             {
1474                 c = *cptr++;
1475                 putc(c, f);
1476                 if (c == quote)
1477                 {
1478                     free(s_line);
1479                     goto loop;
1480                 }
1481                 if (c == '\n')
1482                     unterminated_string(s_lineno, s_line, s_cptr);
1483                 if (c == '\\')
1484                 {
1485                     c = *cptr++;
1486                     putc(c, f);
1487                     if (c == '\n')
1488                     {
1489                         get_line();
1490                         if (line == 0)
1491                             unterminated_string(s_lineno, s_line, s_cptr);
1492                     }
1493                 }
1494             }
1495         }
1496
1497     case '/':
1498         c = *cptr;
1499         if (c == '/')
1500         {
1501             putc('*', f);
1502             while ((c = *++cptr) != '\n')
1503             {
1504                 if (c == '*' && cptr[1] == '/')
1505                     fprintf(f, "* ");
1506                 else
1507                     putc(c, f);
1508             }
1509             fprintf(f, "*/\n");
1510             goto next_line;
1511         }
1512         if (c == '*')
1513         {
1514             int c_lineno = lineno;
1515             char *c_line = dup_line();
1516             char *c_cptr = c_line + (cptr - line - 1);
1517
1518             putc('*', f);
1519             ++cptr;
1520             for (;;)
1521             {
1522                 c = *cptr++;
1523                 putc(c, f);
1524                 if (c == '*' && *cptr == '/')
1525                 {
1526                     putc('/', f);
1527                     ++cptr;
1528                     free(c_line);
1529                     goto loop;
1530                 }
1531                 if (c == '\n')
1532                 {
1533                     get_line();
1534                     if (line == 0)
1535                         unterminated_comment(c_lineno, c_line, c_cptr);
1536                 }
1537             }
1538         }
1539         goto loop;
1540
1541     default:
1542         goto loop;
1543     }
1544 }
1545
1546
1547 static int
1548 mark_symbol(void)
1549 {
1550     int c;
1551     bucket *bp = NULL;
1552
1553     c = cptr[1];
1554     if (c == '%' || c == '\\')
1555     {
1556         cptr += 2;
1557         return (1);
1558     }
1559
1560     if (c == '=')
1561         cptr += 2;
1562     else if ((c == 'p' || c == 'P') &&
1563              ((c = cptr[2]) == 'r' || c == 'R') &&
1564              ((c = cptr[3]) == 'e' || c == 'E') &&
1565              ((c = cptr[4]) == 'c' || c == 'C') &&
1566              ((c = cptr[5], !IS_IDENT(c))))
1567         cptr += 5;
1568     else
1569         syntax_error(lineno, line, cptr);
1570
1571     c = nextc();
1572     if (isalpha(c) || c == '_' || c == '.' || c == '$')
1573         bp = get_name();
1574     else if (c == '\'' || c == '"')
1575         bp = get_literal();
1576     else
1577     {
1578         syntax_error(lineno, line, cptr);
1579         /*NOTREACHED*/
1580     }
1581
1582     if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
1583         prec_redeclared();
1584
1585     rprec[nrules] = bp->prec;
1586     rassoc[nrules] = bp->assoc;
1587     return (0);
1588 }
1589
1590
1591 static void
1592 read_grammar(void)
1593 {
1594     int c;
1595
1596     initialize_grammar();
1597     advance_to_start();
1598
1599     for (;;)
1600     {
1601         c = nextc();
1602         if (c == EOF) break;
1603         if (isalpha(c) || c == '_' || c == '.' || c == '$' || c == '\'' ||
1604                 c == '"')
1605             add_symbol();
1606         else if (c == '{' || c == '=')
1607             copy_action();
1608         else if (c == '|')
1609         {
1610             end_rule();
1611             start_rule(plhs[nrules-1], 0);
1612             ++cptr;
1613         }
1614         else if (c == '%')
1615         {
1616             if (mark_symbol()) break;
1617         }
1618         else
1619             syntax_error(lineno, line, cptr);
1620     }
1621     end_rule();
1622 }
1623
1624
1625 static void
1626 free_tags(void)
1627 {
1628     int i;
1629
1630     if (tag_table == 0) return;
1631
1632     for (i = 0; i < ntags; ++i)
1633     {
1634         assert(tag_table[i]);
1635         free(tag_table[i]);
1636     }
1637     free(tag_table);
1638 }
1639
1640
1641 static void
1642 pack_names(void)
1643 {
1644     bucket *bp;
1645     char *p, *s, *t;
1646
1647     name_pool_size = 13;  /* 13 == sizeof("$end") + sizeof("$accept") */
1648     for (bp = first_symbol; bp; bp = bp->next)
1649         name_pool_size += strlen(bp->name) + 1;
1650     name_pool = malloc(name_pool_size);
1651     if (name_pool == 0) no_space();
1652
1653     strcpy(name_pool, "$accept");
1654     strcpy(name_pool+8, "$end");
1655     t = name_pool + 13;
1656     for (bp = first_symbol; bp; bp = bp->next)
1657     {
1658         p = t;
1659         s = bp->name;
1660         while ((*t++ = *s++)) continue;
1661         free(bp->name);
1662         bp->name = p;
1663     }
1664 }
1665
1666
1667 static void
1668 check_symbols(void)
1669 {
1670     bucket *bp;
1671
1672     if (goal->class == UNKNOWN)
1673         undefined_goal(goal->name);
1674
1675     for (bp = first_symbol; bp; bp = bp->next)
1676     {
1677         if (bp->class == UNKNOWN)
1678         {
1679             undefined_symbol_warning(bp->name);
1680             bp->class = TERM;
1681         }
1682     }
1683 }
1684
1685
1686 static void
1687 pack_symbols(void)
1688 {
1689     bucket *bp;
1690     bucket **v;
1691     int i, j, k, n;
1692
1693     nsyms = 2;
1694     ntokens = 1;
1695     for (bp = first_symbol; bp; bp = bp->next)
1696     {
1697         ++nsyms;
1698         if (bp->class == TERM) ++ntokens;
1699     }
1700     start_symbol = ntokens;
1701     nvars = nsyms - ntokens;
1702
1703     symbol_name = malloc(nsyms*sizeof(char *));
1704     if (symbol_name == 0) no_space();
1705     symbol_value = malloc(nsyms*sizeof(short));
1706     if (symbol_value == 0) no_space();
1707     symbol_prec = malloc(nsyms*sizeof(short));
1708     if (symbol_prec == 0) no_space();
1709     symbol_assoc = malloc(nsyms);
1710     if (symbol_assoc == 0) no_space();
1711
1712     v = malloc(nsyms*sizeof(bucket *));
1713     if (v == 0) no_space();
1714
1715     v[0] = 0;
1716     v[start_symbol] = 0;
1717
1718     i = 1;
1719     j = start_symbol + 1;
1720     for (bp = first_symbol; bp; bp = bp->next)
1721     {
1722         if (bp->class == TERM)
1723             v[i++] = bp;
1724         else
1725             v[j++] = bp;
1726     }
1727     assert(i == ntokens && j == nsyms);
1728
1729     for (i = 1; i < ntokens; ++i)
1730         v[i]->index = i;
1731
1732     goal->index = start_symbol + 1;
1733     k = start_symbol + 2;
1734     while (++i < nsyms)
1735         if (v[i] != goal)
1736         {
1737             v[i]->index = k;
1738             ++k;
1739         }
1740
1741     goal->value = 0;
1742     k = 1;
1743     for (i = start_symbol + 1; i < nsyms; ++i)
1744     {
1745         if (v[i] != goal)
1746         {
1747             v[i]->value = k;
1748             ++k;
1749         }
1750     }
1751
1752     k = 0;
1753     for (i = 1; i < ntokens; ++i)
1754     {
1755         n = v[i]->value;
1756         if (n > 256)
1757         {
1758             for (j = k++; j > 0 && symbol_value[j-1] > n; --j)
1759                 symbol_value[j] = symbol_value[j-1];
1760             symbol_value[j] = n;
1761         }
1762     }
1763
1764     if (v[1]->value == UNDEFINED)
1765         v[1]->value = 256;
1766
1767     j = 0;
1768     n = 257;
1769     for (i = 2; i < ntokens; ++i)
1770     {
1771         if (v[i]->value == UNDEFINED)
1772         {
1773             while (j < k && n == symbol_value[j])
1774             {
1775                 while (++j < k && n == symbol_value[j]) continue;
1776                 ++n;
1777             }
1778             v[i]->value = n;
1779             ++n;
1780         }
1781     }
1782
1783     symbol_name[0] = name_pool + 8;
1784     symbol_value[0] = 0;
1785     symbol_prec[0] = 0;
1786     symbol_assoc[0] = TOKEN;
1787     for (i = 1; i < ntokens; ++i)
1788     {
1789         symbol_name[i] = v[i]->name;
1790         symbol_value[i] = v[i]->value;
1791         symbol_prec[i] = v[i]->prec;
1792         symbol_assoc[i] = v[i]->assoc;
1793     }
1794     symbol_name[start_symbol] = name_pool;
1795     symbol_value[start_symbol] = -1;
1796     symbol_prec[start_symbol] = 0;
1797     symbol_assoc[start_symbol] = TOKEN;
1798     for (++i; i < nsyms; ++i)
1799     {
1800         k = v[i]->index;
1801         symbol_name[k] = v[i]->name;
1802         symbol_value[k] = v[i]->value;
1803         symbol_prec[k] = v[i]->prec;
1804         symbol_assoc[k] = v[i]->assoc;
1805     }
1806
1807     free(v);
1808 }
1809
1810
1811 static void
1812 pack_grammar(void)
1813 {
1814     int i, j;
1815     int assoc, preced;
1816
1817     ritem = malloc(nitems*sizeof(short));
1818     if (ritem == 0) no_space();
1819     rlhs = malloc(nrules*sizeof(short));
1820     if (rlhs == 0) no_space();
1821     rrhs = malloc((nrules+1)*sizeof(short));
1822     if (rrhs == 0) no_space();
1823     rprec = realloc(rprec, nrules*sizeof(short));
1824     if (rprec == 0) no_space();
1825     rassoc = realloc(rassoc, nrules);
1826     if (rassoc == 0) no_space();
1827
1828     ritem[0] = -1;
1829     ritem[1] = goal->index;
1830     ritem[2] = 0;
1831     ritem[3] = -2;
1832     rlhs[0] = 0;
1833     rlhs[1] = 0;
1834     rlhs[2] = start_symbol;
1835     rrhs[0] = 0;
1836     rrhs[1] = 0;
1837     rrhs[2] = 1;
1838
1839     j = 4;
1840     for (i = 3; i < nrules; ++i)
1841     {
1842         rlhs[i] = plhs[i]->index;
1843         rrhs[i] = j;
1844         assoc = TOKEN;
1845         preced = 0;
1846         while (pitem[j])
1847         {
1848             ritem[j] = pitem[j]->index;
1849             if (pitem[j]->class == TERM)
1850             {
1851                 preced = pitem[j]->prec;
1852                 assoc = pitem[j]->assoc;
1853             }
1854             ++j;
1855         }
1856         ritem[j] = -i;
1857         ++j;
1858         if (rprec[i] == UNDEFINED)
1859         {
1860             rprec[i] = preced;
1861             rassoc[i] = assoc;
1862         }
1863     }
1864     rrhs[i] = j;
1865
1866     free(plhs);
1867     free(pitem);
1868 }
1869
1870
1871 static void
1872 print_grammar(void)
1873 {
1874     int i, j, k;
1875     int spacing;
1876     FILE *f = verbose_file;
1877
1878     if (!vflag) return;
1879
1880     k = 1;
1881     spacing = 0;
1882     for (i = 2; i < nrules; ++i)
1883     {
1884         if (rlhs[i] != rlhs[i-1])
1885         {
1886             if (i != 2) fprintf(f, "\n");
1887             fprintf(f, "%4d  %s :", i - 2, symbol_name[rlhs[i]]);
1888             spacing = strlen(symbol_name[rlhs[i]]) + 1;
1889         }
1890         else
1891         {
1892             fprintf(f, "%4d  ", i - 2);
1893             j = spacing;
1894             while (--j >= 0) putc(' ', f);
1895             putc('|', f);
1896         }
1897
1898         while (ritem[k] >= 0)
1899         {
1900             fprintf(f, " %s", symbol_name[ritem[k]]);
1901             ++k;
1902         }
1903         ++k;
1904         putc('\n', f);
1905     }
1906 }
1907
1908
1909 void
1910 reader(void)
1911 {
1912     write_section(banner);
1913     create_symbol_table();
1914     read_declarations();
1915     read_grammar();
1916     free_symbol_table();
1917     free_tags();
1918     pack_names();
1919     check_symbols();
1920     pack_symbols();
1921     pack_grammar();
1922     free_symbols();
1923     print_grammar();
1924 }