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