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