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