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