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