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