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
35static 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
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(void);
81static void advance_to_start(void);
82static void cachec(int);
83static void check_symbols(void);
84static void copy_action(void);
85static void copy_ident(void);
86static void copy_text(void);
87static void copy_union(void);
88static void declare_expect(int);
89static void declare_start(void);
90static void declare_tokens(int);
91static void declare_types(void);
92static char *dup_line(void);
93static void end_rule(void);
94static void expand_items(void);
95static void expand_rules(void);
96static void free_tags(void);
97static void get_line(void);
98static bucket *get_literal(void);
99static bucket *get_name(void);
100static int get_number(void);
101static char *get_tag(void);
102static int hexval(int);
103static void initialize_grammar(void);
104static void insert_empty_rule(void);
105static int is_reserved(char *);
106static int keyword(void);
107static int mark_symbol(void);
108static int nextc(void);
109static void pack_grammar(void);
110static void pack_names(void);
111static void pack_symbols(void);
112static void print_grammar(void);
113static void read_declarations(void);
114static void read_grammar(void);
115static void skip_comment(void);
116static void start_rule(bucket *, int);
117
118static void
119cachec(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
133static void
134get_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
180static char *
181dup_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
198static void
199skip_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
229static int
230nextc(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
291static int
292keyword(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
357static void
358copy_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
387static void
388copy_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
406loop:
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
519static void
520copy_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;
539loop:
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
660static int
661hexval(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
673static bucket *
674get_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
812static int
813is_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
833static bucket *
834get_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
849static int
850get_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
863static char *
864get_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
914static void
915declare_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 */
981static void
982declare_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
1020static void
1021declare_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
1049static void
1050declare_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
1068static void
1069read_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
1122static void
1123initialize_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
1154static void
1155expand_items(void)
1156{
1157    maxitems += 300;
1158    pitem = realloc(pitem, maxitems*sizeof(bucket *));
1159    if (pitem == 0) no_space();
1160}
1161
1162
1163static void
1164expand_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
1176static void
1177advance_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
1227static void
1228start_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
1241static void
1242end_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
1261static void
1262insert_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
1291static void
1292add_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
1323static void
1324copy_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;
1349loop:
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
1547static int
1548mark_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
1591static void
1592read_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
1625static void
1626free_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
1641static void
1642pack_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
1667static void
1668check_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
1686static void
1687pack_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
1811static void
1812pack_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
1871static void
1872print_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
1909void
1910reader(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}
1925