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