xref: /freebsd/contrib/byacc/reader.c (revision 6574b8ed19b093f0af09501d2c9676c28993cb97)
1 /* $Id: reader.c,v 1.47 2014/04/09 21:09:27 tom Exp $ */
2 
3 #include "defs.h"
4 
5 /*  The line size must be a positive integer.  One hundred was chosen	*/
6 /*  because few lines in Yacc input grammars exceed 100 characters.	*/
7 /*  Note that if a line exceeds LINESIZE characters, the line buffer	*/
8 /*  will be expanded to accomodate it.					*/
9 
10 #define LINESIZE 100
11 
12 #define L_CURL  '{'
13 #define R_CURL  '}'
14 #define L_PAREN '('
15 #define R_PAREN ')'
16 #define L_BRAC  '['
17 #define R_BRAC  ']'
18 
19 /* the maximum number of arguments (inherited attributes) to a non-terminal */
20 /* this is a hard limit, but seems more than adequate */
21 #define MAXARGS	20
22 
23 static void start_rule(bucket *bp, int s_lineno);
24 #if defined(YYBTYACC)
25 static void copy_destructor(void);
26 static char *process_destructor_XX(char *code, char *tag);
27 #endif
28 
29 static char *cache;
30 static int cinc, cache_size;
31 
32 int ntags;
33 static int tagmax, havetags;
34 static char **tag_table;
35 
36 static char saw_eof;
37 char unionized;
38 char *cptr, *line;
39 static int linesize;
40 
41 static bucket *goal;
42 static Value_t prec;
43 static int gensym;
44 static char last_was_action;
45 
46 static int maxitems;
47 static bucket **pitem;
48 
49 static int maxrules;
50 static bucket **plhs;
51 
52 static size_t name_pool_size;
53 static char *name_pool;
54 
55 char line_format[] = "#line %d \"%s\"\n";
56 
57 param *lex_param;
58 param *parse_param;
59 
60 #if defined(YYBTYACC)
61 int destructor = 0;	/* =1 if at least one %destructor */
62 
63 static bucket *default_destructor[3] =
64 {0, 0, 0};
65 
66 #define UNTYPED_DEFAULT 0
67 #define TYPED_DEFAULT   1
68 #define TYPE_SPECIFIED  2
69 
70 static bucket *
71 lookup_type_destructor(char *tag)
72 {
73     char name[1024] = "\0";
74     bucket *bp, **bpp = &default_destructor[TYPE_SPECIFIED];
75 
76     while ((bp = *bpp) != NULL)
77     {
78 	if (bp->tag == tag)
79 	    return (bp);
80 	bpp = &bp->link;
81     }
82 
83     *bpp = bp = make_bucket(strcat(strcpy(name, tag), " destructor"));
84     bp->tag = tag;
85 
86     return (bp);
87 }
88 #endif /* defined(YYBTYACC) */
89 
90 static void
91 cachec(int c)
92 {
93     assert(cinc >= 0);
94     if (cinc >= cache_size)
95     {
96 	cache_size += 256;
97 	cache = TREALLOC(char, cache, cache_size);
98 	NO_SPACE(cache);
99     }
100     cache[cinc] = (char)c;
101     ++cinc;
102 }
103 
104 static void
105 get_line(void)
106 {
107     FILE *f = input_file;
108     int c;
109     int i;
110 
111     if (saw_eof || (c = getc(f)) == EOF)
112     {
113 	if (line)
114 	{
115 	    FREE(line);
116 	    line = 0;
117 	}
118 	cptr = 0;
119 	saw_eof = 1;
120 	return;
121     }
122 
123     if (line == 0 || linesize != (LINESIZE + 1))
124     {
125 	if (line)
126 	    FREE(line);
127 	linesize = LINESIZE + 1;
128 	line = TMALLOC(char, linesize);
129 	NO_SPACE(line);
130     }
131 
132     i = 0;
133     ++lineno;
134     for (;;)
135     {
136 	line[i] = (char)c;
137 	if (c == '\n')
138 	    break;
139 	if (++i >= linesize)
140 	{
141 	    linesize += LINESIZE;
142 	    line = TREALLOC(char, line, linesize);
143 	    NO_SPACE(line);
144 	}
145 	c = getc(f);
146 	if (c == EOF)
147 	{
148 	    line[i] = '\n';
149 	    saw_eof = 1;
150 	    break;
151 	}
152     }
153     cptr = line;
154     return;
155 }
156 
157 static char *
158 dup_line(void)
159 {
160     char *p, *s, *t;
161 
162     if (line == 0)
163 	return (0);
164     s = line;
165     while (*s != '\n')
166 	++s;
167     p = TMALLOC(char, s - line + 1);
168     NO_SPACE(p);
169 
170     s = line;
171     t = p;
172     while ((*t++ = *s++) != '\n')
173 	continue;
174     return (p);
175 }
176 
177 static void
178 skip_comment(void)
179 {
180     char *s;
181 
182     int st_lineno = lineno;
183     char *st_line = dup_line();
184     char *st_cptr = st_line + (cptr - line);
185 
186     s = cptr + 2;
187     for (;;)
188     {
189 	if (*s == '*' && s[1] == '/')
190 	{
191 	    cptr = s + 2;
192 	    FREE(st_line);
193 	    return;
194 	}
195 	if (*s == '\n')
196 	{
197 	    get_line();
198 	    if (line == 0)
199 		unterminated_comment(st_lineno, st_line, st_cptr);
200 	    s = cptr;
201 	}
202 	else
203 	    ++s;
204     }
205 }
206 
207 static int
208 nextc(void)
209 {
210     char *s;
211 
212     if (line == 0)
213     {
214 	get_line();
215 	if (line == 0)
216 	    return (EOF);
217     }
218 
219     s = cptr;
220     for (;;)
221     {
222 	switch (*s)
223 	{
224 	case '\n':
225 	    get_line();
226 	    if (line == 0)
227 		return (EOF);
228 	    s = cptr;
229 	    break;
230 
231 	case ' ':
232 	case '\t':
233 	case '\f':
234 	case '\r':
235 	case '\v':
236 	case ',':
237 	case ';':
238 	    ++s;
239 	    break;
240 
241 	case '\\':
242 	    cptr = s;
243 	    return ('%');
244 
245 	case '/':
246 	    if (s[1] == '*')
247 	    {
248 		cptr = s;
249 		skip_comment();
250 		s = cptr;
251 		break;
252 	    }
253 	    else if (s[1] == '/')
254 	    {
255 		get_line();
256 		if (line == 0)
257 		    return (EOF);
258 		s = cptr;
259 		break;
260 	    }
261 	    /* FALLTHRU */
262 
263 	default:
264 	    cptr = s;
265 	    return (*s);
266 	}
267     }
268 }
269 /* *INDENT-OFF* */
270 static struct keyword
271 {
272     char name[13];
273     int token;
274 }
275 keywords[] = {
276     { "binary",      NONASSOC },
277 #if defined(YYBTYACC)
278     { "destructor",  DESTRUCTOR },
279 #endif
280     { "expect",      EXPECT },
281     { "expect-rr",   EXPECT_RR },
282     { "ident",       IDENT },
283     { "left",        LEFT },
284     { "lex-param",   LEX_PARAM },
285 #if defined(YYBTYACC)
286     { "locations",   LOCATIONS },
287 #endif
288     { "nonassoc",    NONASSOC },
289     { "parse-param", PARSE_PARAM },
290     { "pure-parser", PURE_PARSER },
291     { "right",       RIGHT },
292     { "start",       START },
293     { "term",        TOKEN },
294     { "token",       TOKEN },
295     { "token-table", TOKEN_TABLE },
296     { "type",        TYPE },
297     { "union",       UNION },
298     { "yacc",        POSIX_YACC },
299 };
300 /* *INDENT-ON* */
301 
302 static int
303 compare_keys(const void *a, const void *b)
304 {
305     const struct keyword *p = (const struct keyword *)a;
306     const struct keyword *q = (const struct keyword *)b;
307     return strcmp(p->name, q->name);
308 }
309 
310 static int
311 keyword(void)
312 {
313     int c;
314     char *t_cptr = cptr;
315     struct keyword *key;
316 
317     c = *++cptr;
318     if (isalpha(c))
319     {
320 	cinc = 0;
321 	for (;;)
322 	{
323 	    if (isalpha(c))
324 	    {
325 		if (isupper(c))
326 		    c = tolower(c);
327 		cachec(c);
328 	    }
329 	    else if (isdigit(c)
330 		     || c == '-'
331 		     || c == '.'
332 		     || c == '$')
333 	    {
334 		cachec(c);
335 	    }
336 	    else if (c == '_')
337 	    {
338 		/* treat keywords spelled with '_' as if it were '-' */
339 		cachec('-');
340 	    }
341 	    else
342 	    {
343 		break;
344 	    }
345 	    c = *++cptr;
346 	}
347 	cachec(NUL);
348 
349 	if ((key = bsearch(cache, keywords,
350 			   sizeof(keywords) / sizeof(*key),
351 			   sizeof(*key), compare_keys)))
352 	    return key->token;
353     }
354     else
355     {
356 	++cptr;
357 	if (c == L_CURL)
358 	    return (TEXT);
359 	if (c == '%' || c == '\\')
360 	    return (MARK);
361 	if (c == '<')
362 	    return (LEFT);
363 	if (c == '>')
364 	    return (RIGHT);
365 	if (c == '0')
366 	    return (TOKEN);
367 	if (c == '2')
368 	    return (NONASSOC);
369     }
370     syntax_error(lineno, line, t_cptr);
371     return (-1);
372 }
373 
374 static void
375 copy_ident(void)
376 {
377     int c;
378     FILE *f = output_file;
379 
380     c = nextc();
381     if (c == EOF)
382 	unexpected_EOF();
383     if (c != '"')
384 	syntax_error(lineno, line, cptr);
385     ++outline;
386     fprintf(f, "#ident \"");
387     for (;;)
388     {
389 	c = *++cptr;
390 	if (c == '\n')
391 	{
392 	    fprintf(f, "\"\n");
393 	    return;
394 	}
395 	putc(c, f);
396 	if (c == '"')
397 	{
398 	    putc('\n', f);
399 	    ++cptr;
400 	    return;
401 	}
402     }
403 }
404 
405 static char *
406 copy_string(int quote)
407 {
408     struct mstring *temp = msnew();
409     int c;
410     int s_lineno = lineno;
411     char *s_line = dup_line();
412     char *s_cptr = s_line + (cptr - line - 1);
413 
414     for (;;)
415     {
416 	c = *cptr++;
417 	mputc(temp, c);
418 	if (c == quote)
419 	{
420 	    FREE(s_line);
421 	    return msdone(temp);
422 	}
423 	if (c == '\n')
424 	    unterminated_string(s_lineno, s_line, s_cptr);
425 	if (c == '\\')
426 	{
427 	    c = *cptr++;
428 	    mputc(temp, c);
429 	    if (c == '\n')
430 	    {
431 		get_line();
432 		if (line == 0)
433 		    unterminated_string(s_lineno, s_line, s_cptr);
434 	    }
435 	}
436     }
437 }
438 
439 static char *
440 copy_comment(void)
441 {
442     struct mstring *temp = msnew();
443     int c;
444 
445     c = *cptr;
446     if (c == '/')
447     {
448 	mputc(temp, '*');
449 	while ((c = *++cptr) != '\n')
450 	{
451 	    mputc(temp, c);
452 	    if (c == '*' && cptr[1] == '/')
453 		mputc(temp, ' ');
454 	}
455 	mputc(temp, '*');
456 	mputc(temp, '/');
457     }
458     else if (c == '*')
459     {
460 	int c_lineno = lineno;
461 	char *c_line = dup_line();
462 	char *c_cptr = c_line + (cptr - line - 1);
463 
464 	mputc(temp, c);
465 	++cptr;
466 	for (;;)
467 	{
468 	    c = *cptr++;
469 	    mputc(temp, c);
470 	    if (c == '*' && *cptr == '/')
471 	    {
472 		mputc(temp, '/');
473 		++cptr;
474 		FREE(c_line);
475 		return msdone(temp);
476 	    }
477 	    if (c == '\n')
478 	    {
479 		get_line();
480 		if (line == 0)
481 		    unterminated_comment(c_lineno, c_line, c_cptr);
482 	    }
483 	}
484     }
485     return msdone(temp);
486 }
487 
488 static void
489 copy_text(void)
490 {
491     int c;
492     FILE *f = text_file;
493     int need_newline = 0;
494     int t_lineno = lineno;
495     char *t_line = dup_line();
496     char *t_cptr = t_line + (cptr - line - 2);
497 
498     if (*cptr == '\n')
499     {
500 	get_line();
501 	if (line == 0)
502 	    unterminated_text(t_lineno, t_line, t_cptr);
503     }
504     if (!lflag)
505 	fprintf(f, line_format, lineno, input_file_name);
506 
507   loop:
508     c = *cptr++;
509     switch (c)
510     {
511     case '\n':
512 	putc('\n', f);
513 	need_newline = 0;
514 	get_line();
515 	if (line)
516 	    goto loop;
517 	unterminated_text(t_lineno, t_line, t_cptr);
518 
519     case '\'':
520     case '"':
521 	putc(c, f);
522 	{
523 	    char *s = copy_string(c);
524 	    fputs(s, f);
525 	    free(s);
526 	}
527 	need_newline = 1;
528 	goto loop;
529 
530     case '/':
531 	putc(c, f);
532 	{
533 	    char *s = copy_comment();
534 	    fputs(s, f);
535 	    free(s);
536 	}
537 	need_newline = 1;
538 	goto loop;
539 
540     case '%':
541     case '\\':
542 	if (*cptr == R_CURL)
543 	{
544 	    if (need_newline)
545 		putc('\n', f);
546 	    ++cptr;
547 	    FREE(t_line);
548 	    return;
549 	}
550 	/* FALLTHRU */
551 
552     default:
553 	putc(c, f);
554 	need_newline = 1;
555 	goto loop;
556     }
557 }
558 
559 static void
560 puts_both(const char *s)
561 {
562     fputs(s, text_file);
563     if (dflag)
564 	fputs(s, union_file);
565 }
566 
567 static void
568 putc_both(int c)
569 {
570     putc(c, text_file);
571     if (dflag)
572 	putc(c, union_file);
573 }
574 
575 static void
576 copy_union(void)
577 {
578     int c;
579     int depth;
580     int u_lineno = lineno;
581     char *u_line = dup_line();
582     char *u_cptr = u_line + (cptr - line - 6);
583 
584     if (unionized)
585 	over_unionized(cptr - 6);
586     unionized = 1;
587 
588     if (!lflag)
589 	fprintf(text_file, line_format, lineno, input_file_name);
590 
591     puts_both("#ifdef YYSTYPE\n");
592     puts_both("#undef  YYSTYPE_IS_DECLARED\n");
593     puts_both("#define YYSTYPE_IS_DECLARED 1\n");
594     puts_both("#endif\n");
595     puts_both("#ifndef YYSTYPE_IS_DECLARED\n");
596     puts_both("#define YYSTYPE_IS_DECLARED 1\n");
597     puts_both("typedef union");
598 
599     depth = 0;
600   loop:
601     c = *cptr++;
602     putc_both(c);
603     switch (c)
604     {
605     case '\n':
606 	get_line();
607 	if (line == 0)
608 	    unterminated_union(u_lineno, u_line, u_cptr);
609 	goto loop;
610 
611     case L_CURL:
612 	++depth;
613 	goto loop;
614 
615     case R_CURL:
616 	if (--depth == 0)
617 	{
618 	    puts_both(" YYSTYPE;\n");
619 	    puts_both("#endif /* !YYSTYPE_IS_DECLARED */\n");
620 	    FREE(u_line);
621 	    return;
622 	}
623 	goto loop;
624 
625     case '\'':
626     case '"':
627 	{
628 	    char *s = copy_string(c);
629 	    puts_both(s);
630 	    free(s);
631 	}
632 	goto loop;
633 
634     case '/':
635 	{
636 	    char *s = copy_comment();
637 	    puts_both(s);
638 	    free(s);
639 	}
640 	goto loop;
641 
642     default:
643 	goto loop;
644     }
645 }
646 
647 /*
648  * Keep a linked list of parameters
649  */
650 static void
651 copy_param(int k)
652 {
653     char *buf;
654     int c;
655     param *head, *p;
656     int i;
657     int name, type2;
658 
659     c = nextc();
660     if (c == EOF)
661 	unexpected_EOF();
662     if (c != L_CURL)
663 	goto out;
664     cptr++;
665 
666     c = nextc();
667     if (c == EOF)
668 	unexpected_EOF();
669     if (c == R_CURL)
670 	goto out;
671 
672     buf = TMALLOC(char, linesize);
673     NO_SPACE(buf);
674 
675     for (i = 0; (c = *cptr++) != R_CURL; i++)
676     {
677 	if (c == '\0')
678 	    missing_brace();
679 	if (c == EOF)
680 	    unexpected_EOF();
681 	buf[i] = (char)c;
682     }
683 
684     if (i == 0)
685 	goto out;
686 
687     buf[i--] = '\0';
688     while (i > 0 && isspace(UCH(buf[i])))
689 	buf[i--] = '\0';
690 
691     if (buf[i] == ']')
692     {
693 	int level = 1;
694 	while (i >= 0 && level > 0 && buf[i] != '[')
695 	{
696 	    if (buf[i] == ']')
697 		++level;
698 	    else if (buf[i] == '[')
699 		--level;
700 	    i--;
701 	}
702 	if (i <= 0)
703 	    unexpected_EOF();
704 	type2 = i--;
705     }
706     else
707     {
708 	type2 = i + 1;
709     }
710 
711     while (i > 0 && (isalnum(UCH(buf[i])) ||
712 		     UCH(buf[i]) == '_'))
713 	i--;
714 
715     if (!isspace(UCH(buf[i])) && buf[i] != '*')
716 	goto out;
717 
718     name = i + 1;
719 
720     p = TMALLOC(param, 1);
721     NO_SPACE(p);
722 
723     p->type2 = strdup(buf + type2);
724     NO_SPACE(p->type2);
725 
726     buf[type2] = '\0';
727 
728     p->name = strdup(buf + name);
729     NO_SPACE(p->name);
730 
731     buf[name] = '\0';
732     p->type = buf;
733 
734     if (k == LEX_PARAM)
735 	head = lex_param;
736     else
737 	head = parse_param;
738 
739     if (head != NULL)
740     {
741 	while (head->next)
742 	    head = head->next;
743 	head->next = p;
744     }
745     else
746     {
747 	if (k == LEX_PARAM)
748 	    lex_param = p;
749 	else
750 	    parse_param = p;
751     }
752     p->next = NULL;
753     return;
754 
755   out:
756     syntax_error(lineno, line, cptr);
757 }
758 
759 static int
760 hexval(int c)
761 {
762     if (c >= '0' && c <= '9')
763 	return (c - '0');
764     if (c >= 'A' && c <= 'F')
765 	return (c - 'A' + 10);
766     if (c >= 'a' && c <= 'f')
767 	return (c - 'a' + 10);
768     return (-1);
769 }
770 
771 static bucket *
772 get_literal(void)
773 {
774     int c, quote;
775     int i;
776     int n;
777     char *s;
778     bucket *bp;
779     int s_lineno = lineno;
780     char *s_line = dup_line();
781     char *s_cptr = s_line + (cptr - line);
782 
783     quote = *cptr++;
784     cinc = 0;
785     for (;;)
786     {
787 	c = *cptr++;
788 	if (c == quote)
789 	    break;
790 	if (c == '\n')
791 	    unterminated_string(s_lineno, s_line, s_cptr);
792 	if (c == '\\')
793 	{
794 	    char *c_cptr = cptr - 1;
795 
796 	    c = *cptr++;
797 	    switch (c)
798 	    {
799 	    case '\n':
800 		get_line();
801 		if (line == 0)
802 		    unterminated_string(s_lineno, s_line, s_cptr);
803 		continue;
804 
805 	    case '0':
806 	    case '1':
807 	    case '2':
808 	    case '3':
809 	    case '4':
810 	    case '5':
811 	    case '6':
812 	    case '7':
813 		n = c - '0';
814 		c = *cptr;
815 		if (IS_OCTAL(c))
816 		{
817 		    n = (n << 3) + (c - '0');
818 		    c = *++cptr;
819 		    if (IS_OCTAL(c))
820 		    {
821 			n = (n << 3) + (c - '0');
822 			++cptr;
823 		    }
824 		}
825 		if (n > MAXCHAR)
826 		    illegal_character(c_cptr);
827 		c = n;
828 		break;
829 
830 	    case 'x':
831 		c = *cptr++;
832 		n = hexval(c);
833 		if (n < 0 || n >= 16)
834 		    illegal_character(c_cptr);
835 		for (;;)
836 		{
837 		    c = *cptr;
838 		    i = hexval(c);
839 		    if (i < 0 || i >= 16)
840 			break;
841 		    ++cptr;
842 		    n = (n << 4) + i;
843 		    if (n > MAXCHAR)
844 			illegal_character(c_cptr);
845 		}
846 		c = n;
847 		break;
848 
849 	    case 'a':
850 		c = 7;
851 		break;
852 	    case 'b':
853 		c = '\b';
854 		break;
855 	    case 'f':
856 		c = '\f';
857 		break;
858 	    case 'n':
859 		c = '\n';
860 		break;
861 	    case 'r':
862 		c = '\r';
863 		break;
864 	    case 't':
865 		c = '\t';
866 		break;
867 	    case 'v':
868 		c = '\v';
869 		break;
870 	    }
871 	}
872 	cachec(c);
873     }
874     FREE(s_line);
875 
876     n = cinc;
877     s = TMALLOC(char, n);
878     NO_SPACE(s);
879 
880     for (i = 0; i < n; ++i)
881 	s[i] = cache[i];
882 
883     cinc = 0;
884     if (n == 1)
885 	cachec('\'');
886     else
887 	cachec('"');
888 
889     for (i = 0; i < n; ++i)
890     {
891 	c = UCH(s[i]);
892 	if (c == '\\' || c == cache[0])
893 	{
894 	    cachec('\\');
895 	    cachec(c);
896 	}
897 	else if (isprint(c))
898 	    cachec(c);
899 	else
900 	{
901 	    cachec('\\');
902 	    switch (c)
903 	    {
904 	    case 7:
905 		cachec('a');
906 		break;
907 	    case '\b':
908 		cachec('b');
909 		break;
910 	    case '\f':
911 		cachec('f');
912 		break;
913 	    case '\n':
914 		cachec('n');
915 		break;
916 	    case '\r':
917 		cachec('r');
918 		break;
919 	    case '\t':
920 		cachec('t');
921 		break;
922 	    case '\v':
923 		cachec('v');
924 		break;
925 	    default:
926 		cachec(((c >> 6) & 7) + '0');
927 		cachec(((c >> 3) & 7) + '0');
928 		cachec((c & 7) + '0');
929 		break;
930 	    }
931 	}
932     }
933 
934     if (n == 1)
935 	cachec('\'');
936     else
937 	cachec('"');
938 
939     cachec(NUL);
940     bp = lookup(cache);
941     bp->class = TERM;
942     if (n == 1 && bp->value == UNDEFINED)
943 	bp->value = UCH(*s);
944     FREE(s);
945 
946     return (bp);
947 }
948 
949 static int
950 is_reserved(char *name)
951 {
952     char *s;
953 
954     if (strcmp(name, ".") == 0 ||
955 	strcmp(name, "$accept") == 0 ||
956 	strcmp(name, "$end") == 0)
957 	return (1);
958 
959     if (name[0] == '$' && name[1] == '$' && isdigit(UCH(name[2])))
960     {
961 	s = name + 3;
962 	while (isdigit(UCH(*s)))
963 	    ++s;
964 	if (*s == NUL)
965 	    return (1);
966     }
967 
968     return (0);
969 }
970 
971 static bucket *
972 get_name(void)
973 {
974     int c;
975 
976     cinc = 0;
977     for (c = *cptr; IS_IDENT(c); c = *++cptr)
978 	cachec(c);
979     cachec(NUL);
980 
981     if (is_reserved(cache))
982 	used_reserved(cache);
983 
984     return (lookup(cache));
985 }
986 
987 static Value_t
988 get_number(void)
989 {
990     int c;
991     Value_t n;
992 
993     n = 0;
994     for (c = *cptr; isdigit(c); c = *++cptr)
995 	n = (Value_t) (10 * n + (c - '0'));
996 
997     return (n);
998 }
999 
1000 static char *
1001 cache_tag(char *tag, size_t len)
1002 {
1003     int i;
1004     char *s;
1005 
1006     for (i = 0; i < ntags; ++i)
1007     {
1008 	if (strncmp(tag, tag_table[i], len) == 0 &&
1009 	    tag_table[i][len] == NUL)
1010 	    return (tag_table[i]);
1011     }
1012 
1013     if (ntags >= tagmax)
1014     {
1015 	tagmax += 16;
1016 	tag_table =
1017 	    (tag_table
1018 	     ? TREALLOC(char *, tag_table, tagmax)
1019 	     : TMALLOC(char *, tagmax));
1020 	NO_SPACE(tag_table);
1021     }
1022 
1023     s = TMALLOC(char, len + 1);
1024     NO_SPACE(s);
1025 
1026     strncpy(s, tag, len);
1027     s[len] = 0;
1028     tag_table[ntags++] = s;
1029     return s;
1030 }
1031 
1032 static char *
1033 get_tag(void)
1034 {
1035     int c;
1036     int t_lineno = lineno;
1037     char *t_line = dup_line();
1038     char *t_cptr = t_line + (cptr - line);
1039 
1040     ++cptr;
1041     c = nextc();
1042     if (c == EOF)
1043 	unexpected_EOF();
1044     if (!isalpha(c) && c != '_' && c != '$')
1045 	illegal_tag(t_lineno, t_line, t_cptr);
1046 
1047     cinc = 0;
1048     do
1049     {
1050 	cachec(c);
1051 	c = *++cptr;
1052     }
1053     while (IS_IDENT(c));
1054     cachec(NUL);
1055 
1056     c = nextc();
1057     if (c == EOF)
1058 	unexpected_EOF();
1059     if (c != '>')
1060 	illegal_tag(t_lineno, t_line, t_cptr);
1061     ++cptr;
1062 
1063     FREE(t_line);
1064     havetags = 1;
1065     return cache_tag(cache, (size_t) cinc);
1066 }
1067 
1068 #if defined(YYBTYACC)
1069 static char *
1070 scan_id(void)
1071 {
1072     char *b = cptr;
1073 
1074     while (isalnum(*cptr) || *cptr == '_' || *cptr == '$')
1075 	cptr++;
1076     return cache_tag(b, (size_t) (cptr - b));
1077 }
1078 #endif
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 #if defined(YYBTYACC)
1197 static void
1198 declare_argtypes(bucket *bp)
1199 {
1200     char *tags[MAXARGS];
1201     int args = 0, c;
1202 
1203     if (bp->args >= 0)
1204 	retyped_warning(bp->name);
1205     cptr++;			/* skip open paren */
1206     for (;;)
1207     {
1208 	c = nextc();
1209 	if (c == EOF)
1210 	    unexpected_EOF();
1211 	if (c != '<')
1212 	    syntax_error(lineno, line, cptr);
1213 	tags[args++] = get_tag();
1214 	c = nextc();
1215 	if (c == R_PAREN)
1216 	    break;
1217 	if (c == EOF)
1218 	    unexpected_EOF();
1219     }
1220     cptr++;			/* skip close paren */
1221     bp->args = args;
1222     bp->argnames = TMALLOC(char *, args);
1223     NO_SPACE(bp->argnames);
1224     bp->argtags = CALLOC(sizeof(char *), args + 1);
1225     NO_SPACE(bp->argtags);
1226     while (--args >= 0)
1227     {
1228 	bp->argtags[args] = tags[args];
1229 	bp->argnames[args] = NULL;
1230     }
1231 }
1232 #endif
1233 
1234 static void
1235 declare_types(void)
1236 {
1237     int c;
1238     bucket *bp;
1239     char *tag = NULL;
1240 
1241     c = nextc();
1242     if (c == EOF)
1243 	unexpected_EOF();
1244     if (c == '<')
1245 	tag = get_tag();
1246 
1247     for (;;)
1248     {
1249 	c = nextc();
1250 	if (c == EOF)
1251 	    unexpected_EOF();
1252 	if (isalpha(c) || c == '_' || c == '.' || c == '$')
1253 	{
1254 	    bp = get_name();
1255 #if defined(YYBTYACC)
1256 	    if (nextc() == L_PAREN)
1257 		declare_argtypes(bp);
1258 	    else
1259 		bp->args = 0;
1260 #endif
1261 	}
1262 	else if (c == '\'' || c == '"')
1263 	{
1264 	    bp = get_literal();
1265 #if defined(YYBTYACC)
1266 	    bp->args = 0;
1267 #endif
1268 	}
1269 	else
1270 	    return;
1271 
1272 	if (tag)
1273 	{
1274 	    if (bp->tag && tag != bp->tag)
1275 		retyped_warning(bp->name);
1276 	    bp->tag = tag;
1277 	}
1278     }
1279 }
1280 
1281 static void
1282 declare_start(void)
1283 {
1284     int c;
1285     bucket *bp;
1286 
1287     c = nextc();
1288     if (c == EOF)
1289 	unexpected_EOF();
1290     if (!isalpha(c) && c != '_' && c != '.' && c != '$')
1291 	syntax_error(lineno, line, cptr);
1292     bp = get_name();
1293     if (bp->class == TERM)
1294 	terminal_start(bp->name);
1295     if (goal && goal != bp)
1296 	restarted_warning();
1297     goal = bp;
1298 }
1299 
1300 static void
1301 read_declarations(void)
1302 {
1303     int c, k;
1304 
1305     cache_size = 256;
1306     cache = TMALLOC(char, cache_size);
1307     NO_SPACE(cache);
1308 
1309     for (;;)
1310     {
1311 	c = nextc();
1312 	if (c == EOF)
1313 	    unexpected_EOF();
1314 	if (c != '%')
1315 	    syntax_error(lineno, line, cptr);
1316 	switch (k = keyword())
1317 	{
1318 	case MARK:
1319 	    return;
1320 
1321 	case IDENT:
1322 	    copy_ident();
1323 	    break;
1324 
1325 	case TEXT:
1326 	    copy_text();
1327 	    break;
1328 
1329 	case UNION:
1330 	    copy_union();
1331 	    break;
1332 
1333 	case TOKEN:
1334 	case LEFT:
1335 	case RIGHT:
1336 	case NONASSOC:
1337 	    declare_tokens(k);
1338 	    break;
1339 
1340 	case EXPECT:
1341 	case EXPECT_RR:
1342 	    declare_expect(k);
1343 	    break;
1344 
1345 	case TYPE:
1346 	    declare_types();
1347 	    break;
1348 
1349 	case START:
1350 	    declare_start();
1351 	    break;
1352 
1353 	case PURE_PARSER:
1354 	    pure_parser = 1;
1355 	    break;
1356 
1357 	case PARSE_PARAM:
1358 	case LEX_PARAM:
1359 	    copy_param(k);
1360 	    break;
1361 
1362 	case TOKEN_TABLE:
1363 	    token_table = 1;
1364 	    break;
1365 
1366 #if defined(YYBTYACC)
1367 	case LOCATIONS:
1368 	    locations = 1;
1369 	    break;
1370 
1371 	case DESTRUCTOR:
1372 	    destructor = 1;
1373 	    copy_destructor();
1374 	    break;
1375 #endif
1376 
1377 	case POSIX_YACC:
1378 	    /* noop for bison compatibility. byacc is already designed to be posix
1379 	     * yacc compatible. */
1380 	    break;
1381 	}
1382     }
1383 }
1384 
1385 static void
1386 initialize_grammar(void)
1387 {
1388     nitems = 4;
1389     maxitems = 300;
1390 
1391     pitem = TMALLOC(bucket *, maxitems);
1392     NO_SPACE(pitem);
1393 
1394     pitem[0] = 0;
1395     pitem[1] = 0;
1396     pitem[2] = 0;
1397     pitem[3] = 0;
1398 
1399     nrules = 3;
1400     maxrules = 100;
1401 
1402     plhs = TMALLOC(bucket *, maxrules);
1403     NO_SPACE(plhs);
1404 
1405     plhs[0] = 0;
1406     plhs[1] = 0;
1407     plhs[2] = 0;
1408 
1409     rprec = TMALLOC(Value_t, maxrules);
1410     NO_SPACE(rprec);
1411 
1412     rprec[0] = 0;
1413     rprec[1] = 0;
1414     rprec[2] = 0;
1415 
1416     rassoc = TMALLOC(Assoc_t, maxrules);
1417     NO_SPACE(rassoc);
1418 
1419     rassoc[0] = TOKEN;
1420     rassoc[1] = TOKEN;
1421     rassoc[2] = TOKEN;
1422 }
1423 
1424 static void
1425 expand_items(void)
1426 {
1427     maxitems += 300;
1428     pitem = TREALLOC(bucket *, pitem, maxitems);
1429     NO_SPACE(pitem);
1430 }
1431 
1432 static void
1433 expand_rules(void)
1434 {
1435     maxrules += 100;
1436 
1437     plhs = TREALLOC(bucket *, plhs, maxrules);
1438     NO_SPACE(plhs);
1439 
1440     rprec = TREALLOC(Value_t, rprec, maxrules);
1441     NO_SPACE(rprec);
1442 
1443     rassoc = TREALLOC(Assoc_t, rassoc, maxrules);
1444     NO_SPACE(rassoc);
1445 }
1446 
1447 /* set immediately prior to where copy_args() could be called, and incremented by
1448    the various routines that will rescan the argument list as appropriate */
1449 static int rescan_lineno;
1450 #if defined(YYBTYACC)
1451 
1452 static char *
1453 copy_args(int *alen)
1454 {
1455     struct mstring *s = msnew();
1456     int depth = 0, len = 1;
1457     char c, quote = 0;
1458     int a_lineno = lineno;
1459     char *a_line = dup_line();
1460     char *a_cptr = a_line + (cptr - line - 1);
1461 
1462     while ((c = *cptr++) != R_PAREN || depth || quote)
1463     {
1464 	if (c == ',' && !quote && !depth)
1465 	{
1466 	    len++;
1467 	    mputc(s, 0);
1468 	    continue;
1469 	}
1470 	mputc(s, c);
1471 	if (c == '\n')
1472 	{
1473 	    get_line();
1474 	    if (!line)
1475 	    {
1476 		if (quote)
1477 		    unterminated_string(a_lineno, a_line, a_cptr);
1478 		else
1479 		    unterminated_arglist(a_lineno, a_line, a_cptr);
1480 	    }
1481 	}
1482 	else if (quote)
1483 	{
1484 	    if (c == quote)
1485 		quote = 0;
1486 	    else if (c == '\\')
1487 	    {
1488 		if (*cptr != '\n')
1489 		    mputc(s, *cptr++);
1490 	    }
1491 	}
1492 	else
1493 	{
1494 	    if (c == L_PAREN)
1495 		depth++;
1496 	    else if (c == R_PAREN)
1497 		depth--;
1498 	    else if (c == '\"' || c == '\'')
1499 		quote = c;
1500 	}
1501     }
1502     if (alen)
1503 	*alen = len;
1504     FREE(a_line);
1505     return msdone(s);
1506 }
1507 
1508 static char *
1509 parse_id(char *p, char **save)
1510 {
1511     char *b;
1512 
1513     while (isspace(*p))
1514 	if (*p++ == '\n')
1515 	    rescan_lineno++;
1516     if (!isalpha(*p) && *p != '_')
1517 	return NULL;
1518     b = p;
1519     while (isalnum(*p) || *p == '_' || *p == '$')
1520 	p++;
1521     if (save)
1522     {
1523 	*save = cache_tag(b, (size_t) (p - b));
1524     }
1525     return p;
1526 }
1527 
1528 static char *
1529 parse_int(char *p, int *save)
1530 {
1531     int neg = 0, val = 0;
1532 
1533     while (isspace(*p))
1534 	if (*p++ == '\n')
1535 	    rescan_lineno++;
1536     if (*p == '-')
1537     {
1538 	neg = 1;
1539 	p++;
1540     }
1541     if (!isdigit(*p))
1542 	return NULL;
1543     while (isdigit(*p))
1544 	val = val * 10 + *p++ - '0';
1545     if (neg)
1546 	val = -val;
1547     if (save)
1548 	*save = val;
1549     return p;
1550 }
1551 
1552 static void
1553 parse_arginfo(bucket *a, char *args, int argslen)
1554 {
1555     char *p = args, *tmp;
1556     int i, redec = 0;
1557 
1558     if (a->args > 0)
1559     {
1560 	if (a->args != argslen)
1561 	    arg_number_disagree_warning(rescan_lineno, a->name);
1562 	redec = 1;
1563     }
1564     else
1565     {
1566 	if ((a->args = argslen) == 0)
1567 	    return;
1568 	a->argnames = TMALLOC(char *, argslen);
1569 	NO_SPACE(a->argnames);
1570 	a->argtags = TMALLOC(char *, argslen);
1571 	NO_SPACE(a->argtags);
1572     }
1573     if (!args)
1574 	return;
1575     for (i = 0; i < argslen; i++)
1576     {
1577 	while (isspace(*p))
1578 	    if (*p++ == '\n')
1579 		rescan_lineno++;
1580 	if (*p++ != '$')
1581 	    bad_formals();
1582 	while (isspace(*p))
1583 	    if (*p++ == '\n')
1584 		rescan_lineno++;
1585 	if (*p == '<')
1586 	{
1587 	    havetags = 1;
1588 	    if (!(p = parse_id(p + 1, &tmp)))
1589 		bad_formals();
1590 	    while (isspace(*p))
1591 		if (*p++ == '\n')
1592 		    rescan_lineno++;
1593 	    if (*p++ != '>')
1594 		bad_formals();
1595 	    if (redec)
1596 	    {
1597 		if (a->argtags[i] != tmp)
1598 		    arg_type_disagree_warning(rescan_lineno, i + 1, a->name);
1599 	    }
1600 	    else
1601 		a->argtags[i] = tmp;
1602 	}
1603 	else if (!redec)
1604 	    a->argtags[i] = NULL;
1605 	if (!(p = parse_id(p, &a->argnames[i])))
1606 	    bad_formals();
1607 	while (isspace(*p))
1608 	    if (*p++ == '\n')
1609 		rescan_lineno++;
1610 	if (*p++)
1611 	    bad_formals();
1612     }
1613     free(args);
1614 }
1615 
1616 static char *
1617 compile_arg(char **theptr, char *yyvaltag)
1618 {
1619     char *p = *theptr;
1620     struct mstring *c = msnew();
1621     int i, j, n;
1622     Value_t *offsets = NULL, maxoffset;
1623     bucket **rhs;
1624 
1625     maxoffset = 0;
1626     n = 0;
1627     for (i = nitems - 1; pitem[i]; --i)
1628     {
1629 	n++;
1630 	if (pitem[i]->class != ARGUMENT)
1631 	    maxoffset++;
1632     }
1633     if (maxoffset > 0)
1634     {
1635 	offsets = TMALLOC(Value_t, maxoffset + 1);
1636 	NO_SPACE(offsets);
1637     }
1638     for (j = 0, i++; i < nitems; i++)
1639 	if (pitem[i]->class != ARGUMENT)
1640 	    offsets[++j] = (Value_t) (i - nitems + 1);
1641     rhs = pitem + nitems - 1;
1642 
1643     if (yyvaltag)
1644 	msprintf(c, "yyval.%s = ", yyvaltag);
1645     else
1646 	msprintf(c, "yyval = ");
1647     while (*p)
1648     {
1649 	if (*p == '$')
1650 	{
1651 	    char *tag = NULL;
1652 	    if (*++p == '<')
1653 		if (!(p = parse_id(++p, &tag)) || *p++ != '>')
1654 		    illegal_tag(rescan_lineno, NULL, NULL);
1655 	    if (isdigit(*p) || *p == '-')
1656 	    {
1657 		int val;
1658 		if (!(p = parse_int(p, &val)))
1659 		    dollar_error(rescan_lineno, NULL, NULL);
1660 		if (val <= 0)
1661 		    i = val - n;
1662 		else if (val > maxoffset)
1663 		{
1664 		    dollar_warning(rescan_lineno, val);
1665 		    i = val - maxoffset;
1666 		}
1667 		else
1668 		{
1669 		    i = offsets[val];
1670 		    if (!tag && !(tag = rhs[i]->tag) && havetags)
1671 			untyped_rhs(val, rhs[i]->name);
1672 		}
1673 		msprintf(c, "yystack.l_mark[%d]", i);
1674 		if (tag)
1675 		    msprintf(c, ".%s", tag);
1676 		else if (havetags)
1677 		    unknown_rhs(val);
1678 	    }
1679 	    else if (isalpha(*p) || *p == '_')
1680 	    {
1681 		char *arg;
1682 		if (!(p = parse_id(p, &arg)))
1683 		    dollar_error(rescan_lineno, NULL, NULL);
1684 		for (i = plhs[nrules]->args - 1; i >= 0; i--)
1685 		    if (arg == plhs[nrules]->argnames[i])
1686 			break;
1687 		if (i < 0)
1688 		    unknown_arg_warning(rescan_lineno, "$", arg, NULL, NULL);
1689 		else if (!tag)
1690 		    tag = plhs[nrules]->argtags[i];
1691 		msprintf(c, "yystack.l_mark[%d]", i - plhs[nrules]->args + 1
1692 			 - n);
1693 		if (tag)
1694 		    msprintf(c, ".%s", tag);
1695 		else if (havetags)
1696 		    untyped_arg_warning(rescan_lineno, "$", arg);
1697 	    }
1698 	    else
1699 		dollar_error(rescan_lineno, NULL, NULL);
1700 	}
1701 	else if (*p == '@')
1702 	{
1703 	    at_error(rescan_lineno, NULL, NULL);
1704 	}
1705 	else
1706 	{
1707 	    if (*p == '\n')
1708 		rescan_lineno++;
1709 	    mputc(c, *p++);
1710 	}
1711     }
1712     *theptr = p;
1713     if (maxoffset > 0)
1714 	FREE(offsets);
1715     return msdone(c);
1716 }
1717 
1718 #define ARG_CACHE_SIZE	1024
1719 static struct arg_cache
1720 {
1721     struct arg_cache *next;
1722     char *code;
1723     int rule;
1724 }
1725  *arg_cache[ARG_CACHE_SIZE];
1726 
1727 static int
1728 lookup_arg_cache(char *code)
1729 {
1730     struct arg_cache *entry;
1731 
1732     entry = arg_cache[strnshash(code) % ARG_CACHE_SIZE];
1733     while (entry)
1734     {
1735 	if (!strnscmp(entry->code, code))
1736 	    return entry->rule;
1737 	entry = entry->next;
1738     }
1739     return -1;
1740 }
1741 
1742 static void
1743 insert_arg_cache(char *code, int rule)
1744 {
1745     struct arg_cache *entry = NEW(struct arg_cache);
1746     int i;
1747 
1748     NO_SPACE(entry);
1749     i = strnshash(code) % ARG_CACHE_SIZE;
1750     entry->code = code;
1751     entry->rule = rule;
1752     entry->next = arg_cache[i];
1753     arg_cache[i] = entry;
1754 }
1755 
1756 static void
1757 clean_arg_cache(void)
1758 {
1759     struct arg_cache *e, *t;
1760     int i;
1761 
1762     for (i = 0; i < ARG_CACHE_SIZE; i++)
1763     {
1764 	for (e = arg_cache[i]; (t = e); e = e->next, FREE(t))
1765 	    free(e->code);
1766 	arg_cache[i] = NULL;
1767     }
1768 }
1769 #endif
1770 
1771 static void
1772 advance_to_start(void)
1773 {
1774     int c;
1775     bucket *bp;
1776     char *s_cptr;
1777     int s_lineno;
1778 #if defined(YYBTYACC)
1779     char *args = NULL;
1780     int argslen = 0;
1781 #endif
1782 
1783     for (;;)
1784     {
1785 	c = nextc();
1786 	if (c != '%')
1787 	    break;
1788 	s_cptr = cptr;
1789 	switch (keyword())
1790 	{
1791 	case MARK:
1792 	    no_grammar();
1793 
1794 	case TEXT:
1795 	    copy_text();
1796 	    break;
1797 
1798 	case START:
1799 	    declare_start();
1800 	    break;
1801 
1802 	default:
1803 	    syntax_error(lineno, line, s_cptr);
1804 	}
1805     }
1806 
1807     c = nextc();
1808     if (!isalpha(c) && c != '_' && c != '.' && c != '_')
1809 	syntax_error(lineno, line, cptr);
1810     bp = get_name();
1811     if (goal == 0)
1812     {
1813 	if (bp->class == TERM)
1814 	    terminal_start(bp->name);
1815 	goal = bp;
1816     }
1817 
1818     s_lineno = lineno;
1819     c = nextc();
1820     if (c == EOF)
1821 	unexpected_EOF();
1822     rescan_lineno = lineno;	/* line# for possible inherited args rescan */
1823 #if defined(YYBTYACC)
1824     if (c == L_PAREN)
1825     {
1826 	++cptr;
1827 	args = copy_args(&argslen);
1828 	NO_SPACE(args);
1829 	c = nextc();
1830     }
1831 #endif
1832     if (c != ':')
1833 	syntax_error(lineno, line, cptr);
1834     start_rule(bp, s_lineno);
1835 #if defined(YYBTYACC)
1836     parse_arginfo(bp, args, argslen);
1837 #endif
1838     ++cptr;
1839 }
1840 
1841 static void
1842 start_rule(bucket *bp, int s_lineno)
1843 {
1844     if (bp->class == TERM)
1845 	terminal_lhs(s_lineno);
1846     bp->class = NONTERM;
1847     if (!bp->index)
1848 	bp->index = nrules;
1849     if (nrules >= maxrules)
1850 	expand_rules();
1851     plhs[nrules] = bp;
1852     rprec[nrules] = UNDEFINED;
1853     rassoc[nrules] = TOKEN;
1854 }
1855 
1856 static void
1857 end_rule(void)
1858 {
1859     int i;
1860 
1861     if (!last_was_action && plhs[nrules]->tag)
1862     {
1863 	if (pitem[nitems - 1])
1864 	{
1865 	    for (i = nitems - 1; (i > 0) && pitem[i]; --i)
1866 		continue;
1867 	    if (pitem[i + 1] == 0 || pitem[i + 1]->tag != plhs[nrules]->tag)
1868 		default_action_warning();
1869 	}
1870 	else
1871 	{
1872 	    default_action_warning();
1873 	}
1874     }
1875 
1876     last_was_action = 0;
1877     if (nitems >= maxitems)
1878 	expand_items();
1879     pitem[nitems] = 0;
1880     ++nitems;
1881     ++nrules;
1882 }
1883 
1884 static void
1885 insert_empty_rule(void)
1886 {
1887     bucket *bp, **bpp;
1888 
1889     assert(cache);
1890     sprintf(cache, "$$%d", ++gensym);
1891     bp = make_bucket(cache);
1892     last_symbol->next = bp;
1893     last_symbol = bp;
1894     bp->tag = plhs[nrules]->tag;
1895     bp->class = ACTION;
1896 #if defined(YYBTYACC)
1897     bp->args = 0;
1898 #endif
1899 
1900     nitems = (Value_t) (nitems + 2);
1901     if (nitems > maxitems)
1902 	expand_items();
1903     bpp = pitem + nitems - 1;
1904     *bpp-- = bp;
1905     while ((bpp[0] = bpp[-1]) != 0)
1906 	--bpp;
1907 
1908     if (++nrules >= maxrules)
1909 	expand_rules();
1910     plhs[nrules] = plhs[nrules - 1];
1911     plhs[nrules - 1] = bp;
1912     rprec[nrules] = rprec[nrules - 1];
1913     rprec[nrules - 1] = 0;
1914     rassoc[nrules] = rassoc[nrules - 1];
1915     rassoc[nrules - 1] = TOKEN;
1916 }
1917 
1918 #if defined(YYBTYACC)
1919 static char *
1920 insert_arg_rule(char *arg, char *tag)
1921 {
1922     int line_number = rescan_lineno;
1923     char *code = compile_arg(&arg, tag);
1924     int rule = lookup_arg_cache(code);
1925     FILE *f = action_file;
1926 
1927     if (rule < 0)
1928     {
1929 	rule = nrules;
1930 	insert_arg_cache(code, rule);
1931 	fprintf(f, "case %d:\n", rule - 2);
1932 	if (!lflag)
1933 	    fprintf(f, line_format, line_number, input_file_name);
1934 	fprintf(f, "%s;\n", code);
1935 	fprintf(f, "break;\n");
1936 	insert_empty_rule();
1937 	plhs[rule]->tag = tag;
1938 	plhs[rule]->class = ARGUMENT;
1939     }
1940     else
1941     {
1942 	if (++nitems > maxitems)
1943 	    expand_items();
1944 	pitem[nitems - 1] = plhs[rule];
1945 	free(code);
1946     }
1947     return arg + 1;
1948 }
1949 #endif
1950 
1951 static void
1952 add_symbol(void)
1953 {
1954     int c;
1955     bucket *bp;
1956     int s_lineno = lineno;
1957 #if defined(YYBTYACC)
1958     char *args = NULL;
1959     int argslen = 0;
1960 #endif
1961 
1962     c = *cptr;
1963     if (c == '\'' || c == '"')
1964 	bp = get_literal();
1965     else
1966 	bp = get_name();
1967 
1968     c = nextc();
1969     rescan_lineno = lineno;	/* line# for possible inherited args rescan */
1970 #if defined(YYBTYACC)
1971     if (c == L_PAREN)
1972     {
1973 	++cptr;
1974 	args = copy_args(&argslen);
1975 	NO_SPACE(args);
1976 	c = nextc();
1977     }
1978 #endif
1979     if (c == ':')
1980     {
1981 	end_rule();
1982 	start_rule(bp, s_lineno);
1983 #if defined(YYBTYACC)
1984 	parse_arginfo(bp, args, argslen);
1985 #endif
1986 	++cptr;
1987 	return;
1988     }
1989 
1990     if (last_was_action)
1991 	insert_empty_rule();
1992     last_was_action = 0;
1993 
1994 #if defined(YYBTYACC)
1995     if (bp->args < 0)
1996 	bp->args = argslen;
1997     if (argslen == 0 && bp->args > 0 && pitem[nitems - 1] == NULL)
1998     {
1999 	int i;
2000 	if (plhs[nrules]->args != bp->args)
2001 	    wrong_number_args_warning("default ", bp->name);
2002 	for (i = bp->args - 1; i >= 0; i--)
2003 	    if (plhs[nrules]->argtags[i] != bp->argtags[i])
2004 		wrong_type_for_arg_warning(i + 1, bp->name);
2005     }
2006     else if (bp->args != argslen)
2007 	wrong_number_args_warning("", bp->name);
2008     if (bp->args > 0 && argslen > 0)
2009     {
2010 	char *ap;
2011 	int i;
2012 	for (ap = args, i = 0; i < argslen; i++)
2013 	    ap = insert_arg_rule(ap, bp->argtags[i]);
2014 	free(args);
2015     }
2016 #endif /* defined(YYBTYACC) */
2017 
2018     if (++nitems > maxitems)
2019 	expand_items();
2020     pitem[nitems - 1] = bp;
2021 }
2022 
2023 static char *
2024 after_blanks(char *s)
2025 {
2026     while (*s != '\0' && isspace(UCH(*s)))
2027 	++s;
2028     return s;
2029 }
2030 
2031 static void
2032 copy_action(void)
2033 {
2034     int c;
2035     int i, j, n;
2036     int depth;
2037 #if defined(YYBTYACC)
2038     int trialaction = 0;
2039     int haveyyval = 0;
2040 #endif
2041     char *tag;
2042     FILE *f = action_file;
2043     int a_lineno = lineno;
2044     char *a_line = dup_line();
2045     char *a_cptr = a_line + (cptr - line);
2046     Value_t *offsets = NULL, maxoffset;
2047     bucket **rhs;
2048 
2049     if (last_was_action)
2050 	insert_empty_rule();
2051     last_was_action = 1;
2052 
2053     fprintf(f, "case %d:\n", nrules - 2);
2054 #if defined(YYBTYACC)
2055     if (backtrack)
2056     {
2057 	if (*cptr != L_BRAC)
2058 	    fprintf(f, "  if (!yytrial)\n");
2059 	else
2060 	    trialaction = 1;
2061     }
2062 #endif
2063     if (!lflag)
2064 	fprintf(f, line_format, lineno, input_file_name);
2065     if (*cptr == '=')
2066 	++cptr;
2067 
2068     /* avoid putting curly-braces in first column, to ease editing */
2069     if (*after_blanks(cptr) == L_CURL)
2070     {
2071 	putc('\t', f);
2072 	cptr = after_blanks(cptr);
2073     }
2074 
2075     maxoffset = 0;
2076     n = 0;
2077     for (i = nitems - 1; pitem[i]; --i)
2078     {
2079 	++n;
2080 	if (pitem[i]->class != ARGUMENT)
2081 	    maxoffset++;
2082     }
2083     if (maxoffset > 0)
2084     {
2085 	offsets = TMALLOC(Value_t, maxoffset + 1);
2086 	NO_SPACE(offsets);
2087     }
2088     for (j = 0, i++; i < nitems; i++)
2089     {
2090 	if (pitem[i]->class != ARGUMENT)
2091 	{
2092 	    offsets[++j] = (Value_t) (i - nitems + 1);
2093 	}
2094     }
2095     rhs = pitem + nitems - 1;
2096 
2097     depth = 0;
2098   loop:
2099     c = *cptr;
2100     if (c == '$')
2101     {
2102 	if (cptr[1] == '<')
2103 	{
2104 	    int d_lineno = lineno;
2105 	    char *d_line = dup_line();
2106 	    char *d_cptr = d_line + (cptr - line);
2107 
2108 	    ++cptr;
2109 	    tag = get_tag();
2110 	    c = *cptr;
2111 	    if (c == '$')
2112 	    {
2113 		fprintf(f, "yyval.%s", tag);
2114 		++cptr;
2115 		FREE(d_line);
2116 		goto loop;
2117 	    }
2118 	    else if (isdigit(c))
2119 	    {
2120 		i = get_number();
2121 		if (i == 0)
2122 		    fprintf(f, "yystack.l_mark[%d].%s", -n, tag);
2123 		else if (i > maxoffset)
2124 		{
2125 		    dollar_warning(d_lineno, i);
2126 		    fprintf(f, "yystack.l_mark[%d].%s", i - maxoffset, tag);
2127 		}
2128 		else if (offsets)
2129 		    fprintf(f, "yystack.l_mark[%d].%s", offsets[i], tag);
2130 		FREE(d_line);
2131 		goto loop;
2132 	    }
2133 	    else if (c == '-' && isdigit(UCH(cptr[1])))
2134 	    {
2135 		++cptr;
2136 		i = -get_number() - n;
2137 		fprintf(f, "yystack.l_mark[%d].%s", i, tag);
2138 		FREE(d_line);
2139 		goto loop;
2140 	    }
2141 #if defined(YYBTYACC)
2142 	    else if (isalpha(c) || c == '_')
2143 	    {
2144 		char *arg = scan_id();
2145 		for (i = plhs[nrules]->args - 1; i >= 0; i--)
2146 		    if (arg == plhs[nrules]->argnames[i])
2147 			break;
2148 		if (i < 0)
2149 		    unknown_arg_warning(d_lineno, "$", arg, d_line, d_cptr);
2150 		fprintf(f, "yystack.l_mark[%d].%s", i - plhs[nrules]->args +
2151 			1 - n, tag);
2152 		FREE(d_line);
2153 		goto loop;
2154 	    }
2155 #endif
2156 	    else
2157 		dollar_error(d_lineno, d_line, d_cptr);
2158 	}
2159 	else if (cptr[1] == '$')
2160 	{
2161 	    if (havetags)
2162 	    {
2163 		tag = plhs[nrules]->tag;
2164 		if (tag == 0)
2165 		    untyped_lhs();
2166 		fprintf(f, "yyval.%s", tag);
2167 	    }
2168 	    else
2169 		fprintf(f, "yyval");
2170 	    cptr += 2;
2171 #if defined(YYBTYACC)
2172 	    haveyyval = 1;
2173 #endif
2174 	    goto loop;
2175 	}
2176 	else if (isdigit(UCH(cptr[1])))
2177 	{
2178 	    ++cptr;
2179 	    i = get_number();
2180 	    if (havetags)
2181 	    {
2182 		if (i <= 0 || i > maxoffset)
2183 		    unknown_rhs(i);
2184 		tag = rhs[offsets[i]]->tag;
2185 		if (tag == 0)
2186 		    untyped_rhs(i, rhs[offsets[i]]->name);
2187 		fprintf(f, "yystack.l_mark[%d].%s", offsets[i], tag);
2188 	    }
2189 	    else
2190 	    {
2191 		if (i == 0)
2192 		    fprintf(f, "yystack.l_mark[%d]", -n);
2193 		else if (i > maxoffset)
2194 		{
2195 		    dollar_warning(lineno, i);
2196 		    fprintf(f, "yystack.l_mark[%d]", i - maxoffset);
2197 		}
2198 		else if (offsets)
2199 		    fprintf(f, "yystack.l_mark[%d]", offsets[i]);
2200 	    }
2201 	    goto loop;
2202 	}
2203 	else if (cptr[1] == '-')
2204 	{
2205 	    cptr += 2;
2206 	    i = get_number();
2207 	    if (havetags)
2208 		unknown_rhs(-i);
2209 	    fprintf(f, "yystack.l_mark[%d]", -i - n);
2210 	    goto loop;
2211 	}
2212 #if defined(YYBTYACC)
2213 	else if (isalpha(cptr[1]) || cptr[1] == '_')
2214 	{
2215 	    char *arg;
2216 	    ++cptr;
2217 	    arg = scan_id();
2218 	    for (i = plhs[nrules]->args - 1; i >= 0; i--)
2219 		if (arg == plhs[nrules]->argnames[i])
2220 		    break;
2221 	    if (i < 0)
2222 		unknown_arg_warning(lineno, "$", arg, line, cptr);
2223 	    tag = (i < 0 ? NULL : plhs[nrules]->argtags[i]);
2224 	    fprintf(f, "yystack.l_mark[%d]", i - plhs[nrules]->args + 1 - n);
2225 	    if (tag)
2226 		fprintf(f, ".%s", tag);
2227 	    else if (havetags)
2228 		untyped_arg_warning(lineno, "$", arg);
2229 	    goto loop;
2230 	}
2231 #endif
2232     }
2233 #if defined(YYBTYACC)
2234     if (c == '@')
2235     {
2236 	if (!locations)
2237 	{
2238 	    int l_lineno = lineno;
2239 	    char *l_line = dup_line();
2240 	    char *l_cptr = l_line + (cptr - line);
2241 	    syntax_error(l_lineno, l_line, l_cptr);
2242 	}
2243 	if (cptr[1] == '$')
2244 	{
2245 	    fprintf(f, "yyloc");
2246 	    cptr += 2;
2247 	    goto loop;
2248 	}
2249 	else if (isdigit(UCH(cptr[1])))
2250 	{
2251 	    ++cptr;
2252 	    i = get_number();
2253 	    if (i == 0)
2254 		fprintf(f, "yystack.p_mark[%d]", -n);
2255 	    else if (i > maxoffset)
2256 	    {
2257 		at_warning(lineno, i);
2258 		fprintf(f, "yystack.p_mark[%d]", i - maxoffset);
2259 	    }
2260 	    else if (offsets)
2261 		fprintf(f, "yystack.p_mark[%d]", offsets[i]);
2262 	    goto loop;
2263 	}
2264     }
2265 #endif
2266     if (isalpha(c) || c == '_' || c == '$')
2267     {
2268 	do
2269 	{
2270 	    putc(c, f);
2271 	    c = *++cptr;
2272 	}
2273 	while (isalnum(c) || c == '_' || c == '$');
2274 	goto loop;
2275     }
2276     ++cptr;
2277 #if defined(YYBTYACC)
2278     if (backtrack)
2279     {
2280 	if (trialaction && c == L_BRAC && depth == 0)
2281 	{
2282 	    ++depth;
2283 	    putc(L_CURL, f);
2284 	    goto loop;
2285 	}
2286 	if (trialaction && c == R_BRAC && depth == 1)
2287 	{
2288 	    --depth;
2289 	    putc(R_CURL, f);
2290 	    c = nextc();
2291 	    if (c == L_BRAC && !haveyyval)
2292 	    {
2293 		goto loop;
2294 	    }
2295 	    if (c == L_CURL && !haveyyval)
2296 	    {
2297 		fprintf(f, "  if (!yytrial)\n");
2298 		if (!lflag)
2299 		    fprintf(f, line_format, lineno, input_file_name);
2300 		trialaction = 0;
2301 		goto loop;
2302 	    }
2303 	    fprintf(f, "\nbreak;\n");
2304 	    FREE(a_line);
2305 	    if (maxoffset > 0)
2306 		FREE(offsets);
2307 	    return;
2308 	}
2309     }
2310 #endif
2311     putc(c, f);
2312     switch (c)
2313     {
2314     case '\n':
2315 	get_line();
2316 	if (line)
2317 	    goto loop;
2318 	unterminated_action(a_lineno, a_line, a_cptr);
2319 
2320     case ';':
2321 	if (depth > 0)
2322 	    goto loop;
2323 	fprintf(f, "\nbreak;\n");
2324 	free(a_line);
2325 	if (maxoffset > 0)
2326 	    FREE(offsets);
2327 	return;
2328 
2329 #if defined(YYBTYACC)
2330     case L_BRAC:
2331 	if (backtrack)
2332 	    ++depth;
2333 	goto loop;
2334 
2335     case R_BRAC:
2336 	if (backtrack)
2337 	    --depth;
2338 	goto loop;
2339 #endif
2340 
2341     case L_CURL:
2342 	++depth;
2343 	goto loop;
2344 
2345     case R_CURL:
2346 	if (--depth > 0)
2347 	    goto loop;
2348 #if defined(YYBTYACC)
2349 	if (backtrack)
2350 	{
2351 	    c = nextc();
2352 	    if (c == L_BRAC && !haveyyval)
2353 	    {
2354 		trialaction = 1;
2355 		goto loop;
2356 	    }
2357 	    if (c == L_CURL && !haveyyval)
2358 	    {
2359 		fprintf(f, "  if (!yytrial)\n");
2360 		if (!lflag)
2361 		    fprintf(f, line_format, lineno, input_file_name);
2362 		goto loop;
2363 	    }
2364 	}
2365 #endif
2366 	fprintf(f, "\nbreak;\n");
2367 	free(a_line);
2368 	if (maxoffset > 0)
2369 	    FREE(offsets);
2370 	return;
2371 
2372     case '\'':
2373     case '"':
2374 	{
2375 	    char *s = copy_string(c);
2376 	    fputs(s, f);
2377 	    free(s);
2378 	}
2379 	goto loop;
2380 
2381     case '/':
2382 	{
2383 	    char *s = copy_comment();
2384 	    fputs(s, f);
2385 	    free(s);
2386 	}
2387 	goto loop;
2388 
2389     default:
2390 	goto loop;
2391     }
2392 }
2393 
2394 #if defined(YYBTYACC)
2395 static void
2396 copy_destructor(void)
2397 {
2398     int c;
2399     int depth;
2400     char *tag;
2401     bucket *bp;
2402     struct mstring *destructor_text = msnew();
2403     char *code_text;
2404     int a_lineno;
2405     char *a_line;
2406     char *a_cptr;
2407 
2408     if (!lflag)
2409 	msprintf(destructor_text, line_format, lineno, input_file_name);
2410 
2411     cptr = after_blanks(cptr);
2412     if (*cptr == L_CURL)
2413 	/* avoid putting curly-braces in first column, to ease editing */
2414 	mputc(destructor_text, '\t');
2415     else
2416 	syntax_error(lineno, line, cptr);
2417 
2418     a_lineno = lineno;
2419     a_line = dup_line();
2420     a_cptr = a_line + (cptr - line);
2421 
2422     depth = 0;
2423   loop:
2424     c = *cptr;
2425     if (c == '$')
2426     {
2427 	if (cptr[1] == '<')
2428 	{
2429 	    int d_lineno = lineno;
2430 	    char *d_line = dup_line();
2431 	    char *d_cptr = d_line + (cptr - line);
2432 
2433 	    ++cptr;
2434 	    tag = get_tag();
2435 	    c = *cptr;
2436 	    if (c == '$')
2437 	    {
2438 		msprintf(destructor_text, "(*val).%s", tag);
2439 		++cptr;
2440 		FREE(d_line);
2441 		goto loop;
2442 	    }
2443 	    else
2444 		dollar_error(d_lineno, d_line, d_cptr);
2445 	}
2446 	else if (cptr[1] == '$')
2447 	{
2448 	    /* process '$$' later; replacement is context dependent */
2449 	    msprintf(destructor_text, "$$");
2450 	    cptr += 2;
2451 	    goto loop;
2452 	}
2453     }
2454     if (c == '@' && cptr[1] == '$')
2455     {
2456 	if (!locations)
2457 	{
2458 	    int l_lineno = lineno;
2459 	    char *l_line = dup_line();
2460 	    char *l_cptr = l_line + (cptr - line);
2461 	    syntax_error(l_lineno, l_line, l_cptr);
2462 	}
2463 	msprintf(destructor_text, "(*loc)");
2464 	cptr += 2;
2465 	goto loop;
2466     }
2467     if (isalpha(c) || c == '_' || c == '$')
2468     {
2469 	do
2470 	{
2471 	    mputc(destructor_text, c);
2472 	    c = *++cptr;
2473 	}
2474 	while (isalnum(c) || c == '_' || c == '$');
2475 	goto loop;
2476     }
2477     ++cptr;
2478     mputc(destructor_text, c);
2479     switch (c)
2480     {
2481     case '\n':
2482 	get_line();
2483 	if (line)
2484 	    goto loop;
2485 	unterminated_action(a_lineno, a_line, a_cptr);
2486 
2487     case L_CURL:
2488 	++depth;
2489 	goto loop;
2490 
2491     case R_CURL:
2492 	if (--depth > 0)
2493 	    goto loop;
2494 	goto process_symbols;
2495 
2496     case '\'':
2497     case '"':
2498 	{
2499 	    char *s = copy_string(c);
2500 	    msprintf(destructor_text, "%s", s);
2501 	    free(s);
2502 	}
2503 	goto loop;
2504 
2505     case '/':
2506 	{
2507 	    char *s = copy_comment();
2508 	    msprintf(destructor_text, "%s", s);
2509 	    free(s);
2510 	}
2511 	goto loop;
2512 
2513     default:
2514 	goto loop;
2515     }
2516   process_symbols:
2517     code_text = msdone(destructor_text);
2518     for (;;)
2519     {
2520 	c = nextc();
2521 	if (c == EOF)
2522 	    unexpected_EOF();
2523 	if (c == '<')
2524 	{
2525 	    if (cptr[1] == '>')
2526 	    {			/* "no semantic type" default destructor */
2527 		cptr += 2;
2528 		if ((bp = default_destructor[UNTYPED_DEFAULT]) == NULL)
2529 		{
2530 		    static char untyped_default[] = "<>";
2531 		    bp = make_bucket("untyped default");
2532 		    bp->tag = untyped_default;
2533 		    default_destructor[UNTYPED_DEFAULT] = bp;
2534 		}
2535 		if (bp->destructor != NULL)
2536 		    destructor_redeclared_warning(a_lineno, a_line, a_cptr);
2537 		else
2538 		    /* replace "$$" with "(*val)" in destructor code */
2539 		    bp->destructor = process_destructor_XX(code_text, NULL);
2540 	    }
2541 	    else if (cptr[1] == '*' && cptr[2] == '>')
2542 	    {			/* "no per-symbol or per-type" default destructor */
2543 		cptr += 3;
2544 		if ((bp = default_destructor[TYPED_DEFAULT]) == NULL)
2545 		{
2546 		    static char typed_default[] = "<*>";
2547 		    bp = make_bucket("typed default");
2548 		    bp->tag = typed_default;
2549 		    default_destructor[TYPED_DEFAULT] = bp;
2550 		}
2551 		if (bp->destructor != NULL)
2552 		    destructor_redeclared_warning(a_lineno, a_line, a_cptr);
2553 		else
2554 		{
2555 		    /* postpone re-processing destructor $$s until end of grammar spec */
2556 		    bp->destructor = TMALLOC(char, strlen(code_text) + 1);
2557 		    NO_SPACE(bp->destructor);
2558 		    strcpy(bp->destructor, code_text);
2559 		}
2560 	    }
2561 	    else
2562 	    {			/* "semantic type" default destructor */
2563 		tag = get_tag();
2564 		bp = lookup_type_destructor(tag);
2565 		if (bp->destructor != NULL)
2566 		    destructor_redeclared_warning(a_lineno, a_line, a_cptr);
2567 		else
2568 		    /* replace "$$" with "(*val).tag" in destructor code */
2569 		    bp->destructor = process_destructor_XX(code_text, tag);
2570 	    }
2571 	}
2572 	else if (isalpha(c) || c == '_' || c == '.' || c == '$')
2573 	{			/* "symbol" destructor */
2574 	    bp = get_name();
2575 	    if (bp->destructor != NULL)
2576 		destructor_redeclared_warning(a_lineno, a_line, a_cptr);
2577 	    else
2578 	    {
2579 		/* postpone re-processing destructor $$s until end of grammar spec */
2580 		bp->destructor = TMALLOC(char, strlen(code_text) + 1);
2581 		NO_SPACE(bp->destructor);
2582 		strcpy(bp->destructor, code_text);
2583 	    }
2584 	}
2585 	else
2586 	    break;
2587     }
2588     free(a_line);
2589     free(code_text);
2590 }
2591 
2592 static char *
2593 process_destructor_XX(char *code, char *tag)
2594 {
2595     int c;
2596     int quote;
2597     int depth;
2598     struct mstring *new_code = msnew();
2599     char *codeptr = code;
2600 
2601     depth = 0;
2602   loop:			/* step thru code */
2603     c = *codeptr;
2604     if (c == '$' && codeptr[1] == '$')
2605     {
2606 	codeptr += 2;
2607 	if (tag == NULL)
2608 	    msprintf(new_code, "(*val)");
2609 	else
2610 	    msprintf(new_code, "(*val).%s", tag);
2611 	goto loop;
2612     }
2613     if (isalpha(c) || c == '_' || c == '$')
2614     {
2615 	do
2616 	{
2617 	    mputc(new_code, c);
2618 	    c = *++codeptr;
2619 	}
2620 	while (isalnum(c) || c == '_' || c == '$');
2621 	goto loop;
2622     }
2623     ++codeptr;
2624     mputc(new_code, c);
2625     switch (c)
2626     {
2627     case L_CURL:
2628 	++depth;
2629 	goto loop;
2630 
2631     case R_CURL:
2632 	if (--depth > 0)
2633 	    goto loop;
2634 	return msdone(new_code);
2635 
2636     case '\'':
2637     case '"':
2638 	quote = c;
2639 	for (;;)
2640 	{
2641 	    c = *codeptr++;
2642 	    mputc(new_code, c);
2643 	    if (c == quote)
2644 		goto loop;
2645 	    if (c == '\\')
2646 	    {
2647 		c = *codeptr++;
2648 		mputc(new_code, c);
2649 	    }
2650 	}
2651 
2652     case '/':
2653 	c = *codeptr;
2654 	if (c == '*')
2655 	{
2656 	    mputc(new_code, c);
2657 	    ++codeptr;
2658 	    for (;;)
2659 	    {
2660 		c = *codeptr++;
2661 		mputc(new_code, c);
2662 		if (c == '*' && *codeptr == '/')
2663 		{
2664 		    mputc(new_code, '/');
2665 		    ++codeptr;
2666 		    goto loop;
2667 		}
2668 	    }
2669 	}
2670 	goto loop;
2671 
2672     default:
2673 	goto loop;
2674     }
2675 }
2676 #endif /* defined(YYBTYACC) */
2677 
2678 static int
2679 mark_symbol(void)
2680 {
2681     int c;
2682     bucket *bp = NULL;
2683 
2684     c = cptr[1];
2685     if (c == '%' || c == '\\')
2686     {
2687 	cptr += 2;
2688 	return (1);
2689     }
2690 
2691     if (c == '=')
2692 	cptr += 2;
2693     else if ((c == 'p' || c == 'P') &&
2694 	     ((c = cptr[2]) == 'r' || c == 'R') &&
2695 	     ((c = cptr[3]) == 'e' || c == 'E') &&
2696 	     ((c = cptr[4]) == 'c' || c == 'C') &&
2697 	     ((c = cptr[5], !IS_IDENT(c))))
2698 	cptr += 5;
2699     else
2700 	syntax_error(lineno, line, cptr);
2701 
2702     c = nextc();
2703     if (isalpha(c) || c == '_' || c == '.' || c == '$')
2704 	bp = get_name();
2705     else if (c == '\'' || c == '"')
2706 	bp = get_literal();
2707     else
2708     {
2709 	syntax_error(lineno, line, cptr);
2710     }
2711 
2712     if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
2713 	prec_redeclared();
2714 
2715     rprec[nrules] = bp->prec;
2716     rassoc[nrules] = bp->assoc;
2717     return (0);
2718 }
2719 
2720 static void
2721 read_grammar(void)
2722 {
2723     int c;
2724 
2725     initialize_grammar();
2726     advance_to_start();
2727 
2728     for (;;)
2729     {
2730 	c = nextc();
2731 	if (c == EOF)
2732 	    break;
2733 	if (isalpha(c)
2734 	    || c == '_'
2735 	    || c == '.'
2736 	    || c == '$'
2737 	    || c == '\''
2738 	    || c == '"')
2739 	    add_symbol();
2740 #if defined(YYBTYACC)
2741 	else if (c == L_CURL || c == '=' || (backtrack && c == L_BRAC))
2742 #else
2743 	else if (c == L_CURL || c == '=')
2744 #endif
2745 	    copy_action();
2746 	else if (c == '|')
2747 	{
2748 	    end_rule();
2749 	    start_rule(plhs[nrules - 1], 0);
2750 	    ++cptr;
2751 	}
2752 	else if (c == '%')
2753 	{
2754 	    if (mark_symbol())
2755 		break;
2756 	}
2757 	else
2758 	    syntax_error(lineno, line, cptr);
2759     }
2760     end_rule();
2761 #if defined(YYBTYACC)
2762     if (goal->args > 0)
2763 	start_requires_args(goal->name);
2764 #endif
2765 }
2766 
2767 static void
2768 free_tags(void)
2769 {
2770     int i;
2771 
2772     if (tag_table == 0)
2773 	return;
2774 
2775     for (i = 0; i < ntags; ++i)
2776     {
2777 	assert(tag_table[i]);
2778 	FREE(tag_table[i]);
2779     }
2780     FREE(tag_table);
2781 }
2782 
2783 static void
2784 pack_names(void)
2785 {
2786     bucket *bp;
2787     char *p, *s, *t;
2788 
2789     name_pool_size = 13;	/* 13 == sizeof("$end") + sizeof("$accept") */
2790     for (bp = first_symbol; bp; bp = bp->next)
2791 	name_pool_size += strlen(bp->name) + 1;
2792 
2793     name_pool = TMALLOC(char, name_pool_size);
2794     NO_SPACE(name_pool);
2795 
2796     strcpy(name_pool, "$accept");
2797     strcpy(name_pool + 8, "$end");
2798     t = name_pool + 13;
2799     for (bp = first_symbol; bp; bp = bp->next)
2800     {
2801 	p = t;
2802 	s = bp->name;
2803 	while ((*t++ = *s++) != 0)
2804 	    continue;
2805 	FREE(bp->name);
2806 	bp->name = p;
2807     }
2808 }
2809 
2810 static void
2811 check_symbols(void)
2812 {
2813     bucket *bp;
2814 
2815     if (goal->class == UNKNOWN)
2816 	undefined_goal(goal->name);
2817 
2818     for (bp = first_symbol; bp; bp = bp->next)
2819     {
2820 	if (bp->class == UNKNOWN)
2821 	{
2822 	    undefined_symbol_warning(bp->name);
2823 	    bp->class = TERM;
2824 	}
2825     }
2826 }
2827 
2828 static void
2829 protect_string(char *src, char **des)
2830 {
2831     unsigned len;
2832     char *s;
2833     char *d;
2834 
2835     *des = src;
2836     if (src)
2837     {
2838 	len = 1;
2839 	s = src;
2840 	while (*s)
2841 	{
2842 	    if ('\\' == *s || '"' == *s)
2843 		len++;
2844 	    s++;
2845 	    len++;
2846 	}
2847 
2848 	*des = d = TMALLOC(char, len);
2849 	NO_SPACE(d);
2850 
2851 	s = src;
2852 	while (*s)
2853 	{
2854 	    if ('\\' == *s || '"' == *s)
2855 		*d++ = '\\';
2856 	    *d++ = *s++;
2857 	}
2858 	*d = '\0';
2859     }
2860 }
2861 
2862 static void
2863 pack_symbols(void)
2864 {
2865     bucket *bp;
2866     bucket **v;
2867     Value_t i, j, k, n;
2868 #if defined(YYBTYACC)
2869     Value_t max_tok_pval;
2870 #endif
2871 
2872     nsyms = 2;
2873     ntokens = 1;
2874     for (bp = first_symbol; bp; bp = bp->next)
2875     {
2876 	++nsyms;
2877 	if (bp->class == TERM)
2878 	    ++ntokens;
2879     }
2880     start_symbol = (Value_t) ntokens;
2881     nvars = (Value_t) (nsyms - ntokens);
2882 
2883     symbol_name = TMALLOC(char *, nsyms);
2884     NO_SPACE(symbol_name);
2885 
2886     symbol_value = TMALLOC(Value_t, nsyms);
2887     NO_SPACE(symbol_value);
2888 
2889     symbol_prec = TMALLOC(Value_t, nsyms);
2890     NO_SPACE(symbol_prec);
2891 
2892     symbol_assoc = TMALLOC(char, nsyms);
2893     NO_SPACE(symbol_assoc);
2894 
2895 #if defined(YYBTYACC)
2896     symbol_pval = TMALLOC(Value_t, nsyms);
2897     NO_SPACE(symbol_pval);
2898 
2899     if (destructor)
2900     {
2901 	symbol_destructor = CALLOC(sizeof(char *), nsyms);
2902 	NO_SPACE(symbol_destructor);
2903 
2904 	symbol_type_tag = CALLOC(sizeof(char *), nsyms);
2905 	NO_SPACE(symbol_type_tag);
2906     }
2907 #endif
2908 
2909     v = TMALLOC(bucket *, nsyms);
2910     NO_SPACE(v);
2911 
2912     v[0] = 0;
2913     v[start_symbol] = 0;
2914 
2915     i = 1;
2916     j = (Value_t) (start_symbol + 1);
2917     for (bp = first_symbol; bp; bp = bp->next)
2918     {
2919 	if (bp->class == TERM)
2920 	    v[i++] = bp;
2921 	else
2922 	    v[j++] = bp;
2923     }
2924     assert(i == ntokens && j == nsyms);
2925 
2926     for (i = 1; i < ntokens; ++i)
2927 	v[i]->index = i;
2928 
2929     goal->index = (Index_t) (start_symbol + 1);
2930     k = (Value_t) (start_symbol + 2);
2931     while (++i < nsyms)
2932 	if (v[i] != goal)
2933 	{
2934 	    v[i]->index = k;
2935 	    ++k;
2936 	}
2937 
2938     goal->value = 0;
2939     k = 1;
2940     for (i = (Value_t) (start_symbol + 1); i < nsyms; ++i)
2941     {
2942 	if (v[i] != goal)
2943 	{
2944 	    v[i]->value = k;
2945 	    ++k;
2946 	}
2947     }
2948 
2949     k = 0;
2950     for (i = 1; i < ntokens; ++i)
2951     {
2952 	n = v[i]->value;
2953 	if (n > 256)
2954 	{
2955 	    for (j = k++; j > 0 && symbol_value[j - 1] > n; --j)
2956 		symbol_value[j] = symbol_value[j - 1];
2957 	    symbol_value[j] = n;
2958 	}
2959     }
2960 
2961     assert(v[1] != 0);
2962 
2963     if (v[1]->value == UNDEFINED)
2964 	v[1]->value = 256;
2965 
2966     j = 0;
2967     n = 257;
2968     for (i = 2; i < ntokens; ++i)
2969     {
2970 	if (v[i]->value == UNDEFINED)
2971 	{
2972 	    while (j < k && n == symbol_value[j])
2973 	    {
2974 		while (++j < k && n == symbol_value[j])
2975 		    continue;
2976 		++n;
2977 	    }
2978 	    v[i]->value = n;
2979 	    ++n;
2980 	}
2981     }
2982 
2983     symbol_name[0] = name_pool + 8;
2984     symbol_value[0] = 0;
2985     symbol_prec[0] = 0;
2986     symbol_assoc[0] = TOKEN;
2987 #if defined(YYBTYACC)
2988     symbol_pval[0] = 0;
2989     max_tok_pval = 0;
2990 #endif
2991     for (i = 1; i < ntokens; ++i)
2992     {
2993 	symbol_name[i] = v[i]->name;
2994 	symbol_value[i] = v[i]->value;
2995 	symbol_prec[i] = v[i]->prec;
2996 	symbol_assoc[i] = v[i]->assoc;
2997 #if defined(YYBTYACC)
2998 	symbol_pval[i] = v[i]->value;
2999 	if (symbol_pval[i] > max_tok_pval)
3000 	    max_tok_pval = symbol_pval[i];
3001 	if (destructor)
3002 	{
3003 	    symbol_destructor[i] = v[i]->destructor;
3004 	    symbol_type_tag[i] = v[i]->tag;
3005 	}
3006 #endif
3007     }
3008     symbol_name[start_symbol] = name_pool;
3009     symbol_value[start_symbol] = -1;
3010     symbol_prec[start_symbol] = 0;
3011     symbol_assoc[start_symbol] = TOKEN;
3012 #if defined(YYBTYACC)
3013     symbol_pval[start_symbol] = (Value_t) (max_tok_pval + 1);
3014 #endif
3015     for (++i; i < nsyms; ++i)
3016     {
3017 	k = v[i]->index;
3018 	symbol_name[k] = v[i]->name;
3019 	symbol_value[k] = v[i]->value;
3020 	symbol_prec[k] = v[i]->prec;
3021 	symbol_assoc[k] = v[i]->assoc;
3022 #if defined(YYBTYACC)
3023 	symbol_pval[k] = (Value_t) ((max_tok_pval + 1) + v[i]->value + 1);
3024 	if (destructor)
3025 	{
3026 	    symbol_destructor[k] = v[i]->destructor;
3027 	    symbol_type_tag[k] = v[i]->tag;
3028 	}
3029 #endif
3030     }
3031 
3032     if (gflag)
3033     {
3034 	symbol_pname = TMALLOC(char *, nsyms);
3035 	NO_SPACE(symbol_pname);
3036 
3037 	for (i = 0; i < nsyms; ++i)
3038 	    protect_string(symbol_name[i], &(symbol_pname[i]));
3039     }
3040 
3041     FREE(v);
3042 }
3043 
3044 static void
3045 pack_grammar(void)
3046 {
3047     int i;
3048     Value_t j;
3049     Assoc_t assoc;
3050     Value_t prec2;
3051 
3052     ritem = TMALLOC(Value_t, nitems);
3053     NO_SPACE(ritem);
3054 
3055     rlhs = TMALLOC(Value_t, nrules);
3056     NO_SPACE(rlhs);
3057 
3058     rrhs = TMALLOC(Value_t, nrules + 1);
3059     NO_SPACE(rrhs);
3060 
3061     rprec = TREALLOC(Value_t, rprec, nrules);
3062     NO_SPACE(rprec);
3063 
3064     rassoc = TREALLOC(Assoc_t, rassoc, nrules);
3065     NO_SPACE(rassoc);
3066 
3067     ritem[0] = -1;
3068     ritem[1] = goal->index;
3069     ritem[2] = 0;
3070     ritem[3] = -2;
3071     rlhs[0] = 0;
3072     rlhs[1] = 0;
3073     rlhs[2] = start_symbol;
3074     rrhs[0] = 0;
3075     rrhs[1] = 0;
3076     rrhs[2] = 1;
3077 
3078     j = 4;
3079     for (i = 3; i < nrules; ++i)
3080     {
3081 #if defined(YYBTYACC)
3082 	if (plhs[i]->args > 0)
3083 	{
3084 	    if (plhs[i]->argnames)
3085 	    {
3086 		FREE(plhs[i]->argnames);
3087 		plhs[i]->argnames = NULL;
3088 	    }
3089 	    if (plhs[i]->argtags)
3090 	    {
3091 		FREE(plhs[i]->argtags);
3092 		plhs[i]->argtags = NULL;
3093 	    }
3094 	}
3095 #endif /* defined(YYBTYACC) */
3096 	rlhs[i] = plhs[i]->index;
3097 	rrhs[i] = j;
3098 	assoc = TOKEN;
3099 	prec2 = 0;
3100 	while (pitem[j])
3101 	{
3102 	    ritem[j] = pitem[j]->index;
3103 	    if (pitem[j]->class == TERM)
3104 	    {
3105 		prec2 = pitem[j]->prec;
3106 		assoc = pitem[j]->assoc;
3107 	    }
3108 	    ++j;
3109 	}
3110 	ritem[j] = (Value_t) - i;
3111 	++j;
3112 	if (rprec[i] == UNDEFINED)
3113 	{
3114 	    rprec[i] = prec2;
3115 	    rassoc[i] = assoc;
3116 	}
3117     }
3118     rrhs[i] = j;
3119 
3120     FREE(plhs);
3121     FREE(pitem);
3122 #if defined(YYBTYACC)
3123     clean_arg_cache();
3124 #endif
3125 }
3126 
3127 static void
3128 print_grammar(void)
3129 {
3130     int i, k;
3131     size_t j, spacing = 0;
3132     FILE *f = verbose_file;
3133 
3134     if (!vflag)
3135 	return;
3136 
3137     k = 1;
3138     for (i = 2; i < nrules; ++i)
3139     {
3140 	if (rlhs[i] != rlhs[i - 1])
3141 	{
3142 	    if (i != 2)
3143 		fprintf(f, "\n");
3144 	    fprintf(f, "%4d  %s :", i - 2, symbol_name[rlhs[i]]);
3145 	    spacing = strlen(symbol_name[rlhs[i]]) + 1;
3146 	}
3147 	else
3148 	{
3149 	    fprintf(f, "%4d  ", i - 2);
3150 	    j = spacing;
3151 	    while (j-- != 0)
3152 		putc(' ', f);
3153 	    putc('|', f);
3154 	}
3155 
3156 	while (ritem[k] >= 0)
3157 	{
3158 	    fprintf(f, " %s", symbol_name[ritem[k]]);
3159 	    ++k;
3160 	}
3161 	++k;
3162 	putc('\n', f);
3163     }
3164 }
3165 
3166 #if defined(YYBTYACC)
3167 static void
3168 finalize_destructors(void)
3169 {
3170     int i;
3171     bucket *bp;
3172     char *tag;
3173 
3174     for (i = 2; i < nsyms; ++i)
3175     {
3176 	tag = symbol_type_tag[i];
3177 	if (symbol_destructor[i] == NULL)
3178 	{
3179 	    if (tag == NULL)
3180 	    {			/* use <> destructor, if there is one */
3181 		if ((bp = default_destructor[UNTYPED_DEFAULT]) != NULL)
3182 		{
3183 		    symbol_destructor[i] = TMALLOC(char,
3184 						   strlen(bp->destructor) + 1);
3185 		    NO_SPACE(symbol_destructor[i]);
3186 		    strcpy(symbol_destructor[i], bp->destructor);
3187 		}
3188 	    }
3189 	    else
3190 	    {			/* use type destructor for this tag, if there is one */
3191 		bp = lookup_type_destructor(tag);
3192 		if (bp->destructor != NULL)
3193 		{
3194 		    symbol_destructor[i] = TMALLOC(char,
3195 						   strlen(bp->destructor) + 1);
3196 		    NO_SPACE(symbol_destructor[i]);
3197 		    strcpy(symbol_destructor[i], bp->destructor);
3198 		}
3199 		else
3200 		{		/* use <*> destructor, if there is one */
3201 		    if ((bp = default_destructor[TYPED_DEFAULT]) != NULL)
3202 			/* replace "$$" with "(*val).tag" in destructor code */
3203 			symbol_destructor[i]
3204 			    = process_destructor_XX(bp->destructor, tag);
3205 		}
3206 	    }
3207 	}
3208 	else
3209 	{			/* replace "$$" with "(*val)[.tag]" in destructor code */
3210 	    symbol_destructor[i]
3211 		= process_destructor_XX(symbol_destructor[i], tag);
3212 	}
3213     }
3214     /* 'symbol_type_tag[]' elements are freed by 'free_tags()' */
3215     DO_FREE(symbol_type_tag);	/* no longer needed */
3216     if ((bp = default_destructor[UNTYPED_DEFAULT]) != NULL)
3217     {
3218 	FREE(bp->name);
3219 	/* 'bp->tag' is a static value, don't free */
3220 	FREE(bp->destructor);
3221 	FREE(bp);
3222     }
3223     if ((bp = default_destructor[TYPED_DEFAULT]) != NULL)
3224     {
3225 	FREE(bp->name);
3226 	/* 'bp->tag' is a static value, don't free */
3227 	FREE(bp->destructor);
3228 	FREE(bp);
3229     }
3230     if ((bp = default_destructor[TYPE_SPECIFIED]) != NULL)
3231     {
3232 	bucket *p;
3233 	for (; bp; bp = p)
3234 	{
3235 	    p = bp->link;
3236 	    FREE(bp->name);
3237 	    /* 'bp->tag' freed by 'free_tags()' */
3238 	    FREE(bp->destructor);
3239 	    FREE(bp);
3240 	}
3241     }
3242 }
3243 #endif /* defined(YYBTYACC) */
3244 
3245 void
3246 reader(void)
3247 {
3248     write_section(code_file, banner);
3249     create_symbol_table();
3250     read_declarations();
3251     read_grammar();
3252     free_symbol_table();
3253     pack_names();
3254     check_symbols();
3255     pack_symbols();
3256     pack_grammar();
3257     free_symbols();
3258     print_grammar();
3259 #if defined(YYBTYACC)
3260     if (destructor)
3261 	finalize_destructors();
3262 #endif
3263     free_tags();
3264 }
3265 
3266 #ifdef NO_LEAKS
3267 static param *
3268 free_declarations(param * list)
3269 {
3270     while (list != 0)
3271     {
3272 	param *next = list->next;
3273 	free(list->type);
3274 	free(list->name);
3275 	free(list->type2);
3276 	free(list);
3277 	list = next;
3278     }
3279     return list;
3280 }
3281 
3282 void
3283 reader_leaks(void)
3284 {
3285     lex_param = free_declarations(lex_param);
3286     parse_param = free_declarations(parse_param);
3287 
3288     DO_FREE(line);
3289     DO_FREE(rrhs);
3290     DO_FREE(rlhs);
3291     DO_FREE(rprec);
3292     DO_FREE(ritem);
3293     DO_FREE(rassoc);
3294     DO_FREE(cache);
3295     DO_FREE(name_pool);
3296     DO_FREE(symbol_name);
3297     DO_FREE(symbol_prec);
3298     DO_FREE(symbol_assoc);
3299     DO_FREE(symbol_value);
3300 #if defined(YYBTYACC)
3301     DO_FREE(symbol_pval);
3302     DO_FREE(symbol_destructor);
3303     DO_FREE(symbol_type_tag);
3304 #endif
3305 }
3306 #endif
3307