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