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