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