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