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