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