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