xref: /freebsd/contrib/byacc/reader.c (revision d2ce15bd43b3a1dcce08eecbff8d5d359946d972)
1 /* $Id: reader.c,v 1.36 2012/05/26 16:05:41 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 = TREALLOC(char, 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 = TMALLOC(char, 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 = TREALLOC(char, 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 = TMALLOC(char, 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 = TMALLOC(char, 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 = TMALLOC(param, 1);
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 = TMALLOC(char, 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 =
1062 	    (tag_table
1063 	     ? TREALLOC(char *, tag_table, tagmax)
1064 	     : TMALLOC(char *, tagmax));
1065 	NO_SPACE(tag_table);
1066     }
1067 
1068     s = TMALLOC(char, 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 = TMALLOC(char, 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 = TMALLOC(bucket *, maxitems);
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 = TMALLOC(bucket *, maxrules);
1331     NO_SPACE(plhs);
1332 
1333     plhs[0] = 0;
1334     plhs[1] = 0;
1335     plhs[2] = 0;
1336 
1337     rprec = TMALLOC(Value_t, maxrules);
1338     NO_SPACE(rprec);
1339 
1340     rprec[0] = 0;
1341     rprec[1] = 0;
1342     rprec[2] = 0;
1343 
1344     rassoc = TMALLOC(Assoc_t, maxrules);
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 = TREALLOC(bucket *, pitem, maxitems);
1357     NO_SPACE(pitem);
1358 }
1359 
1360 static void
1361 expand_rules(void)
1362 {
1363     maxrules += 100;
1364 
1365     plhs = TREALLOC(bucket *, plhs, maxrules);
1366     NO_SPACE(plhs);
1367 
1368     rprec = TREALLOC(Value_t, rprec, maxrules);
1369     NO_SPACE(rprec);
1370 
1371     rassoc = TREALLOC(Assoc_t, rassoc, maxrules);
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 = NULL;
1784 
1785     c = cptr[1];
1786     if (c == '%' || c == '\\')
1787     {
1788 	cptr += 2;
1789 	return (1);
1790     }
1791 
1792     if (c == '=')
1793 	cptr += 2;
1794     else if ((c == 'p' || c == 'P') &&
1795 	     ((c = cptr[2]) == 'r' || c == 'R') &&
1796 	     ((c = cptr[3]) == 'e' || c == 'E') &&
1797 	     ((c = cptr[4]) == 'c' || c == 'C') &&
1798 	     ((c = cptr[5], !IS_IDENT(c))))
1799 	cptr += 5;
1800     else
1801 	syntax_error(lineno, line, cptr);
1802 
1803     c = nextc();
1804     if (isalpha(c) || c == '_' || c == '.' || c == '$')
1805 	bp = get_name();
1806     else if (c == '\'' || c == '"')
1807 	bp = get_literal();
1808     else
1809     {
1810 	syntax_error(lineno, line, cptr);
1811 	/*NOTREACHED */
1812     }
1813 
1814     if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
1815 	prec_redeclared();
1816 
1817     rprec[nrules] = bp->prec;
1818     rassoc[nrules] = bp->assoc;
1819     return (0);
1820 }
1821 
1822 static void
1823 read_grammar(void)
1824 {
1825     int c;
1826 
1827     initialize_grammar();
1828     advance_to_start();
1829 
1830     for (;;)
1831     {
1832 	c = nextc();
1833 	if (c == EOF)
1834 	    break;
1835 	if (isalpha(c)
1836 	    || c == '_'
1837 	    || c == '.'
1838 	    || c == '$'
1839 	    || c == '\''
1840 	    || c == '"')
1841 	    add_symbol();
1842 	else if (c == L_CURL || c == '=')
1843 	    copy_action();
1844 	else if (c == '|')
1845 	{
1846 	    end_rule();
1847 	    start_rule(plhs[nrules - 1], 0);
1848 	    ++cptr;
1849 	}
1850 	else if (c == '%')
1851 	{
1852 	    if (mark_symbol())
1853 		break;
1854 	}
1855 	else
1856 	    syntax_error(lineno, line, cptr);
1857     }
1858     end_rule();
1859 }
1860 
1861 static void
1862 free_tags(void)
1863 {
1864     int i;
1865 
1866     if (tag_table == 0)
1867 	return;
1868 
1869     for (i = 0; i < ntags; ++i)
1870     {
1871 	assert(tag_table[i]);
1872 	FREE(tag_table[i]);
1873     }
1874     FREE(tag_table);
1875 }
1876 
1877 static void
1878 pack_names(void)
1879 {
1880     bucket *bp;
1881     char *p, *s, *t;
1882 
1883     name_pool_size = 13;	/* 13 == sizeof("$end") + sizeof("$accept") */
1884     for (bp = first_symbol; bp; bp = bp->next)
1885 	name_pool_size += strlen(bp->name) + 1;
1886 
1887     name_pool = TMALLOC(char, name_pool_size);
1888     NO_SPACE(name_pool);
1889 
1890     strcpy(name_pool, "$accept");
1891     strcpy(name_pool + 8, "$end");
1892     t = name_pool + 13;
1893     for (bp = first_symbol; bp; bp = bp->next)
1894     {
1895 	p = t;
1896 	s = bp->name;
1897 	while ((*t++ = *s++) != 0)
1898 	    continue;
1899 	FREE(bp->name);
1900 	bp->name = p;
1901     }
1902 }
1903 
1904 static void
1905 check_symbols(void)
1906 {
1907     bucket *bp;
1908 
1909     if (goal->class == UNKNOWN)
1910 	undefined_goal(goal->name);
1911 
1912     for (bp = first_symbol; bp; bp = bp->next)
1913     {
1914 	if (bp->class == UNKNOWN)
1915 	{
1916 	    undefined_symbol_warning(bp->name);
1917 	    bp->class = TERM;
1918 	}
1919     }
1920 }
1921 
1922 static void
1923 protect_string(char *src, char **des)
1924 {
1925     unsigned len;
1926     char *s;
1927     char *d;
1928 
1929     *des = src;
1930     if (src)
1931     {
1932 	len = 1;
1933 	s = src;
1934 	while (*s)
1935 	{
1936 	    if ('\\' == *s || '"' == *s)
1937 		len++;
1938 	    s++;
1939 	    len++;
1940 	}
1941 
1942 	*des = d = TMALLOC(char, len);
1943 	NO_SPACE(d);
1944 
1945 	s = src;
1946 	while (*s)
1947 	{
1948 	    if ('\\' == *s || '"' == *s)
1949 		*d++ = '\\';
1950 	    *d++ = *s++;
1951 	}
1952 	*d = '\0';
1953     }
1954 }
1955 
1956 static void
1957 pack_symbols(void)
1958 {
1959     bucket *bp;
1960     bucket **v;
1961     Value_t i, j, k, n;
1962 
1963     nsyms = 2;
1964     ntokens = 1;
1965     for (bp = first_symbol; bp; bp = bp->next)
1966     {
1967 	++nsyms;
1968 	if (bp->class == TERM)
1969 	    ++ntokens;
1970     }
1971     start_symbol = (Value_t) ntokens;
1972     nvars = nsyms - ntokens;
1973 
1974     symbol_name = TMALLOC(char *, nsyms);
1975     NO_SPACE(symbol_name);
1976 
1977     symbol_value = TMALLOC(Value_t, nsyms);
1978     NO_SPACE(symbol_value);
1979 
1980     symbol_prec = TMALLOC(short, nsyms);
1981     NO_SPACE(symbol_prec);
1982 
1983     symbol_assoc = TMALLOC(char, nsyms);
1984     NO_SPACE(symbol_assoc);
1985 
1986     v = TMALLOC(bucket *, nsyms);
1987     NO_SPACE(v);
1988 
1989     v[0] = 0;
1990     v[start_symbol] = 0;
1991 
1992     i = 1;
1993     j = (Value_t) (start_symbol + 1);
1994     for (bp = first_symbol; bp; bp = bp->next)
1995     {
1996 	if (bp->class == TERM)
1997 	    v[i++] = bp;
1998 	else
1999 	    v[j++] = bp;
2000     }
2001     assert(i == ntokens && j == nsyms);
2002 
2003     for (i = 1; i < ntokens; ++i)
2004 	v[i]->index = i;
2005 
2006     goal->index = (Index_t) (start_symbol + 1);
2007     k = (Value_t) (start_symbol + 2);
2008     while (++i < nsyms)
2009 	if (v[i] != goal)
2010 	{
2011 	    v[i]->index = k;
2012 	    ++k;
2013 	}
2014 
2015     goal->value = 0;
2016     k = 1;
2017     for (i = (Value_t) (start_symbol + 1); i < nsyms; ++i)
2018     {
2019 	if (v[i] != goal)
2020 	{
2021 	    v[i]->value = k;
2022 	    ++k;
2023 	}
2024     }
2025 
2026     k = 0;
2027     for (i = 1; i < ntokens; ++i)
2028     {
2029 	n = v[i]->value;
2030 	if (n > 256)
2031 	{
2032 	    for (j = k++; j > 0 && symbol_value[j - 1] > n; --j)
2033 		symbol_value[j] = symbol_value[j - 1];
2034 	    symbol_value[j] = n;
2035 	}
2036     }
2037 
2038     assert(v[1] != 0);
2039 
2040     if (v[1]->value == UNDEFINED)
2041 	v[1]->value = 256;
2042 
2043     j = 0;
2044     n = 257;
2045     for (i = 2; i < ntokens; ++i)
2046     {
2047 	if (v[i]->value == UNDEFINED)
2048 	{
2049 	    while (j < k && n == symbol_value[j])
2050 	    {
2051 		while (++j < k && n == symbol_value[j])
2052 		    continue;
2053 		++n;
2054 	    }
2055 	    v[i]->value = n;
2056 	    ++n;
2057 	}
2058     }
2059 
2060     symbol_name[0] = name_pool + 8;
2061     symbol_value[0] = 0;
2062     symbol_prec[0] = 0;
2063     symbol_assoc[0] = TOKEN;
2064     for (i = 1; i < ntokens; ++i)
2065     {
2066 	symbol_name[i] = v[i]->name;
2067 	symbol_value[i] = v[i]->value;
2068 	symbol_prec[i] = v[i]->prec;
2069 	symbol_assoc[i] = v[i]->assoc;
2070     }
2071     symbol_name[start_symbol] = name_pool;
2072     symbol_value[start_symbol] = -1;
2073     symbol_prec[start_symbol] = 0;
2074     symbol_assoc[start_symbol] = TOKEN;
2075     for (++i; i < nsyms; ++i)
2076     {
2077 	k = v[i]->index;
2078 	symbol_name[k] = v[i]->name;
2079 	symbol_value[k] = v[i]->value;
2080 	symbol_prec[k] = v[i]->prec;
2081 	symbol_assoc[k] = v[i]->assoc;
2082     }
2083 
2084     if (gflag)
2085     {
2086 	symbol_pname = TMALLOC(char *, nsyms);
2087 	NO_SPACE(symbol_pname);
2088 
2089 	for (i = 0; i < nsyms; ++i)
2090 	    protect_string(symbol_name[i], &(symbol_pname[i]));
2091     }
2092 
2093     FREE(v);
2094 }
2095 
2096 static void
2097 pack_grammar(void)
2098 {
2099     int i;
2100     Value_t j;
2101     Assoc_t assoc;
2102     Value_t prec2;
2103 
2104     ritem = TMALLOC(Value_t, nitems);
2105     NO_SPACE(ritem);
2106 
2107     rlhs = TMALLOC(Value_t, nrules);
2108     NO_SPACE(rlhs);
2109 
2110     rrhs = TMALLOC(Value_t, nrules + 1);
2111     NO_SPACE(rrhs);
2112 
2113     rprec = TREALLOC(Value_t, rprec, nrules);
2114     NO_SPACE(rprec);
2115 
2116     rassoc = TREALLOC(Assoc_t, rassoc, nrules);
2117     NO_SPACE(rassoc);
2118 
2119     ritem[0] = -1;
2120     ritem[1] = goal->index;
2121     ritem[2] = 0;
2122     ritem[3] = -2;
2123     rlhs[0] = 0;
2124     rlhs[1] = 0;
2125     rlhs[2] = start_symbol;
2126     rrhs[0] = 0;
2127     rrhs[1] = 0;
2128     rrhs[2] = 1;
2129 
2130     j = 4;
2131     for (i = 3; i < nrules; ++i)
2132     {
2133 	rlhs[i] = plhs[i]->index;
2134 	rrhs[i] = j;
2135 	assoc = TOKEN;
2136 	prec2 = 0;
2137 	while (pitem[j])
2138 	{
2139 	    ritem[j] = pitem[j]->index;
2140 	    if (pitem[j]->class == TERM)
2141 	    {
2142 		prec2 = pitem[j]->prec;
2143 		assoc = pitem[j]->assoc;
2144 	    }
2145 	    ++j;
2146 	}
2147 	ritem[j] = (Value_t) - i;
2148 	++j;
2149 	if (rprec[i] == UNDEFINED)
2150 	{
2151 	    rprec[i] = prec2;
2152 	    rassoc[i] = assoc;
2153 	}
2154     }
2155     rrhs[i] = j;
2156 
2157     FREE(plhs);
2158     FREE(pitem);
2159 }
2160 
2161 static void
2162 print_grammar(void)
2163 {
2164     int i, k;
2165     size_t j, spacing = 0;
2166     FILE *f = verbose_file;
2167 
2168     if (!vflag)
2169 	return;
2170 
2171     k = 1;
2172     for (i = 2; i < nrules; ++i)
2173     {
2174 	if (rlhs[i] != rlhs[i - 1])
2175 	{
2176 	    if (i != 2)
2177 		fprintf(f, "\n");
2178 	    fprintf(f, "%4d  %s :", i - 2, symbol_name[rlhs[i]]);
2179 	    spacing = strlen(symbol_name[rlhs[i]]) + 1;
2180 	}
2181 	else
2182 	{
2183 	    fprintf(f, "%4d  ", i - 2);
2184 	    j = spacing;
2185 	    while (j-- != 0)
2186 		putc(' ', f);
2187 	    putc('|', f);
2188 	}
2189 
2190 	while (ritem[k] >= 0)
2191 	{
2192 	    fprintf(f, " %s", symbol_name[ritem[k]]);
2193 	    ++k;
2194 	}
2195 	++k;
2196 	putc('\n', f);
2197     }
2198 }
2199 
2200 void
2201 reader(void)
2202 {
2203     write_section(code_file, banner);
2204     create_symbol_table();
2205     read_declarations();
2206     read_grammar();
2207     free_symbol_table();
2208     free_tags();
2209     pack_names();
2210     check_symbols();
2211     pack_symbols();
2212     pack_grammar();
2213     free_symbols();
2214     print_grammar();
2215 }
2216 
2217 #ifdef NO_LEAKS
2218 static param *
2219 free_declarations(param * list)
2220 {
2221     while (list != 0)
2222     {
2223 	param *next = list->next;
2224 	free(list->type);
2225 	free(list->name);
2226 	free(list->type2);
2227 	free(list);
2228 	list = next;
2229     }
2230     return list;
2231 }
2232 
2233 void
2234 reader_leaks(void)
2235 {
2236     lex_param = free_declarations(lex_param);
2237     parse_param = free_declarations(parse_param);
2238 
2239     DO_FREE(line);
2240     DO_FREE(rrhs);
2241     DO_FREE(rlhs);
2242     DO_FREE(rprec);
2243     DO_FREE(ritem);
2244     DO_FREE(rassoc);
2245     DO_FREE(cache);
2246     DO_FREE(name_pool);
2247     DO_FREE(symbol_name);
2248     DO_FREE(symbol_prec);
2249     DO_FREE(symbol_assoc);
2250     DO_FREE(symbol_value);
2251 }
2252 #endif
2253