xref: /openbsd/usr.bin/yacc/reader.c (revision 404b540a)
1 /*	$OpenBSD: reader.c,v 1.20 2006/04/21 07:38:16 deraadt 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, "#ifndef YYSTYPE_DEFINED\n");
535     fprintf(text_file, "#define YYSTYPE_DEFINED\n");
536     fprintf(text_file, "typedef union");
537     if (dflag) fprintf(union_file, "#ifndef YYSTYPE_DEFINED\n");
538     if (dflag) fprintf(union_file, "#define YYSTYPE_DEFINED\n");
539     if (dflag) fprintf(union_file, "typedef union");
540 
541     depth = 0;
542 loop:
543     c = *cptr++;
544     putc(c, text_file);
545     if (dflag) putc(c, union_file);
546     switch (c)
547     {
548     case '\n':
549     next_line:
550 	get_line();
551 	if (line == 0) unterminated_union(u_lineno, u_line, u_cptr);
552 	goto loop;
553 
554     case '{':
555 	++depth;
556 	goto loop;
557 
558     case '}':
559 	if (--depth == 0)
560 	{
561 	    fprintf(text_file, " YYSTYPE;\n");
562 	    fprintf(text_file, "#endif /* YYSTYPE_DEFINED */\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 
664 int
665 hexval(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 
677 bucket *
678 get_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 > MAXCHAR) 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 > MAXCHAR) 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 
816 int
817 is_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 
837 bucket *
838 get_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 
853 int
854 get_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 
867 char *
868 get_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     FREE(t_line);
892     ++cptr;
893 
894     for (i = 0; i < ntags; ++i)
895     {
896 	if (strcmp(cache, tag_table[i]) == 0)
897 	    return (tag_table[i]);
898     }
899 
900     if (ntags >= tagmax)
901     {
902 	tagmax += 16;
903 	tag_table = (char **)
904 			(tag_table ? REALLOC(tag_table, tagmax*sizeof(char *))
905 				   : MALLOC(tagmax*sizeof(char *)));
906 	if (tag_table == 0) no_space();
907     }
908 
909     s = MALLOC(cinc);
910     if  (s == 0) no_space();
911     strlcpy(s, cache, cinc);
912     tag_table[ntags] = s;
913     ++ntags;
914     return (s);
915 }
916 
917 
918 void
919 declare_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  */
985 void
986 declare_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 
1024 void
1025 declare_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 
1053 void
1054 declare_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 
1072 void
1073 read_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 
1126 void
1127 initialize_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 
1158 void
1159 expand_items(void)
1160 {
1161     maxitems += 300;
1162     pitem = (bucket **) REALLOC(pitem, maxitems*sizeof(bucket *));
1163     if (pitem == 0) no_space();
1164 }
1165 
1166 
1167 void
1168 expand_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 
1180 void
1181 advance_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 
1231 void
1232 start_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 
1245 void
1246 end_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 
1265 void
1266 insert_empty_rule(void)
1267 {
1268     bucket *bp, **bpp;
1269 
1270     assert(cache);
1271     snprintf(cache, cache_size, "$$%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 
1295 void
1296 add_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 
1327 void
1328 copy_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;
1353 loop:
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 	FREE(a_line);
1458 	return;
1459 
1460     case '{':
1461 	++depth;
1462 	goto loop;
1463 
1464     case '}':
1465 	if (--depth > 0) goto loop;
1466 	fprintf(f, "\nbreak;\n");
1467 	FREE(a_line);
1468 	return;
1469 
1470     case '\'':
1471     case '"':
1472 	{
1473 	    int s_lineno = lineno;
1474 	    char *s_line = dup_line();
1475 	    char *s_cptr = s_line + (cptr - line - 1);
1476 
1477 	    quote = c;
1478 	    for (;;)
1479 	    {
1480 		c = *cptr++;
1481 		putc(c, f);
1482 		if (c == quote)
1483 		{
1484 		    FREE(s_line);
1485 		    goto loop;
1486 		}
1487 		if (c == '\n')
1488 		    unterminated_string(s_lineno, s_line, s_cptr);
1489 		if (c == '\\')
1490 		{
1491 		    c = *cptr++;
1492 		    putc(c, f);
1493 		    if (c == '\n')
1494 		    {
1495 			get_line();
1496 			if (line == 0)
1497 			    unterminated_string(s_lineno, s_line, s_cptr);
1498 		    }
1499 		}
1500 	    }
1501 	}
1502 
1503     case '/':
1504 	c = *cptr;
1505 	if (c == '/')
1506 	{
1507 	    putc('*', f);
1508 	    while ((c = *++cptr) != '\n')
1509 	    {
1510 		if (c == '*' && cptr[1] == '/')
1511 		    fprintf(f, "* ");
1512 		else
1513 		    putc(c, f);
1514 	    }
1515 	    fprintf(f, "*/\n");
1516 	    goto next_line;
1517 	}
1518 	if (c == '*')
1519 	{
1520 	    int c_lineno = lineno;
1521 	    char *c_line = dup_line();
1522 	    char *c_cptr = c_line + (cptr - line - 1);
1523 
1524 	    putc('*', f);
1525 	    ++cptr;
1526 	    for (;;)
1527 	    {
1528 		c = *cptr++;
1529 		putc(c, f);
1530 		if (c == '*' && *cptr == '/')
1531 		{
1532 		    putc('/', f);
1533 		    ++cptr;
1534 		    FREE(c_line);
1535 		    goto loop;
1536 		}
1537 		if (c == '\n')
1538 		{
1539 		    get_line();
1540 		    if (line == 0)
1541 			unterminated_comment(c_lineno, c_line, c_cptr);
1542 		}
1543 	    }
1544 	}
1545 	goto loop;
1546 
1547     default:
1548 	goto loop;
1549     }
1550 }
1551 
1552 
1553 int
1554 mark_symbol(void)
1555 {
1556     int c;
1557     bucket *bp = NULL;
1558 
1559     c = cptr[1];
1560     if (c == '%' || c == '\\')
1561     {
1562 	cptr += 2;
1563 	return (1);
1564     }
1565 
1566     if (c == '=')
1567 	cptr += 2;
1568     else if ((c == 'p' || c == 'P') &&
1569 	     ((c = cptr[2]) == 'r' || c == 'R') &&
1570 	     ((c = cptr[3]) == 'e' || c == 'E') &&
1571 	     ((c = cptr[4]) == 'c' || c == 'C') &&
1572 	     ((c = cptr[5], !IS_IDENT(c))))
1573 	cptr += 5;
1574     else
1575 	syntax_error(lineno, line, cptr);
1576 
1577     c = nextc();
1578     if (isalpha(c) || c == '_' || c == '.' || c == '$')
1579 	bp = get_name();
1580     else if (c == '\'' || c == '"')
1581 	bp = get_literal();
1582     else
1583     {
1584 	syntax_error(lineno, line, cptr);
1585 	/*NOTREACHED*/
1586     }
1587 
1588     if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
1589 	prec_redeclared();
1590 
1591     rprec[nrules] = bp->prec;
1592     rassoc[nrules] = bp->assoc;
1593     return (0);
1594 }
1595 
1596 
1597 void
1598 read_grammar(void)
1599 {
1600     int c;
1601 
1602     initialize_grammar();
1603     advance_to_start();
1604 
1605     for (;;)
1606     {
1607 	c = nextc();
1608 	if (c == EOF) break;
1609 	if (isalpha(c) || c == '_' || c == '.' || c == '$' || c == '\'' ||
1610 		c == '"')
1611 	    add_symbol();
1612 	else if (c == '{' || c == '=')
1613 	    copy_action();
1614 	else if (c == '|')
1615 	{
1616 	    end_rule();
1617 	    start_rule(plhs[nrules-1], 0);
1618 	    ++cptr;
1619 	}
1620 	else if (c == '%')
1621 	{
1622 	    if (mark_symbol()) break;
1623 	}
1624 	else
1625 	    syntax_error(lineno, line, cptr);
1626     }
1627     end_rule();
1628 }
1629 
1630 
1631 void
1632 free_tags(void)
1633 {
1634     int i;
1635 
1636     if (tag_table == 0) return;
1637 
1638     for (i = 0; i < ntags; ++i)
1639     {
1640 	assert(tag_table[i]);
1641 	FREE(tag_table[i]);
1642     }
1643     FREE(tag_table);
1644 }
1645 
1646 
1647 void
1648 pack_names(void)
1649 {
1650     bucket *bp;
1651     char *p, *s, *t;
1652 
1653     name_pool_size = 13;  /* 13 == sizeof("$end") + sizeof("$accept") */
1654     for (bp = first_symbol; bp; bp = bp->next)
1655 	name_pool_size += strlen(bp->name) + 1;
1656     name_pool = MALLOC(name_pool_size);
1657     if (name_pool == 0) no_space();
1658 
1659     strlcpy(name_pool, "$accept", name_pool_size);
1660     strlcpy(name_pool+8, "$end", name_pool_size - 8);
1661     t = name_pool + 13;
1662     for (bp = first_symbol; bp; bp = bp->next)
1663     {
1664 	p = t;
1665 	s = bp->name;
1666 	while ((*t++ = *s++)) continue;
1667 	FREE(bp->name);
1668 	bp->name = p;
1669     }
1670 }
1671 
1672 
1673 void
1674 check_symbols(void)
1675 {
1676     bucket *bp;
1677 
1678     if (goal->class == UNKNOWN)
1679 	undefined_goal(goal->name);
1680 
1681     for (bp = first_symbol; bp; bp = bp->next)
1682     {
1683 	if (bp->class == UNKNOWN)
1684 	{
1685 	    undefined_symbol_warning(bp->name);
1686 	    bp->class = TERM;
1687 	}
1688     }
1689 }
1690 
1691 
1692 void
1693 pack_symbols(void)
1694 {
1695     bucket *bp;
1696     bucket **v;
1697     int i, j, k, n;
1698 
1699     nsyms = 2;
1700     ntokens = 1;
1701     for (bp = first_symbol; bp; bp = bp->next)
1702     {
1703 	++nsyms;
1704 	if (bp->class == TERM) ++ntokens;
1705     }
1706     start_symbol = ntokens;
1707     nvars = nsyms - ntokens;
1708 
1709     symbol_name = (char **) MALLOC(nsyms*sizeof(char *));
1710     if (symbol_name == 0) no_space();
1711     symbol_value = (short *) MALLOC(nsyms*sizeof(short));
1712     if (symbol_value == 0) no_space();
1713     symbol_prec = (short *) MALLOC(nsyms*sizeof(short));
1714     if (symbol_prec == 0) no_space();
1715     symbol_assoc = MALLOC(nsyms);
1716     if (symbol_assoc == 0) no_space();
1717 
1718     v = (bucket **) MALLOC(nsyms*sizeof(bucket *));
1719     if (v == 0) no_space();
1720 
1721     v[0] = 0;
1722     v[start_symbol] = 0;
1723 
1724     i = 1;
1725     j = start_symbol + 1;
1726     for (bp = first_symbol; bp; bp = bp->next)
1727     {
1728 	if (bp->class == TERM)
1729 	    v[i++] = bp;
1730 	else
1731 	    v[j++] = bp;
1732     }
1733     assert(i == ntokens && j == nsyms);
1734 
1735     for (i = 1; i < ntokens; ++i)
1736 	v[i]->index = i;
1737 
1738     goal->index = start_symbol + 1;
1739     k = start_symbol + 2;
1740     while (++i < nsyms)
1741 	if (v[i] != goal)
1742 	{
1743 	    v[i]->index = k;
1744 	    ++k;
1745 	}
1746 
1747     goal->value = 0;
1748     k = 1;
1749     for (i = start_symbol + 1; i < nsyms; ++i)
1750     {
1751 	if (v[i] != goal)
1752 	{
1753 	    v[i]->value = k;
1754 	    ++k;
1755 	}
1756     }
1757 
1758     k = 0;
1759     for (i = 1; i < ntokens; ++i)
1760     {
1761 	n = v[i]->value;
1762 	if (n > 256)
1763 	{
1764 	    for (j = k++; j > 0 && symbol_value[j-1] > n; --j)
1765 		symbol_value[j] = symbol_value[j-1];
1766 	    symbol_value[j] = n;
1767 	}
1768     }
1769 
1770     if (v[1]->value == UNDEFINED)
1771 	v[1]->value = 256;
1772 
1773     j = 0;
1774     n = 257;
1775     for (i = 2; i < ntokens; ++i)
1776     {
1777 	if (v[i]->value == UNDEFINED)
1778 	{
1779 	    while (j < k && n == symbol_value[j])
1780 	    {
1781 		while (++j < k && n == symbol_value[j]) continue;
1782 		++n;
1783 	    }
1784 	    v[i]->value = n;
1785 	    ++n;
1786 	}
1787     }
1788 
1789     symbol_name[0] = name_pool + 8;
1790     symbol_value[0] = 0;
1791     symbol_prec[0] = 0;
1792     symbol_assoc[0] = TOKEN;
1793     for (i = 1; i < ntokens; ++i)
1794     {
1795 	symbol_name[i] = v[i]->name;
1796 	symbol_value[i] = v[i]->value;
1797 	symbol_prec[i] = v[i]->prec;
1798 	symbol_assoc[i] = v[i]->assoc;
1799     }
1800     symbol_name[start_symbol] = name_pool;
1801     symbol_value[start_symbol] = -1;
1802     symbol_prec[start_symbol] = 0;
1803     symbol_assoc[start_symbol] = TOKEN;
1804     for (++i; i < nsyms; ++i)
1805     {
1806 	k = v[i]->index;
1807 	symbol_name[k] = v[i]->name;
1808 	symbol_value[k] = v[i]->value;
1809 	symbol_prec[k] = v[i]->prec;
1810 	symbol_assoc[k] = v[i]->assoc;
1811     }
1812 
1813     FREE(v);
1814 }
1815 
1816 
1817 void
1818 pack_grammar(void)
1819 {
1820     int i, j;
1821     int assoc, prec;
1822 
1823     ritem = (short *) MALLOC(nitems*sizeof(short));
1824     if (ritem == 0) no_space();
1825     rlhs = (short *) MALLOC(nrules*sizeof(short));
1826     if (rlhs == 0) no_space();
1827     rrhs = (short *) MALLOC((nrules+1)*sizeof(short));
1828     if (rrhs == 0) no_space();
1829     rprec = (short *) REALLOC(rprec, nrules*sizeof(short));
1830     if (rprec == 0) no_space();
1831     rassoc = REALLOC(rassoc, nrules);
1832     if (rassoc == 0) no_space();
1833 
1834     ritem[0] = -1;
1835     ritem[1] = goal->index;
1836     ritem[2] = 0;
1837     ritem[3] = -2;
1838     rlhs[0] = 0;
1839     rlhs[1] = 0;
1840     rlhs[2] = start_symbol;
1841     rrhs[0] = 0;
1842     rrhs[1] = 0;
1843     rrhs[2] = 1;
1844 
1845     j = 4;
1846     for (i = 3; i < nrules; ++i)
1847     {
1848 	rlhs[i] = plhs[i]->index;
1849 	rrhs[i] = j;
1850 	assoc = TOKEN;
1851 	prec = 0;
1852 	while (pitem[j])
1853 	{
1854 	    ritem[j] = pitem[j]->index;
1855 	    if (pitem[j]->class == TERM)
1856 	    {
1857 		prec = pitem[j]->prec;
1858 		assoc = pitem[j]->assoc;
1859 	    }
1860 	    ++j;
1861 	}
1862 	ritem[j] = -i;
1863 	++j;
1864 	if (rprec[i] == UNDEFINED)
1865 	{
1866 	    rprec[i] = prec;
1867 	    rassoc[i] = assoc;
1868 	}
1869     }
1870     rrhs[i] = j;
1871 
1872     FREE(plhs);
1873     FREE(pitem);
1874 }
1875 
1876 
1877 void
1878 print_grammar(void)
1879 {
1880     int i, j, k;
1881     int spacing = 0;
1882     FILE *f = verbose_file;
1883 
1884     if (!vflag) return;
1885 
1886     k = 1;
1887     for (i = 2; i < nrules; ++i)
1888     {
1889 	if (rlhs[i] != rlhs[i-1])
1890 	{
1891 	    if (i != 2) fprintf(f, "\n");
1892 	    fprintf(f, "%4d  %s :", i - 2, symbol_name[rlhs[i]]);
1893 	    spacing = strlen(symbol_name[rlhs[i]]) + 1;
1894 	}
1895 	else
1896 	{
1897 	    fprintf(f, "%4d  ", i - 2);
1898 	    j = spacing;
1899 	    while (--j >= 0) putc(' ', f);
1900 	    putc('|', f);
1901 	}
1902 
1903 	while (ritem[k] >= 0)
1904 	{
1905 	    fprintf(f, " %s", symbol_name[ritem[k]]);
1906 	    ++k;
1907 	}
1908 	++k;
1909 	putc('\n', f);
1910     }
1911 }
1912 
1913 
1914 void
1915 reader(void)
1916 {
1917     write_section(banner);
1918     create_symbol_table();
1919     read_declarations();
1920     read_grammar();
1921     free_symbol_table();
1922     free_tags();
1923     pack_names();
1924     check_symbols();
1925     pack_symbols();
1926     pack_grammar();
1927     free_symbols();
1928     print_grammar();
1929 }
1930