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