xref: /netbsd/external/bsd/byacc/dist/reader.c (revision 6550d01e)
1 /*	$NetBSD: reader.c,v 1.6 2010/12/25 23:43:30 christos Exp $	*/
2 /* Id: reader.c,v 1.31 2010/11/26 12:30:40 tom Exp */
3 
4 #include "defs.h"
5 
6 #include <sys/cdefs.h>
7 __RCSID("$NetBSD: reader.c,v 1.6 2010/12/25 23:43:30 christos Exp $");
8 
9 /*  The line size must be a positive integer.  One hundred was chosen	*/
10 /*  because few lines in Yacc input grammars exceed 100 characters.	*/
11 /*  Note that if a line exceeds LINESIZE characters, the line buffer	*/
12 /*  will be expanded to accomodate it.					*/
13 
14 #define LINESIZE 100
15 
16 #define L_CURL '{'
17 #define R_CURL '}'
18 
19 static void start_rule(bucket *bp, int s_lineno);
20 
21 static char *cache;
22 static int cinc, cache_size;
23 
24 int ntags;
25 static int tagmax;
26 static char **tag_table;
27 
28 static char saw_eof;
29 char unionized;
30 char *cptr, *line;
31 static int linesize;
32 
33 static bucket *goal;
34 static Value_t prec;
35 static int gensym;
36 static char last_was_action;
37 
38 static int maxitems;
39 static bucket **pitem;
40 
41 static int maxrules;
42 static bucket **plhs;
43 
44 static size_t name_pool_size;
45 static char *name_pool;
46 
47 char line_format[] = "#line %d \"%s\"\n";
48 
49 param *lex_param;
50 param *parse_param;
51 
52 static void
53 cachec(int c)
54 {
55     assert(cinc >= 0);
56     if (cinc >= cache_size)
57     {
58 	cache_size += 256;
59 	cache = REALLOC(cache, cache_size);
60 	NO_SPACE(cache);
61     }
62     cache[cinc] = (char)c;
63     ++cinc;
64 }
65 
66 static void
67 get_line(void)
68 {
69     FILE *f = input_file;
70     int c;
71     int i;
72 
73     if (saw_eof || (c = getc(f)) == EOF)
74     {
75 	if (line)
76 	{
77 	    FREE(line);
78 	    line = 0;
79 	}
80 	cptr = 0;
81 	saw_eof = 1;
82 	return;
83     }
84 
85     if (line == 0 || linesize != (LINESIZE + 1))
86     {
87 	if (line)
88 	    FREE(line);
89 	linesize = LINESIZE + 1;
90 	line = MALLOC(linesize);
91 	NO_SPACE(line);
92     }
93 
94     i = 0;
95     ++lineno;
96     for (;;)
97     {
98 	line[i] = (char)c;
99 	if (c == '\n')
100 	{
101 	    cptr = line;
102 	    return;
103 	}
104 	if (++i >= linesize)
105 	{
106 	    linesize += LINESIZE;
107 	    line = REALLOC(line, linesize);
108 	    NO_SPACE(line);
109 	}
110 	c = getc(f);
111 	if (c == EOF)
112 	{
113 	    line[i] = '\n';
114 	    saw_eof = 1;
115 	    cptr = line;
116 	    return;
117 	}
118     }
119 }
120 
121 static char *
122 dup_line(void)
123 {
124     char *p, *s, *t;
125 
126     if (line == 0)
127 	return (0);
128     s = line;
129     while (*s != '\n')
130 	++s;
131     p = MALLOC(s - line + 1);
132     NO_SPACE(p);
133 
134     s = line;
135     t = p;
136     while ((*t++ = *s++) != '\n')
137 	continue;
138     return (p);
139 }
140 
141 static void
142 skip_comment(void)
143 {
144     char *s;
145 
146     int st_lineno = lineno;
147     char *st_line = dup_line();
148     char *st_cptr = st_line + (cptr - line);
149 
150     s = cptr + 2;
151     for (;;)
152     {
153 	if (*s == '*' && s[1] == '/')
154 	{
155 	    cptr = s + 2;
156 	    FREE(st_line);
157 	    return;
158 	}
159 	if (*s == '\n')
160 	{
161 	    get_line();
162 	    if (line == 0)
163 		unterminated_comment(st_lineno, st_line, st_cptr);
164 	    s = cptr;
165 	}
166 	else
167 	    ++s;
168     }
169 }
170 
171 static int
172 nextc(void)
173 {
174     char *s;
175 
176     if (line == 0)
177     {
178 	get_line();
179 	if (line == 0)
180 	    return (EOF);
181     }
182 
183     s = cptr;
184     for (;;)
185     {
186 	switch (*s)
187 	{
188 	case '\n':
189 	    get_line();
190 	    if (line == 0)
191 		return (EOF);
192 	    s = cptr;
193 	    break;
194 
195 	case ' ':
196 	case '\t':
197 	case '\f':
198 	case '\r':
199 	case '\v':
200 	case ',':
201 	case ';':
202 	    ++s;
203 	    break;
204 
205 	case '\\':
206 	    cptr = s;
207 	    return ('%');
208 
209 	case '/':
210 	    if (s[1] == '*')
211 	    {
212 		cptr = s;
213 		skip_comment();
214 		s = cptr;
215 		break;
216 	    }
217 	    else if (s[1] == '/')
218 	    {
219 		get_line();
220 		if (line == 0)
221 		    return (EOF);
222 		s = cptr;
223 		break;
224 	    }
225 	    /* FALLTHRU */
226 
227 	default:
228 	    cptr = s;
229 	    return (*s);
230 	}
231     }
232 }
233 
234 /*
235  * Compare keyword to cached token, treating '_' and '-' the same.  Some
236  * grammars rely upon this misfeature.
237  */
238 static int
239 matchec(const char *name)
240 {
241     const char *p = cache;
242     const char *q = name;
243     int code = 0;	/* assume mismatch */
244 
245     while (*p != '\0' && *q != '\0')
246     {
247 	char a = *p++;
248 	char b = *q++;
249 	if (a == '_')
250 	    a = '-';
251 	if (b == '_')
252 	    b = '-';
253 	if (a != b)
254 	    break;
255 	if (*p == '\0' && *q == '\0')
256 	{
257 	    code = 1;
258 	    break;
259 	}
260     }
261     return code;
262 }
263 
264 static int
265 keyword(void)
266 {
267     int c;
268     char *t_cptr = cptr;
269 
270     c = *++cptr;
271     if (isalpha(c))
272     {
273 	cinc = 0;
274 	for (;;)
275 	{
276 	    if (isalpha(c))
277 	    {
278 		if (isupper(c))
279 		    c = tolower(c);
280 		cachec(c);
281 	    }
282 	    else if (isdigit(c)
283 		     || c == '-'
284 		     || c == '_'
285 		     || c == '.'
286 		     || c == '$')
287 	    {
288 		cachec(c);
289 	    }
290 	    else
291 	    {
292 		break;
293 	    }
294 	    c = *++cptr;
295 	}
296 	cachec(NUL);
297 
298 	if (matchec("token") || matchec("term"))
299 	    return (TOKEN);
300 	if (matchec("type"))
301 	    return (TYPE);
302 	if (matchec("left"))
303 	    return (LEFT);
304 	if (matchec("right"))
305 	    return (RIGHT);
306 	if (matchec("nonassoc") || matchec("binary"))
307 	    return (NONASSOC);
308 	if (matchec("start"))
309 	    return (START);
310 	if (matchec("union"))
311 	    return (UNION);
312 	if (matchec("ident"))
313 	    return (IDENT);
314 	if (matchec("expect"))
315 	    return (EXPECT);
316 	if (matchec("expect-rr"))
317 	    return (EXPECT_RR);
318 	if (matchec("pure-parser"))
319 	    return (PURE_PARSER);
320 	if (matchec("parse-param"))
321 	    return (PARSE_PARAM);
322 	if (matchec("lex-param"))
323 	    return (LEX_PARAM);
324 	if (matchec("yacc"))
325 	    return (POSIX_YACC);
326     }
327     else
328     {
329 	++cptr;
330 	if (c == L_CURL)
331 	    return (TEXT);
332 	if (c == '%' || c == '\\')
333 	    return (MARK);
334 	if (c == '<')
335 	    return (LEFT);
336 	if (c == '>')
337 	    return (RIGHT);
338 	if (c == '0')
339 	    return (TOKEN);
340 	if (c == '2')
341 	    return (NONASSOC);
342     }
343     syntax_error(lineno, line, t_cptr);
344     /*NOTREACHED */
345 }
346 
347 
348 static void
349 copy_ident(void)
350 {
351     int c;
352     FILE *f = output_file;
353 
354     c = nextc();
355     if (c == EOF)
356 	unexpected_EOF();
357     if (c != '"')
358 	syntax_error(lineno, line, cptr);
359     ++outline;
360     fprintf(f, "#ident \"");
361     for (;;)
362     {
363 	c = *++cptr;
364 	if (c == '\n')
365 	{
366 	    fprintf(f, "\"\n");
367 	    return;
368 	}
369 	putc(c, f);
370 	if (c == '"')
371 	{
372 	    putc('\n', f);
373 	    ++cptr;
374 	    return;
375 	}
376     }
377 }
378 
379 static void
380 copy_text(void)
381 {
382     int c;
383     int quote;
384     FILE *f = text_file;
385     int need_newline = 0;
386     int t_lineno = lineno;
387     char *t_line = dup_line();
388     char *t_cptr = t_line + (cptr - line - 2);
389 
390     if (*cptr == '\n')
391     {
392 	get_line();
393 	if (line == 0)
394 	    unterminated_text(t_lineno, t_line, t_cptr);
395     }
396     if (!lflag)
397 	fprintf(f, line_format, lineno, input_file_name);
398 
399   loop:
400     c = *cptr++;
401     switch (c)
402     {
403     case '\n':
404       next_line:
405 	putc('\n', f);
406 	need_newline = 0;
407 	get_line();
408 	if (line)
409 	    goto loop;
410 	unterminated_text(t_lineno, t_line, t_cptr);
411 
412     case '\'':
413     case '"':
414 	{
415 	    int s_lineno = lineno;
416 	    char *s_line = dup_line();
417 	    char *s_cptr = s_line + (cptr - line - 1);
418 
419 	    quote = c;
420 	    putc(c, f);
421 	    for (;;)
422 	    {
423 		c = *cptr++;
424 		putc(c, f);
425 		if (c == quote)
426 		{
427 		    need_newline = 1;
428 		    FREE(s_line);
429 		    goto loop;
430 		}
431 		if (c == '\n')
432 		    unterminated_string(s_lineno, s_line, s_cptr);
433 		if (c == '\\')
434 		{
435 		    c = *cptr++;
436 		    putc(c, f);
437 		    if (c == '\n')
438 		    {
439 			get_line();
440 			if (line == 0)
441 			    unterminated_string(s_lineno, s_line, s_cptr);
442 		    }
443 		}
444 	    }
445 	}
446 
447     case '/':
448 	putc(c, f);
449 	need_newline = 1;
450 	c = *cptr;
451 	if (c == '/')
452 	{
453 	    putc('*', f);
454 	    while ((c = *++cptr) != '\n')
455 	    {
456 		if (c == '*' && cptr[1] == '/')
457 		    fprintf(f, "* ");
458 		else
459 		    putc(c, f);
460 	    }
461 	    fprintf(f, "*/");
462 	    goto next_line;
463 	}
464 	if (c == '*')
465 	{
466 	    int c_lineno = lineno;
467 	    char *c_line = dup_line();
468 	    char *c_cptr = c_line + (cptr - line - 1);
469 
470 	    putc('*', f);
471 	    ++cptr;
472 	    for (;;)
473 	    {
474 		c = *cptr++;
475 		putc(c, f);
476 		if (c == '*' && *cptr == '/')
477 		{
478 		    putc('/', f);
479 		    ++cptr;
480 		    FREE(c_line);
481 		    goto loop;
482 		}
483 		if (c == '\n')
484 		{
485 		    get_line();
486 		    if (line == 0)
487 			unterminated_comment(c_lineno, c_line, c_cptr);
488 		}
489 	    }
490 	}
491 	need_newline = 1;
492 	goto loop;
493 
494     case '%':
495     case '\\':
496 	if (*cptr == R_CURL)
497 	{
498 	    if (need_newline)
499 		putc('\n', f);
500 	    ++cptr;
501 	    FREE(t_line);
502 	    return;
503 	}
504 	/* FALLTHRU */
505 
506     default:
507 	putc(c, f);
508 	need_newline = 1;
509 	goto loop;
510     }
511 }
512 
513 static void
514 puts_both(const char *s)
515 {
516     fputs(s, text_file);
517     if (dflag)
518 	fputs(s, union_file);
519 }
520 
521 static void
522 putc_both(int c)
523 {
524     putc(c, text_file);
525     if (dflag)
526 	putc(c, union_file);
527 }
528 
529 static void
530 copy_union(void)
531 {
532     int c;
533     int quote;
534     int depth;
535     int u_lineno = lineno;
536     char *u_line = dup_line();
537     char *u_cptr = u_line + (cptr - line - 6);
538 
539     if (unionized)
540 	over_unionized(cptr - 6);
541     unionized = 1;
542 
543     if (!lflag)
544 	fprintf(text_file, line_format, lineno, input_file_name);
545 
546     puts_both("#ifdef YYSTYPE\n");
547     puts_both("#undef  YYSTYPE_IS_DECLARED\n");
548     puts_both("#define YYSTYPE_IS_DECLARED 1\n");
549     puts_both("#endif\n");
550     puts_both("#ifndef YYSTYPE_IS_DECLARED\n");
551     puts_both("#define YYSTYPE_IS_DECLARED 1\n");
552     puts_both("typedef union");
553 
554     depth = 0;
555   loop:
556     c = *cptr++;
557     putc_both(c);
558     switch (c)
559     {
560     case '\n':
561       next_line:
562 	get_line();
563 	if (line == 0)
564 	    unterminated_union(u_lineno, u_line, u_cptr);
565 	goto loop;
566 
567     case L_CURL:
568 	++depth;
569 	goto loop;
570 
571     case R_CURL:
572 	if (--depth == 0)
573 	{
574 	    puts_both(" YYSTYPE;\n");
575 	    puts_both("#endif /* !YYSTYPE_IS_DECLARED */\n");
576 	    FREE(u_line);
577 	    return;
578 	}
579 	goto loop;
580 
581     case '\'':
582     case '"':
583 	{
584 	    int s_lineno = lineno;
585 	    char *s_line = dup_line();
586 	    char *s_cptr = s_line + (cptr - line - 1);
587 
588 	    quote = c;
589 	    for (;;)
590 	    {
591 		c = *cptr++;
592 		putc_both(c);
593 		if (c == quote)
594 		{
595 		    FREE(s_line);
596 		    goto loop;
597 		}
598 		if (c == '\n')
599 		    unterminated_string(s_lineno, s_line, s_cptr);
600 		if (c == '\\')
601 		{
602 		    c = *cptr++;
603 		    putc_both(c);
604 		    if (c == '\n')
605 		    {
606 			get_line();
607 			if (line == 0)
608 			    unterminated_string(s_lineno, s_line, s_cptr);
609 		    }
610 		}
611 	    }
612 	}
613 
614     case '/':
615 	c = *cptr;
616 	if (c == '/')
617 	{
618 	    putc_both('*');
619 	    while ((c = *++cptr) != '\n')
620 	    {
621 		if (c == '*' && cptr[1] == '/')
622 		{
623 		    puts_both("* ");
624 		}
625 		else
626 		{
627 		    putc_both(c);
628 		}
629 	    }
630 	    puts_both("*/\n");
631 	    goto next_line;
632 	}
633 	if (c == '*')
634 	{
635 	    int c_lineno = lineno;
636 	    char *c_line = dup_line();
637 	    char *c_cptr = c_line + (cptr - line - 1);
638 
639 	    putc_both('*');
640 	    ++cptr;
641 	    for (;;)
642 	    {
643 		c = *cptr++;
644 		putc_both(c);
645 		if (c == '*' && *cptr == '/')
646 		{
647 		    putc_both('/');
648 		    ++cptr;
649 		    FREE(c_line);
650 		    goto loop;
651 		}
652 		if (c == '\n')
653 		{
654 		    get_line();
655 		    if (line == 0)
656 			unterminated_comment(c_lineno, c_line, c_cptr);
657 		}
658 	    }
659 	}
660 	goto loop;
661 
662     default:
663 	goto loop;
664     }
665 }
666 
667 /*
668  * Keep a linked list of parameters
669  */
670 static void
671 copy_param(int k)
672 {
673     char *buf;
674     int c;
675     param *head, *p;
676     int i;
677     int name, type2;
678 
679     c = nextc();
680     if (c == EOF)
681 	unexpected_EOF();
682     if (c != '{')
683 	goto out;
684     cptr++;
685 
686     c = nextc();
687     if (c == EOF)
688 	unexpected_EOF();
689     if (c == '}')
690 	goto out;
691 
692     buf = MALLOC(linesize);
693     NO_SPACE(buf);
694 
695     for (i = 0; (c = *cptr++) != '}'; i++)
696     {
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 = MALLOC(sizeof(*p));
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 = MALLOC(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 = (char **)
1064 	    (tag_table
1065 	     ? REALLOC(tag_table, (unsigned)tagmax * sizeof(char *))
1066 	     : MALLOC((unsigned)tagmax * sizeof(char *)));
1067 	NO_SPACE(tag_table);
1068     }
1069 
1070     s = MALLOC(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 = MALLOC(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 POSIX_YACC:
1308 	    /* noop for bison compatibility. byacc is already designed to be posix
1309 	     * yacc compatible. */
1310 	    break;
1311 	}
1312     }
1313 }
1314 
1315 static void
1316 initialize_grammar(void)
1317 {
1318     nitems = 4;
1319     maxitems = 300;
1320 
1321     pitem = (bucket **)MALLOC((unsigned)maxitems * sizeof(bucket *));
1322     NO_SPACE(pitem);
1323 
1324     pitem[0] = 0;
1325     pitem[1] = 0;
1326     pitem[2] = 0;
1327     pitem[3] = 0;
1328 
1329     nrules = 3;
1330     maxrules = 100;
1331 
1332     plhs = (bucket **)MALLOC((unsigned)maxrules * sizeof(bucket *));
1333     NO_SPACE(plhs);
1334 
1335     plhs[0] = 0;
1336     plhs[1] = 0;
1337     plhs[2] = 0;
1338 
1339     rprec = (short *)MALLOC((unsigned)maxrules * sizeof(short));
1340     NO_SPACE(rprec);
1341 
1342     rprec[0] = 0;
1343     rprec[1] = 0;
1344     rprec[2] = 0;
1345 
1346     rassoc = (char *)MALLOC((unsigned)maxrules * sizeof(char));
1347     NO_SPACE(rassoc);
1348 
1349     rassoc[0] = TOKEN;
1350     rassoc[1] = TOKEN;
1351     rassoc[2] = TOKEN;
1352 }
1353 
1354 static void
1355 expand_items(void)
1356 {
1357     maxitems += 300;
1358     pitem = (bucket **)REALLOC(pitem, (unsigned)maxitems * sizeof(bucket *));
1359     NO_SPACE(pitem);
1360 }
1361 
1362 static void
1363 expand_rules(void)
1364 {
1365     maxrules += 100;
1366 
1367     plhs = (bucket **)REALLOC(plhs, (unsigned)maxrules * sizeof(bucket *));
1368     NO_SPACE(plhs);
1369 
1370     rprec = (short *)REALLOC(rprec, (unsigned)maxrules * sizeof(short));
1371     NO_SPACE(rprec);
1372 
1373     rassoc = (char *)REALLOC(rassoc, (unsigned)maxrules * sizeof(char));
1374     NO_SPACE(rassoc);
1375 }
1376 
1377 static void
1378 advance_to_start(void)
1379 {
1380     int c;
1381     bucket *bp;
1382     char *s_cptr;
1383     int s_lineno;
1384 
1385     for (;;)
1386     {
1387 	c = nextc();
1388 	if (c != '%')
1389 	    break;
1390 	s_cptr = cptr;
1391 	switch (keyword())
1392 	{
1393 	case MARK:
1394 	    no_grammar();
1395 
1396 	case TEXT:
1397 	    copy_text();
1398 	    break;
1399 
1400 	case START:
1401 	    declare_start();
1402 	    break;
1403 
1404 	default:
1405 	    syntax_error(lineno, line, s_cptr);
1406 	}
1407     }
1408 
1409     c = nextc();
1410     if (!isalpha(c) && c != '_' && c != '.' && c != '_')
1411 	syntax_error(lineno, line, cptr);
1412     bp = get_name();
1413     if (goal == 0)
1414     {
1415 	if (bp->class == TERM)
1416 	    terminal_start(bp->name);
1417 	goal = bp;
1418     }
1419 
1420     s_lineno = lineno;
1421     c = nextc();
1422     if (c == EOF)
1423 	unexpected_EOF();
1424     if (c != ':')
1425 	syntax_error(lineno, line, cptr);
1426     start_rule(bp, s_lineno);
1427     ++cptr;
1428 }
1429 
1430 static void
1431 start_rule(bucket *bp, int s_lineno)
1432 {
1433     if (bp->class == TERM)
1434 	terminal_lhs(s_lineno);
1435     bp->class = NONTERM;
1436     if (nrules >= maxrules)
1437 	expand_rules();
1438     plhs[nrules] = bp;
1439     rprec[nrules] = UNDEFINED;
1440     rassoc[nrules] = TOKEN;
1441 }
1442 
1443 static void
1444 end_rule(void)
1445 {
1446     int i;
1447 
1448     if (!last_was_action && plhs[nrules]->tag)
1449     {
1450 	if (pitem[nitems - 1])
1451 	{
1452 	    for (i = nitems - 1; (i > 0) && pitem[i]; --i)
1453 		continue;
1454 	    if (pitem[i + 1] == 0 || pitem[i + 1]->tag != plhs[nrules]->tag)
1455 		default_action_warning();
1456 	}
1457 	else
1458 	{
1459 	    default_action_warning();
1460 	}
1461     }
1462 
1463     last_was_action = 0;
1464     if (nitems >= maxitems)
1465 	expand_items();
1466     pitem[nitems] = 0;
1467     ++nitems;
1468     ++nrules;
1469 }
1470 
1471 static void
1472 insert_empty_rule(void)
1473 {
1474     bucket *bp, **bpp;
1475 
1476     assert(cache);
1477     sprintf(cache, "$$%d", ++gensym);
1478     bp = make_bucket(cache);
1479     last_symbol->next = bp;
1480     last_symbol = bp;
1481     bp->tag = plhs[nrules]->tag;
1482     bp->class = NONTERM;
1483 
1484     if ((nitems += 2) > maxitems)
1485 	expand_items();
1486     bpp = pitem + nitems - 1;
1487     *bpp-- = bp;
1488     while ((bpp[0] = bpp[-1]) != 0)
1489 	--bpp;
1490 
1491     if (++nrules >= maxrules)
1492 	expand_rules();
1493     plhs[nrules] = plhs[nrules - 1];
1494     plhs[nrules - 1] = bp;
1495     rprec[nrules] = rprec[nrules - 1];
1496     rprec[nrules - 1] = 0;
1497     rassoc[nrules] = rassoc[nrules - 1];
1498     rassoc[nrules - 1] = TOKEN;
1499 }
1500 
1501 static void
1502 add_symbol(void)
1503 {
1504     int c;
1505     bucket *bp;
1506     int s_lineno = lineno;
1507 
1508     c = *cptr;
1509     if (c == '\'' || c == '"')
1510 	bp = get_literal();
1511     else
1512 	bp = get_name();
1513 
1514     c = nextc();
1515     if (c == ':')
1516     {
1517 	end_rule();
1518 	start_rule(bp, s_lineno);
1519 	++cptr;
1520 	return;
1521     }
1522 
1523     if (last_was_action)
1524 	insert_empty_rule();
1525     last_was_action = 0;
1526 
1527     if (++nitems > maxitems)
1528 	expand_items();
1529     pitem[nitems - 1] = bp;
1530 }
1531 
1532 static char *
1533 after_blanks(char *s)
1534 {
1535     while (*s != '\0' && isspace(UCH(*s)))
1536 	++s;
1537     return s;
1538 }
1539 
1540 static void
1541 copy_action(void)
1542 {
1543     int c;
1544     int i, n;
1545     int depth;
1546     int quote;
1547     char *tag;
1548     FILE *f = action_file;
1549     int a_lineno = lineno;
1550     char *a_line = dup_line();
1551     char *a_cptr = a_line + (cptr - line);
1552 
1553     if (last_was_action)
1554 	insert_empty_rule();
1555     last_was_action = 1;
1556 
1557     fprintf(f, "case %d:\n", nrules - 2);
1558     if (!lflag)
1559 	fprintf(f, line_format, lineno, input_file_name);
1560     if (*cptr == '=')
1561 	++cptr;
1562 
1563     /* avoid putting curly-braces in first column, to ease editing */
1564     if (*after_blanks(cptr) == L_CURL)
1565     {
1566 	putc('\t', f);
1567 	cptr = after_blanks(cptr);
1568     }
1569 
1570     n = 0;
1571     for (i = nitems - 1; pitem[i]; --i)
1572 	++n;
1573 
1574     depth = 0;
1575   loop:
1576     c = *cptr;
1577     if (c == '$')
1578     {
1579 	if (cptr[1] == '<')
1580 	{
1581 	    int d_lineno = lineno;
1582 	    char *d_line = dup_line();
1583 	    char *d_cptr = d_line + (cptr - line);
1584 
1585 	    ++cptr;
1586 	    tag = get_tag();
1587 	    c = *cptr;
1588 	    if (c == '$')
1589 	    {
1590 		fprintf(f, "yyval.%s", tag);
1591 		++cptr;
1592 		FREE(d_line);
1593 		goto loop;
1594 	    }
1595 	    else if (isdigit(c))
1596 	    {
1597 		i = get_number();
1598 		if (i > n)
1599 		    dollar_warning(d_lineno, i);
1600 		fprintf(f, "yystack.l_mark[%d].%s", i - n, tag);
1601 		FREE(d_line);
1602 		goto loop;
1603 	    }
1604 	    else if (c == '-' && isdigit(UCH(cptr[1])))
1605 	    {
1606 		++cptr;
1607 		i = -get_number() - n;
1608 		fprintf(f, "yystack.l_mark[%d].%s", i, tag);
1609 		FREE(d_line);
1610 		goto loop;
1611 	    }
1612 	    else
1613 		dollar_error(d_lineno, d_line, d_cptr);
1614 	}
1615 	else if (cptr[1] == '$')
1616 	{
1617 	    if (ntags)
1618 	    {
1619 		tag = plhs[nrules]->tag;
1620 		if (tag == 0)
1621 		    untyped_lhs();
1622 		fprintf(f, "yyval.%s", tag);
1623 	    }
1624 	    else
1625 		fprintf(f, "yyval");
1626 	    cptr += 2;
1627 	    goto loop;
1628 	}
1629 	else if (isdigit(UCH(cptr[1])))
1630 	{
1631 	    ++cptr;
1632 	    i = get_number();
1633 	    if (ntags)
1634 	    {
1635 		if (i <= 0 || i > n)
1636 		    unknown_rhs(i);
1637 		tag = pitem[nitems + i - n - 1]->tag;
1638 		if (tag == 0)
1639 		    untyped_rhs(i, pitem[nitems + i - n - 1]->name);
1640 		fprintf(f, "yystack.l_mark[%d].%s", i - n, tag);
1641 	    }
1642 	    else
1643 	    {
1644 		if (i > n)
1645 		    dollar_warning(lineno, i);
1646 		fprintf(f, "yystack.l_mark[%d]", i - n);
1647 	    }
1648 	    goto loop;
1649 	}
1650 	else if (cptr[1] == '-')
1651 	{
1652 	    cptr += 2;
1653 	    i = get_number();
1654 	    if (ntags)
1655 		unknown_rhs(-i);
1656 	    fprintf(f, "yystack.l_mark[%d]", -i - n);
1657 	    goto loop;
1658 	}
1659     }
1660     if (isalpha(c) || c == '_' || c == '$')
1661     {
1662 	do
1663 	{
1664 	    putc(c, f);
1665 	    c = *++cptr;
1666 	}
1667 	while (isalnum(c) || c == '_' || c == '$');
1668 	goto loop;
1669     }
1670     putc(c, f);
1671     ++cptr;
1672     switch (c)
1673     {
1674     case '\n':
1675       next_line:
1676 	get_line();
1677 	if (line)
1678 	    goto loop;
1679 	unterminated_action(a_lineno, a_line, a_cptr);
1680 
1681     case ';':
1682 	if (depth > 0)
1683 	    goto loop;
1684 	fprintf(f, "\nbreak;\n");
1685 	free(a_line);
1686 	return;
1687 
1688     case L_CURL:
1689 	++depth;
1690 	goto loop;
1691 
1692     case R_CURL:
1693 	if (--depth > 0)
1694 	    goto loop;
1695 	fprintf(f, "\nbreak;\n");
1696 	free(a_line);
1697 	return;
1698 
1699     case '\'':
1700     case '"':
1701 	{
1702 	    int s_lineno = lineno;
1703 	    char *s_line = dup_line();
1704 	    char *s_cptr = s_line + (cptr - line - 1);
1705 
1706 	    quote = c;
1707 	    for (;;)
1708 	    {
1709 		c = *cptr++;
1710 		putc(c, f);
1711 		if (c == quote)
1712 		{
1713 		    FREE(s_line);
1714 		    goto loop;
1715 		}
1716 		if (c == '\n')
1717 		    unterminated_string(s_lineno, s_line, s_cptr);
1718 		if (c == '\\')
1719 		{
1720 		    c = *cptr++;
1721 		    putc(c, f);
1722 		    if (c == '\n')
1723 		    {
1724 			get_line();
1725 			if (line == 0)
1726 			    unterminated_string(s_lineno, s_line, s_cptr);
1727 		    }
1728 		}
1729 	    }
1730 	}
1731 
1732     case '/':
1733 	c = *cptr;
1734 	if (c == '/')
1735 	{
1736 	    putc('*', f);
1737 	    while ((c = *++cptr) != '\n')
1738 	    {
1739 		if (c == '*' && cptr[1] == '/')
1740 		    fprintf(f, "* ");
1741 		else
1742 		    putc(c, f);
1743 	    }
1744 	    fprintf(f, "*/\n");
1745 	    goto next_line;
1746 	}
1747 	if (c == '*')
1748 	{
1749 	    int c_lineno = lineno;
1750 	    char *c_line = dup_line();
1751 	    char *c_cptr = c_line + (cptr - line - 1);
1752 
1753 	    putc('*', f);
1754 	    ++cptr;
1755 	    for (;;)
1756 	    {
1757 		c = *cptr++;
1758 		putc(c, f);
1759 		if (c == '*' && *cptr == '/')
1760 		{
1761 		    putc('/', f);
1762 		    ++cptr;
1763 		    FREE(c_line);
1764 		    goto loop;
1765 		}
1766 		if (c == '\n')
1767 		{
1768 		    get_line();
1769 		    if (line == 0)
1770 			unterminated_comment(c_lineno, c_line, c_cptr);
1771 		}
1772 	    }
1773 	}
1774 	goto loop;
1775 
1776     default:
1777 	goto loop;
1778     }
1779 }
1780 
1781 static int
1782 mark_symbol(void)
1783 {
1784     int c;
1785     bucket *bp;
1786 
1787     c = cptr[1];
1788     if (c == '%' || c == '\\')
1789     {
1790 	cptr += 2;
1791 	return (1);
1792     }
1793 
1794     if (c == '=')
1795 	cptr += 2;
1796     else if ((c == 'p' || c == 'P') &&
1797 	     ((c = cptr[2]) == 'r' || c == 'R') &&
1798 	     ((c = cptr[3]) == 'e' || c == 'E') &&
1799 	     ((c = cptr[4]) == 'c' || c == 'C') &&
1800 	     ((c = cptr[5], !IS_IDENT(c))))
1801 	cptr += 5;
1802     else
1803 	syntax_error(lineno, line, cptr);
1804 
1805     c = nextc();
1806     if (isalpha(c) || c == '_' || c == '.' || c == '$')
1807 	bp = get_name();
1808     else if (c == '\'' || c == '"')
1809 	bp = get_literal();
1810     else
1811     {
1812 	syntax_error(lineno, line, cptr);
1813 	/*NOTREACHED */
1814     }
1815 
1816     if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
1817 	prec_redeclared();
1818 
1819     rprec[nrules] = bp->prec;
1820     rassoc[nrules] = bp->assoc;
1821     return (0);
1822 }
1823 
1824 static void
1825 read_grammar(void)
1826 {
1827     int c;
1828 
1829     initialize_grammar();
1830     advance_to_start();
1831 
1832     for (;;)
1833     {
1834 	c = nextc();
1835 	if (c == EOF)
1836 	    break;
1837 	if (isalpha(c)
1838 	    || c == '_'
1839 	    || c == '.'
1840 	    || c == '$'
1841 	    || c == '\''
1842 	    || c == '"')
1843 	    add_symbol();
1844 	else if (c == L_CURL || c == '=')
1845 	    copy_action();
1846 	else if (c == '|')
1847 	{
1848 	    end_rule();
1849 	    start_rule(plhs[nrules - 1], 0);
1850 	    ++cptr;
1851 	}
1852 	else if (c == '%')
1853 	{
1854 	    if (mark_symbol())
1855 		break;
1856 	}
1857 	else
1858 	    syntax_error(lineno, line, cptr);
1859     }
1860     end_rule();
1861 }
1862 
1863 static void
1864 free_tags(void)
1865 {
1866     int i;
1867 
1868     if (tag_table == 0)
1869 	return;
1870 
1871     for (i = 0; i < ntags; ++i)
1872     {
1873 	assert(tag_table[i]);
1874 	FREE(tag_table[i]);
1875     }
1876     FREE(tag_table);
1877 }
1878 
1879 static void
1880 pack_names(void)
1881 {
1882     bucket *bp;
1883     char *p, *s, *t;
1884 
1885     name_pool_size = 13;	/* 13 == sizeof("$end") + sizeof("$accept") */
1886     for (bp = first_symbol; bp; bp = bp->next)
1887 	name_pool_size += strlen(bp->name) + 1;
1888 
1889     name_pool = MALLOC(name_pool_size);
1890     NO_SPACE(name_pool);
1891 
1892     strlcpy(name_pool, "$accept", name_pool_size);
1893     strlcpy(name_pool + 8, "$end", name_pool_size - 8);
1894     t = name_pool + 13;
1895     for (bp = first_symbol; bp; bp = bp->next)
1896     {
1897 	p = t;
1898 	s = bp->name;
1899 	while ((*t++ = *s++) != 0)
1900 	    continue;
1901 	FREE(bp->name);
1902 	bp->name = p;
1903     }
1904 }
1905 
1906 static void
1907 check_symbols(void)
1908 {
1909     bucket *bp;
1910 
1911     if (goal->class == UNKNOWN)
1912 	undefined_goal(goal->name);
1913 
1914     for (bp = first_symbol; bp; bp = bp->next)
1915     {
1916 	if (bp->class == UNKNOWN)
1917 	{
1918 	    undefined_symbol_warning(bp->name);
1919 	    bp->class = TERM;
1920 	}
1921     }
1922 }
1923 
1924 static void
1925 protect_string(char *src, char **des)
1926 {
1927     unsigned len;
1928     char *s;
1929     char *d;
1930 
1931     *des = src;
1932     if (src)
1933     {
1934 	len = 1;
1935 	s = src;
1936 	while (*s)
1937 	{
1938 	    if ('\\' == *s || '"' == *s)
1939 		len++;
1940 	    s++;
1941 	    len++;
1942 	}
1943 
1944 	*des = d = (char *)MALLOC(len);
1945 	NO_SPACE(d);
1946 
1947 	s = src;
1948 	while (*s)
1949 	{
1950 	    if ('\\' == *s || '"' == *s)
1951 		*d++ = '\\';
1952 	    *d++ = *s++;
1953 	}
1954 	*d = '\0';
1955     }
1956 }
1957 
1958 static void
1959 pack_symbols(void)
1960 {
1961     bucket *bp;
1962     bucket **v;
1963     Value_t i, j, k, n;
1964 
1965     nsyms = 2;
1966     ntokens = 1;
1967     for (bp = first_symbol; bp; bp = bp->next)
1968     {
1969 	++nsyms;
1970 	if (bp->class == TERM)
1971 	    ++ntokens;
1972     }
1973     start_symbol = (Value_t) ntokens;
1974     nvars = nsyms - ntokens;
1975 
1976     symbol_name = (char **)MALLOC((unsigned)nsyms * sizeof(char *));
1977     NO_SPACE(symbol_name);
1978 
1979     symbol_value = (short *)MALLOC((unsigned)nsyms * sizeof(short));
1980     NO_SPACE(symbol_value);
1981 
1982     symbol_prec = (short *)MALLOC((unsigned)nsyms * sizeof(short));
1983     NO_SPACE(symbol_prec);
1984 
1985     symbol_assoc = MALLOC(nsyms);
1986     NO_SPACE(symbol_assoc);
1987 
1988     v = (bucket **)MALLOC((unsigned)nsyms * sizeof(bucket *));
1989     NO_SPACE(v);
1990 
1991     v[0] = 0;
1992     v[start_symbol] = 0;
1993 
1994     i = 1;
1995     j = (Value_t) (start_symbol + 1);
1996     for (bp = first_symbol; bp; bp = bp->next)
1997     {
1998 	if (bp->class == TERM)
1999 	    v[i++] = bp;
2000 	else
2001 	    v[j++] = bp;
2002     }
2003     assert(i == ntokens && j == nsyms);
2004 
2005     for (i = 1; i < ntokens; ++i)
2006 	v[i]->index = i;
2007 
2008     goal->index = (Index_t) (start_symbol + 1);
2009     k = (Value_t) (start_symbol + 2);
2010     while (++i < nsyms)
2011 	if (v[i] != goal)
2012 	{
2013 	    v[i]->index = k;
2014 	    ++k;
2015 	}
2016 
2017     goal->value = 0;
2018     k = 1;
2019     for (i = (Value_t) (start_symbol + 1); i < nsyms; ++i)
2020     {
2021 	if (v[i] != goal)
2022 	{
2023 	    v[i]->value = k;
2024 	    ++k;
2025 	}
2026     }
2027 
2028     k = 0;
2029     for (i = 1; i < ntokens; ++i)
2030     {
2031 	n = v[i]->value;
2032 	if (n > 256)
2033 	{
2034 	    for (j = k++; j > 0 && symbol_value[j - 1] > n; --j)
2035 		symbol_value[j] = symbol_value[j - 1];
2036 	    symbol_value[j] = n;
2037 	}
2038     }
2039 
2040     assert(v[1] != 0);
2041 
2042     if (v[1]->value == UNDEFINED)
2043 	v[1]->value = 256;
2044 
2045     j = 0;
2046     n = 257;
2047     for (i = 2; i < ntokens; ++i)
2048     {
2049 	if (v[i]->value == UNDEFINED)
2050 	{
2051 	    while (j < k && n == symbol_value[j])
2052 	    {
2053 		while (++j < k && n == symbol_value[j])
2054 		    continue;
2055 		++n;
2056 	    }
2057 	    v[i]->value = n;
2058 	    ++n;
2059 	}
2060     }
2061 
2062     symbol_name[0] = name_pool + 8;
2063     symbol_value[0] = 0;
2064     symbol_prec[0] = 0;
2065     symbol_assoc[0] = TOKEN;
2066     for (i = 1; i < ntokens; ++i)
2067     {
2068 	symbol_name[i] = v[i]->name;
2069 	symbol_value[i] = v[i]->value;
2070 	symbol_prec[i] = v[i]->prec;
2071 	symbol_assoc[i] = v[i]->assoc;
2072     }
2073     symbol_name[start_symbol] = name_pool;
2074     symbol_value[start_symbol] = -1;
2075     symbol_prec[start_symbol] = 0;
2076     symbol_assoc[start_symbol] = TOKEN;
2077     for (++i; i < nsyms; ++i)
2078     {
2079 	k = v[i]->index;
2080 	symbol_name[k] = v[i]->name;
2081 	symbol_value[k] = v[i]->value;
2082 	symbol_prec[k] = v[i]->prec;
2083 	symbol_assoc[k] = v[i]->assoc;
2084     }
2085 
2086     if (gflag)
2087     {
2088 	symbol_pname = (char **)MALLOC((unsigned)nsyms * sizeof(char *));
2089 	NO_SPACE(symbol_pname);
2090 
2091 	for (i = 0; i < nsyms; ++i)
2092 	    protect_string(symbol_name[i], &(symbol_pname[i]));
2093     }
2094 
2095     FREE(v);
2096 }
2097 
2098 static void
2099 pack_grammar(void)
2100 {
2101     int i;
2102     Value_t j;
2103     Assoc_t assoc;
2104     Value_t prec2;
2105 
2106     ritem = (short *)MALLOC((unsigned)nitems * sizeof(short));
2107     NO_SPACE(ritem);
2108 
2109     rlhs = (short *)MALLOC((unsigned)nrules * sizeof(short));
2110     NO_SPACE(rlhs);
2111 
2112     rrhs = (short *)MALLOC((unsigned)(nrules + 1) * sizeof(short));
2113     NO_SPACE(rrhs);
2114 
2115     rprec = (short *)REALLOC(rprec, (unsigned)nrules * sizeof(short));
2116     NO_SPACE(rprec);
2117 
2118     rassoc = REALLOC(rassoc, nrules);
2119     NO_SPACE(rassoc);
2120 
2121     ritem[0] = -1;
2122     ritem[1] = goal->index;
2123     ritem[2] = 0;
2124     ritem[3] = -2;
2125     rlhs[0] = 0;
2126     rlhs[1] = 0;
2127     rlhs[2] = start_symbol;
2128     rrhs[0] = 0;
2129     rrhs[1] = 0;
2130     rrhs[2] = 1;
2131 
2132     j = 4;
2133     for (i = 3; i < nrules; ++i)
2134     {
2135 	rlhs[i] = plhs[i]->index;
2136 	rrhs[i] = j;
2137 	assoc = TOKEN;
2138 	prec2 = 0;
2139 	while (pitem[j])
2140 	{
2141 	    ritem[j] = pitem[j]->index;
2142 	    if (pitem[j]->class == TERM)
2143 	    {
2144 		prec2 = pitem[j]->prec;
2145 		assoc = pitem[j]->assoc;
2146 	    }
2147 	    ++j;
2148 	}
2149 	ritem[j] = (Value_t) - i;
2150 	++j;
2151 	if (rprec[i] == UNDEFINED)
2152 	{
2153 	    rprec[i] = prec2;
2154 	    rassoc[i] = assoc;
2155 	}
2156     }
2157     rrhs[i] = j;
2158 
2159     FREE(plhs);
2160     FREE(pitem);
2161 }
2162 
2163 static void
2164 print_grammar(void)
2165 {
2166     int i, k;
2167     size_t j, spacing = 0;
2168     FILE *f = verbose_file;
2169 
2170     if (!vflag)
2171 	return;
2172 
2173     k = 1;
2174     for (i = 2; i < nrules; ++i)
2175     {
2176 	if (rlhs[i] != rlhs[i - 1])
2177 	{
2178 	    if (i != 2)
2179 		fprintf(f, "\n");
2180 	    fprintf(f, "%4d  %s :", i - 2, symbol_name[rlhs[i]]);
2181 	    spacing = strlen(symbol_name[rlhs[i]]) + 1;
2182 	}
2183 	else
2184 	{
2185 	    fprintf(f, "%4d  ", i - 2);
2186 	    j = spacing;
2187 	    while (j-- != 0)
2188 		putc(' ', f);
2189 	    putc('|', f);
2190 	}
2191 
2192 	while (ritem[k] >= 0)
2193 	{
2194 	    fprintf(f, " %s", symbol_name[ritem[k]]);
2195 	    ++k;
2196 	}
2197 	++k;
2198 	putc('\n', f);
2199     }
2200 }
2201 
2202 void
2203 reader(void)
2204 {
2205     write_section(banner);
2206     create_symbol_table();
2207     read_declarations();
2208     read_grammar();
2209     free_symbol_table();
2210     free_tags();
2211     pack_names();
2212     check_symbols();
2213     pack_symbols();
2214     pack_grammar();
2215     free_symbols();
2216     print_grammar();
2217 }
2218 
2219 #ifdef NO_LEAKS
2220 static param *
2221 free_declarations(param * list)
2222 {
2223     while (list != 0)
2224     {
2225 	param *next = list->next;
2226 	free(list->type);
2227 	free(list->name);
2228 	free(list->type2);
2229 	free(list);
2230 	list = next;
2231     }
2232     return list;
2233 }
2234 
2235 void
2236 reader_leaks(void)
2237 {
2238     lex_param = free_declarations(lex_param);
2239     parse_param = free_declarations(parse_param);
2240 
2241     DO_FREE(line);
2242     DO_FREE(rrhs);
2243     DO_FREE(rlhs);
2244     DO_FREE(rprec);
2245     DO_FREE(ritem);
2246     DO_FREE(rassoc);
2247     DO_FREE(cache);
2248     DO_FREE(name_pool);
2249     DO_FREE(symbol_name);
2250     DO_FREE(symbol_prec);
2251     DO_FREE(symbol_assoc);
2252     DO_FREE(symbol_value);
2253 }
2254 #endif
2255