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