1 /* $Id: reader.c,v 1.91 2022/01/09 18:04:58 tom Exp $ */
2
3 #include "defs.h"
4
5 /* The line size must be a positive integer. One hundred was chosen */
6 /* because few lines in Yacc input grammars exceed 100 characters. */
7 /* Note that if a line exceeds LINESIZE characters, the line buffer */
8 /* will be expanded to accommodate it. */
9
10 #define LINESIZE 100
11
12 #define L_CURL '{'
13 #define R_CURL '}'
14 #define L_PAREN '('
15 #define R_PAREN ')'
16 #define L_BRAC '['
17 #define R_BRAC ']'
18
19 /* the maximum number of arguments (inherited attributes) to a non-terminal */
20 /* this is a hard limit, but seems more than adequate */
21 #define MAXARGS 20
22
23 #define begin_case(f,n) fprintf(f, "case %d:\n", (int)(n))
24
25 #define end_case(f) \
26 fprintf(f, "\n"); \
27 fprintf_lineno(f, 1, ""); \
28 fprintf(f, "break;\n")
29
30 static void start_rule(bucket *bp, int s_lineno);
31 #if defined(YYBTYACC)
32 static void copy_initial_action(void);
33 static void copy_destructor(void);
34 static char *process_destructor_XX(char *code, char *tag);
35 #endif
36
37 #define CACHE_SIZE 256
38 static char *cache;
39 static int cinc, cache_size;
40
41 int ntags;
42 static int tagmax, havetags;
43 static char **tag_table;
44
45 static char saw_eof;
46 char unionized;
47 char *cptr, *line;
48 static int linesize;
49
50 static bucket *goal;
51 static Value_t prec;
52 static int gensym;
53 static char last_was_action;
54 #if defined(YYBTYACC)
55 static int trialaction;
56 #endif
57
58 static int maxitems;
59 static bucket **pitem;
60
61 static int maxrules;
62 static bucket **plhs;
63
64 static size_t name_pool_size;
65 static char *name_pool;
66
67 char line_format[] = "#line %d \"%s\"\n";
68
69 param *lex_param;
70 param *parse_param;
71
72 static const char *code_keys[] =
73 {
74 "", "requires", "provides", "top", "imports",
75 };
76
77 struct code_lines code_lines[CODE_MAX];
78
79 #if defined(YYBTYACC)
80 int destructor = 0; /* =1 if at least one %destructor */
81
82 static bucket *default_destructor[3] =
83 {0, 0, 0};
84
85 #define UNTYPED_DEFAULT 0
86 #define TYPED_DEFAULT 1
87 #define TYPE_SPECIFIED 2
88
89 static bucket *
lookup_type_destructor(char * tag)90 lookup_type_destructor(char *tag)
91 {
92 const char fmt[] = "%.*s destructor";
93 char name[1024] = "\0";
94 bucket *bp, **bpp = &default_destructor[TYPE_SPECIFIED];
95
96 while ((bp = *bpp) != NULL)
97 {
98 if (bp->tag == tag)
99 return (bp);
100 bpp = &bp->link;
101 }
102
103 sprintf(name, fmt, (int)(sizeof(name) - sizeof(fmt)), tag);
104 *bpp = bp = make_bucket(name);
105 bp->tag = tag;
106
107 return (bp);
108 }
109 #endif /* defined(YYBTYACC) */
110
111 static void
cachec(int c)112 cachec(int c)
113 {
114 assert(cinc >= 0);
115 if (cinc >= cache_size)
116 {
117 cache_size += CACHE_SIZE;
118 cache = TREALLOC(char, cache, cache_size);
119 NO_SPACE(cache);
120 }
121 cache[cinc] = (char)c;
122 ++cinc;
123 }
124
125 typedef enum
126 {
127 ldSPC1,
128 ldSPC2,
129 ldNAME,
130 ldSPC3,
131 ldNUM,
132 ldSPC4,
133 ldFILE,
134 ldOK,
135 ldERR
136 }
137 LINE_DIR;
138
139 /*
140 * Expect this pattern:
141 * /^[[:space:]]*#[[:space:]]*
142 * line[[:space:]]+
143 * [[:digit:]]+
144 * ([[:space:]]*|[[:space:]]+"[^"]+")/
145 */
146 static int
line_directive(void)147 line_directive(void)
148 {
149 #define UNLESS(what) if (what) { ld = ldERR; break; }
150 int n;
151 int line_1st = -1;
152 int name_1st = -1;
153 int name_end = -1;
154 LINE_DIR ld = ldSPC1;
155 for (n = 0; (ld <= ldOK) && (line[n] != '\0'); ++n)
156 {
157 int ch = UCH(line[n]);
158 switch (ld)
159 {
160 case ldSPC1:
161 if (isspace(UCH(ch)))
162 {
163 break;
164 }
165 else
166 UNLESS(ch != '#');
167 ld = ldSPC2;
168 break;
169 case ldSPC2:
170 if (isspace(UCH(ch)))
171 {
172 break;
173 }
174 /* FALLTHRU */
175 case ldNAME:
176 UNLESS(strncmp(line + n, "line", 4));
177 n += 4;
178 if (line[n] == '\0')
179 {
180 ld = ldOK;
181 break;
182 }
183 else
184 UNLESS(!isspace(UCH(line[n])));
185 ld = ldSPC3;
186 break;
187 case ldSPC3:
188 if (isspace(UCH(ch)))
189 {
190 break;
191 }
192 else
193 UNLESS(!isdigit(UCH(ch)));
194 line_1st = n;
195 ld = ldNUM; /* this is needed, but cppcheck says no... */
196 /* FALLTHRU */
197 case ldNUM:
198 if (isdigit(UCH(ch)))
199 {
200 break;
201 }
202 else
203 UNLESS(!isspace(UCH(ch)));
204 ld = ldSPC4;
205 break;
206 case ldSPC4:
207 if (isspace(UCH(ch)))
208 {
209 break;
210 }
211 else
212 UNLESS(ch != '"');
213 UNLESS(line[n + 1] == '"');
214 ld = ldFILE;
215 name_1st = n;
216 break;
217 case ldFILE:
218 if (ch != '"')
219 {
220 break;
221 }
222 ld = ldOK;
223 name_end = n;
224 /* FALLTHRU */
225 case ldERR:
226 case ldOK:
227 break;
228 }
229 }
230
231 if (ld == ldOK)
232 {
233 size_t need = (size_t)(name_end - name_1st);
234 if ((long)need > (long)input_file_name_len)
235 {
236 input_file_name_len = ((need + 1) * 3) / 2;
237 input_file_name = TREALLOC(char, input_file_name, input_file_name_len);
238 NO_SPACE(input_file_name);
239 }
240 if ((long)need > 0)
241 {
242 memcpy(input_file_name, line + name_1st + 1, need - 1);
243 input_file_name[need - 1] = '\0';
244 }
245 else
246 {
247 input_file_name[0] = '\0';
248 }
249 }
250
251 if (ld >= ldNUM && ld < ldERR)
252 {
253 if (line_1st >= 0)
254 {
255 lineno = (int)strtol(line + line_1st, NULL, 10) - 1;
256 }
257 else
258 {
259 lineno = 0;
260 }
261 }
262
263 return (ld == ldOK);
264 #undef UNLESS
265 }
266
267 static void
get_line(void)268 get_line(void)
269 {
270 FILE *f = input_file;
271
272 do
273 {
274 int c;
275 int i;
276
277 if (saw_eof || (c = getc(f)) == EOF)
278 {
279 if (line)
280 {
281 FREE(line);
282 line = 0;
283 }
284 cptr = 0;
285 saw_eof = 1;
286 return;
287 }
288
289 if (line == NULL || linesize != (LINESIZE + 1))
290 {
291 if (line)
292 FREE(line);
293 linesize = LINESIZE + 1;
294 line = TMALLOC(char, linesize);
295 NO_SPACE(line);
296 }
297
298 i = 0;
299 ++lineno;
300 for (;;)
301 {
302 line[i++] = (char)c;
303 if (c == '\n')
304 break;
305 if ((i + 3) >= linesize)
306 {
307 linesize += LINESIZE;
308 line = TREALLOC(char, line, linesize);
309 NO_SPACE(line);
310 }
311 c = getc(f);
312 if (c == EOF)
313 {
314 line[i++] = '\n';
315 saw_eof = 1;
316 break;
317 }
318 }
319 line[i] = '\0';
320 }
321 while (line_directive());
322 cptr = line;
323 return;
324 }
325
326 static char *
dup_line(void)327 dup_line(void)
328 {
329 char *p, *s, *t;
330
331 if (line == NULL)
332 return (NULL);
333 s = line;
334 while (*s != '\n')
335 ++s;
336 p = TMALLOC(char, s - line + 1);
337 NO_SPACE(p);
338
339 s = line;
340 t = p;
341 while ((*t++ = *s++) != '\n')
342 continue;
343 return (p);
344 }
345
346 static void
skip_comment(void)347 skip_comment(void)
348 {
349 char *s;
350 struct ainfo a;
351 a.a_lineno = lineno;
352 a.a_line = dup_line();
353 a.a_cptr = a.a_line + (cptr - line);
354
355 s = cptr + 2;
356 for (;;)
357 {
358 if (*s == '*' && s[1] == '/')
359 {
360 cptr = s + 2;
361 FREE(a.a_line);
362 return;
363 }
364 if (*s == '\n')
365 {
366 get_line();
367 if (line == NULL)
368 unterminated_comment(&a);
369 s = cptr;
370 }
371 else
372 ++s;
373 }
374 }
375
376 static int
next_inline(void)377 next_inline(void)
378 {
379 char *s;
380
381 if (line == NULL)
382 {
383 get_line();
384 if (line == NULL)
385 return (EOF);
386 }
387
388 s = cptr;
389 for (;;)
390 {
391 switch (*s)
392 {
393 case '/':
394 if (s[1] == '*')
395 {
396 cptr = s;
397 skip_comment();
398 s = cptr;
399 break;
400 }
401 else if (s[1] == '/')
402 {
403 get_line();
404 if (line == NULL)
405 return (EOF);
406 s = cptr;
407 break;
408 }
409 /* FALLTHRU */
410
411 default:
412 cptr = s;
413 return (*s);
414 }
415 }
416 }
417
418 static int
nextc(void)419 nextc(void)
420 {
421 int ch;
422 int finish = 0;
423
424 do
425 {
426 switch (ch = next_inline())
427 {
428 case '\n':
429 get_line();
430 break;
431 case ' ':
432 case '\t':
433 case '\f':
434 case '\r':
435 case '\v':
436 case ',':
437 case ';':
438 ++cptr;
439 break;
440 case '\\':
441 ch = '%';
442 /* FALLTHRU */
443 default:
444 finish = 1;
445 break;
446 }
447 }
448 while (!finish);
449
450 return ch;
451 }
452 /* *INDENT-OFF* */
453 static struct keyword
454 {
455 char name[16];
456 int token;
457 }
458 keywords[] = {
459 { "binary", NONASSOC },
460 { "code", XCODE },
461 { "debug", NONPOSIX_DEBUG },
462 #if defined(YYBTYACC)
463 { "destructor", DESTRUCTOR },
464 #endif
465 { "error-verbose",ERROR_VERBOSE },
466 { "expect", EXPECT },
467 { "expect-rr", EXPECT_RR },
468 { "ident", IDENT },
469 #if defined(YYBTYACC)
470 { "initial-action", INITIAL_ACTION },
471 #endif
472 { "left", LEFT },
473 { "lex-param", LEX_PARAM },
474 #if defined(YYBTYACC)
475 { "locations", LOCATIONS },
476 #endif
477 { "nonassoc", NONASSOC },
478 { "parse-param", PARSE_PARAM },
479 { "pure-parser", PURE_PARSER },
480 { "right", RIGHT },
481 { "start", START },
482 { "term", TOKEN },
483 { "token", TOKEN },
484 { "token-table", TOKEN_TABLE },
485 { "type", TYPE },
486 { "union", UNION },
487 { "yacc", POSIX_YACC },
488 };
489 /* *INDENT-ON* */
490
491 static int
compare_keys(const void * a,const void * b)492 compare_keys(const void *a, const void *b)
493 {
494 const struct keyword *p = (const struct keyword *)a;
495 const struct keyword *q = (const struct keyword *)b;
496 return strcmp(p->name, q->name);
497 }
498
499 static int
keyword(void)500 keyword(void)
501 {
502 int c;
503 char *t_cptr = cptr;
504
505 c = *++cptr;
506 if (isalpha(UCH(c)))
507 {
508 struct keyword *key;
509
510 cinc = 0;
511 for (;;)
512 {
513 if (isalpha(UCH(c)))
514 {
515 if (isupper(UCH(c)))
516 c = tolower(c);
517 cachec(c);
518 }
519 else if (isdigit(UCH(c))
520 || c == '-'
521 || c == '.'
522 || c == '$')
523 {
524 cachec(c);
525 }
526 else if (c == '_')
527 {
528 /* treat keywords spelled with '_' as if it were '-' */
529 cachec('-');
530 }
531 else
532 {
533 break;
534 }
535 c = *++cptr;
536 }
537 cachec(NUL);
538
539 if ((key = bsearch(cache, keywords,
540 sizeof(keywords) / sizeof(*key),
541 sizeof(*key), compare_keys)))
542 return key->token;
543 }
544 else
545 {
546 ++cptr;
547 if (c == L_CURL)
548 return (TEXT);
549 if (c == '%' || c == '\\')
550 return (MARK);
551 if (c == '<')
552 return (LEFT);
553 if (c == '>')
554 return (RIGHT);
555 if (c == '0')
556 return (TOKEN);
557 if (c == '2')
558 return (NONASSOC);
559 }
560 syntax_error(lineno, line, t_cptr);
561 /*NOTREACHED */
562 }
563
564 static void
copy_ident(void)565 copy_ident(void)
566 {
567 int c;
568 FILE *f = output_file;
569
570 c = nextc();
571 if (c == EOF)
572 unexpected_EOF();
573 if (c != '"')
574 syntax_error(lineno, line, cptr);
575 ++outline;
576 fprintf(f, "#ident \"");
577 for (;;)
578 {
579 c = *++cptr;
580 if (c == '\n')
581 {
582 fprintf(f, "\"\n");
583 return;
584 }
585 putc(c, f);
586 if (c == '"')
587 {
588 putc('\n', f);
589 ++cptr;
590 return;
591 }
592 }
593 }
594
595 static char *
copy_string(int quote)596 copy_string(int quote)
597 {
598 struct mstring *temp = msnew();
599 struct ainfo a;
600 a.a_lineno = lineno;
601 a.a_line = dup_line();
602 a.a_cptr = a.a_line + (cptr - line - 1);
603
604 for (;;)
605 {
606 int c = *cptr++;
607
608 mputc(temp, c);
609 if (c == quote)
610 {
611 FREE(a.a_line);
612 return msdone(temp);
613 }
614 if (c == '\n')
615 unterminated_string(&a);
616 if (c == '\\')
617 {
618 c = *cptr++;
619 mputc(temp, c);
620 if (c == '\n')
621 {
622 get_line();
623 if (line == NULL)
624 unterminated_string(&a);
625 }
626 }
627 }
628 }
629
630 static char *
copy_comment(void)631 copy_comment(void)
632 {
633 struct mstring *temp = msnew();
634 int c;
635
636 c = *cptr;
637 if (c == '/')
638 {
639 mputc(temp, '*');
640 while ((c = *++cptr) != '\n')
641 {
642 mputc(temp, c);
643 if (c == '*' && cptr[1] == '/')
644 mputc(temp, ' ');
645 }
646 mputc(temp, '*');
647 mputc(temp, '/');
648 }
649 else if (c == '*')
650 {
651 struct ainfo a;
652 a.a_lineno = lineno;
653 a.a_line = dup_line();
654 a.a_cptr = a.a_line + (cptr - line - 1);
655
656 mputc(temp, c);
657 ++cptr;
658 for (;;)
659 {
660 c = *cptr++;
661 mputc(temp, c);
662 if (c == '*' && *cptr == '/')
663 {
664 mputc(temp, '/');
665 ++cptr;
666 FREE(a.a_line);
667 return msdone(temp);
668 }
669 if (c == '\n')
670 {
671 get_line();
672 if (line == NULL)
673 unterminated_comment(&a);
674 }
675 }
676 }
677 return msdone(temp);
678 }
679
680 static int
check_key(int pos)681 check_key(int pos)
682 {
683 const char *key = code_keys[pos];
684 while (*cptr && *key)
685 if (*key++ != *cptr++)
686 return 0;
687 if (*key || (!isspace(UCH(*cptr)) && *cptr != L_CURL))
688 return 0;
689 cptr--;
690 return 1;
691 }
692
693 static void
copy_code(void)694 copy_code(void)
695 {
696 int c;
697 int curl;
698 int cline;
699 int on_line = 0;
700 int pos = CODE_HEADER;
701 struct mstring *code_mstr;
702
703 /* read %code <keyword> { */
704 for (;;)
705 {
706 c = *++cptr;
707 if (c == EOF)
708 unexpected_EOF();
709 if (isspace(UCH(c)))
710 continue;
711
712 if (c == L_CURL)
713 break;
714
715 if (pos == CODE_HEADER)
716 {
717 switch (UCH(c))
718 {
719 case 'r':
720 pos = CODE_REQUIRES;
721 break;
722 case 'p':
723 pos = CODE_PROVIDES;
724 break;
725 case 't':
726 pos = CODE_TOP;
727 break;
728 case 'i':
729 pos = CODE_IMPORTS;
730 break;
731 default:
732 break;
733 }
734
735 if (pos == -1 || !check_key(pos))
736 {
737 syntax_error(lineno, line, cptr);
738 /*NOTREACHED */
739 }
740 }
741 }
742
743 cptr++; /* skip initial curl */
744 while (*cptr && isspace(UCH(*cptr))) /* skip space */
745 cptr++;
746 curl = 1; /* nesting count */
747
748 /* gather text */
749 code_lines[pos].name = code_keys[pos];
750 if ((cline = (int)code_lines[pos].num) != 0)
751 {
752 code_mstr = msrenew(code_lines[pos].lines);
753 }
754 else
755 {
756 code_mstr = msnew();
757 }
758 cline++;
759 if (!lflag)
760 msprintf(code_mstr, line_format, lineno, input_file_name);
761 for (;;)
762 {
763 c = *cptr++;
764 switch (c)
765 {
766 case '\0':
767 get_line();
768 if (line == NULL)
769 {
770 unexpected_EOF();
771 /*NOTREACHED */
772 }
773 continue;
774 case '\n':
775 cline++;
776 on_line = 0;
777 break;
778 case L_CURL:
779 curl++;
780 break;
781 case R_CURL:
782 if (--curl == 0)
783 {
784 if (on_line > 1)
785 {
786 mputc(code_mstr, '\n');
787 cline++;
788 }
789 code_lines[pos].lines = msdone(code_mstr);
790 code_lines[pos].num = (size_t)cline;
791 return;
792 }
793 break;
794 default:
795 break;
796 }
797 mputc(code_mstr, c);
798 on_line++;
799 }
800 }
801
802 static void
copy_text(void)803 copy_text(void)
804 {
805 int c;
806 FILE *f = text_file;
807 int need_newline = 0;
808 struct ainfo a;
809 a.a_lineno = lineno;
810 a.a_line = dup_line();
811 a.a_cptr = a.a_line + (cptr - line - 2);
812
813 if (*cptr == '\n')
814 {
815 get_line();
816 if (line == NULL)
817 unterminated_text(&a);
818 }
819 fprintf_lineno(f, lineno, input_file_name);
820
821 loop:
822 c = *cptr++;
823 switch (c)
824 {
825 case '\n':
826 putc('\n', f);
827 need_newline = 0;
828 get_line();
829 if (line)
830 goto loop;
831 unterminated_text(&a);
832
833 case '\'':
834 case '"':
835 putc(c, f);
836 {
837 char *s = copy_string(c);
838 fputs(s, f);
839 free(s);
840 }
841 need_newline = 1;
842 goto loop;
843
844 case '/':
845 putc(c, f);
846 {
847 char *s = copy_comment();
848 fputs(s, f);
849 free(s);
850 }
851 need_newline = 1;
852 goto loop;
853
854 case '%':
855 case '\\':
856 if (*cptr == R_CURL)
857 {
858 if (need_newline)
859 putc('\n', f);
860 ++cptr;
861 FREE(a.a_line);
862 return;
863 }
864 /* FALLTHRU */
865
866 default:
867 putc(c, f);
868 need_newline = 1;
869 goto loop;
870 }
871 }
872
873 static void
puts_both(const char * s)874 puts_both(const char *s)
875 {
876 fputs(s, text_file);
877 if (dflag)
878 fputs(s, union_file);
879 }
880
881 static void
putc_both(int c)882 putc_both(int c)
883 {
884 putc(c, text_file);
885 if (dflag)
886 putc(c, union_file);
887 }
888
889 static void
copy_union(void)890 copy_union(void)
891 {
892 int c;
893 int depth;
894 struct ainfo a;
895 a.a_lineno = lineno;
896 a.a_line = dup_line();
897 a.a_cptr = a.a_line + (cptr - line - 6);
898
899 if (unionized)
900 over_unionized(cptr - 6);
901 unionized = 1;
902
903 puts_both("#ifdef YYSTYPE\n");
904 puts_both("#undef YYSTYPE_IS_DECLARED\n");
905 puts_both("#define YYSTYPE_IS_DECLARED 1\n");
906 puts_both("#endif\n");
907 puts_both("#ifndef YYSTYPE_IS_DECLARED\n");
908 puts_both("#define YYSTYPE_IS_DECLARED 1\n");
909
910 fprintf_lineno(text_file, lineno, input_file_name);
911 puts_both("typedef union YYSTYPE");
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 NONPOSIX_DEBUG:
1900 tflag = 1;
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 = TCMALLOC(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 = TCMALLOC(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 begin_case(f, rule - 2);
2557 fprintf_lineno(f, line_number, input_file_name);
2558 fprintf(f, "%s;", code);
2559 end_case(f);
2560 insert_empty_rule();
2561 plhs[rule]->tag = cache_tag(tag, strlen(tag));
2562 plhs[rule]->class = ARGUMENT;
2563 }
2564 else
2565 {
2566 if (++nitems > maxitems)
2567 expand_items();
2568 pitem[nitems - 1] = plhs[rule];
2569 free(code);
2570 }
2571 return arg + 1;
2572 }
2573 #endif
2574
2575 static void
add_symbol(void)2576 add_symbol(void)
2577 {
2578 int c;
2579 bucket *bp;
2580 int s_lineno = lineno;
2581 #if defined(YYBTYACC)
2582 char *args = NULL;
2583 int argslen = 0;
2584 #endif
2585
2586 c = *cptr;
2587 if (c == '\'' || c == '"')
2588 bp = get_literal();
2589 else
2590 bp = get_name();
2591
2592 c = nextc();
2593 rescan_lineno = lineno; /* line# for possible inherited args rescan */
2594 #if defined(YYBTYACC)
2595 if (c == L_PAREN)
2596 {
2597 ++cptr;
2598 args = copy_args(&argslen);
2599 NO_SPACE(args);
2600 c = nextc();
2601 }
2602 #endif
2603 if (c == ':')
2604 {
2605 end_rule();
2606 start_rule(bp, s_lineno);
2607 #if defined(YYBTYACC)
2608 parse_arginfo(bp, args, argslen);
2609 #endif
2610 ++cptr;
2611 return;
2612 }
2613
2614 if (last_was_action)
2615 insert_empty_rule();
2616 last_was_action = 0;
2617
2618 #if defined(YYBTYACC)
2619 if (bp->args < 0)
2620 bp->args = argslen;
2621 if (argslen == 0 && bp->args > 0 && pitem[nitems - 1] == NULL)
2622 {
2623 int i;
2624 if (plhs[nrules]->args != bp->args)
2625 wrong_number_args_warning("default ", bp->name);
2626 for (i = bp->args - 1; i >= 0; i--)
2627 if (plhs[nrules]->argtags[i] != bp->argtags[i])
2628 wrong_type_for_arg_warning(i + 1, bp->name);
2629 }
2630 else if (bp->args != argslen)
2631 wrong_number_args_warning("", bp->name);
2632 if (args != 0)
2633 {
2634 char *ap = args;
2635 int i = 0;
2636 int elide_cnt = can_elide_arg(&ap, bp->argtags[0]);
2637
2638 if (elide_cnt > argslen)
2639 elide_cnt = 0;
2640 if (elide_cnt)
2641 {
2642 for (i = 1; i < elide_cnt; i++)
2643 if (can_elide_arg(&ap, bp->argtags[i]) != elide_cnt - i)
2644 {
2645 elide_cnt = 0;
2646 break;
2647 }
2648 }
2649 if (elide_cnt)
2650 {
2651 assert(i == elide_cnt);
2652 }
2653 else
2654 {
2655 ap = args;
2656 i = 0;
2657 }
2658 for (; i < argslen; i++)
2659 ap = insert_arg_rule(ap, bp->argtags[i]);
2660 free(args);
2661 }
2662 #endif /* defined(YYBTYACC) */
2663
2664 if (++nitems > maxitems)
2665 expand_items();
2666 pitem[nitems - 1] = bp;
2667 }
2668
2669 static void
copy_action(void)2670 copy_action(void)
2671 {
2672 int c;
2673 int i, j, n;
2674 int depth;
2675 #if defined(YYBTYACC)
2676 int haveyyval = 0;
2677 #endif
2678 char *tag;
2679 FILE *f = action_file;
2680 struct ainfo a;
2681 Value_t *offsets = NULL, maxoffset;
2682 bucket **rhs;
2683
2684 a.a_lineno = lineno;
2685 a.a_line = dup_line();
2686 a.a_cptr = a.a_line + (cptr - line);
2687
2688 if (last_was_action)
2689 insert_empty_rule();
2690 last_was_action = 1;
2691 #if defined(YYBTYACC)
2692 trialaction = (*cptr == L_BRAC);
2693 #endif
2694
2695 begin_case(f, nrules - 2);
2696 #if defined(YYBTYACC)
2697 if (backtrack)
2698 {
2699 if (!trialaction)
2700 fprintf(f, " if (!yytrial)\n");
2701 }
2702 #endif
2703 fprintf_lineno(f, lineno, input_file_name);
2704 if (*cptr == '=')
2705 ++cptr;
2706
2707 /* avoid putting curly-braces in first column, to ease editing */
2708 if (*after_blanks(cptr) == L_CURL)
2709 {
2710 putc('\t', f);
2711 cptr = after_blanks(cptr);
2712 }
2713
2714 maxoffset = 0;
2715 n = 0;
2716 for (i = nitems - 1; pitem[i]; --i)
2717 {
2718 ++n;
2719 if (pitem[i]->class != ARGUMENT)
2720 maxoffset++;
2721 }
2722 if (maxoffset > 0)
2723 {
2724 offsets = TMALLOC(Value_t, maxoffset + 1);
2725 NO_SPACE(offsets);
2726
2727 for (j = 0, i++; i < nitems; i++)
2728 {
2729 if (pitem[i]->class != ARGUMENT)
2730 {
2731 offsets[++j] = (Value_t)(i - nitems + 1);
2732 }
2733 }
2734 }
2735 rhs = pitem + nitems - 1;
2736
2737 depth = 0;
2738 loop:
2739 c = *cptr;
2740 if (c == '$')
2741 {
2742 if (cptr[1] == '<')
2743 {
2744 int d_lineno = lineno;
2745 char *d_line = dup_line();
2746 char *d_cptr = d_line + (cptr - line);
2747
2748 ++cptr;
2749 tag = get_tag();
2750 c = *cptr;
2751 if (c == '$')
2752 {
2753 fprintf(f, "yyval.%s", tag);
2754 ++cptr;
2755 FREE(d_line);
2756 goto loop;
2757 }
2758 else if (isdigit(UCH(c)))
2759 {
2760 i = get_number();
2761 if (i == 0)
2762 fprintf(f, "yystack.l_mark[%d].%s", -n, tag);
2763 else if (i > maxoffset)
2764 {
2765 dollar_warning(d_lineno, i);
2766 fprintf(f, "yystack.l_mark[%ld].%s",
2767 (long)(i - maxoffset), tag);
2768 }
2769 else if (offsets)
2770 fprintf(f, "yystack.l_mark[%ld].%s",
2771 (long)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[%ld].%s", (long)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[%ld]", (long)(i - maxoffset));
2839 }
2840 else if (offsets)
2841 fprintf(f, "yystack.l_mark[%ld]", (long)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 fprintf_lineno(f, lineno, input_file_name);
2948 trialaction = 0;
2949 goto loop;
2950 }
2951 end_case(f);
2952 FREE(a.a_line);
2953 if (maxoffset > 0)
2954 FREE(offsets);
2955 return;
2956 }
2957 }
2958 #endif
2959 putc(c, f);
2960 switch (c)
2961 {
2962 case '\n':
2963 get_line();
2964 if (line)
2965 goto loop;
2966 unterminated_action(&a);
2967
2968 case ';':
2969 if (depth > 0)
2970 goto loop;
2971 end_case(f);
2972 free(a.a_line);
2973 if (maxoffset > 0)
2974 FREE(offsets);
2975 return;
2976
2977 #if defined(YYBTYACC)
2978 case L_BRAC:
2979 if (backtrack)
2980 ++depth;
2981 goto loop;
2982
2983 case R_BRAC:
2984 if (backtrack)
2985 --depth;
2986 goto loop;
2987 #endif
2988
2989 case L_CURL:
2990 ++depth;
2991 goto loop;
2992
2993 case R_CURL:
2994 if (--depth > 0)
2995 goto loop;
2996 #if defined(YYBTYACC)
2997 if (backtrack)
2998 {
2999 c = nextc();
3000 if (c == L_BRAC && !haveyyval)
3001 {
3002 trialaction = 1;
3003 goto loop;
3004 }
3005 if (c == L_CURL && !haveyyval)
3006 {
3007 fprintf(f, " if (!yytrial)\n");
3008 fprintf_lineno(f, lineno, input_file_name);
3009 goto loop;
3010 }
3011 }
3012 #endif
3013 end_case(f);
3014 free(a.a_line);
3015 if (maxoffset > 0)
3016 FREE(offsets);
3017 return;
3018
3019 case '\'':
3020 case '"':
3021 {
3022 char *s = copy_string(c);
3023 fputs(s, f);
3024 free(s);
3025 }
3026 goto loop;
3027
3028 case '/':
3029 {
3030 char *s = copy_comment();
3031 fputs(s, f);
3032 free(s);
3033 }
3034 goto loop;
3035
3036 default:
3037 goto loop;
3038 }
3039 }
3040
3041 #if defined(YYBTYACC)
3042 static char *
get_code(struct ainfo * a,const char * loc)3043 get_code(struct ainfo *a, const char *loc)
3044 {
3045 int c;
3046 int depth;
3047 char *tag;
3048 struct mstring *code_mstr = msnew();
3049
3050 if (!lflag)
3051 msprintf(code_mstr, line_format, lineno, input_file_name);
3052
3053 cptr = after_blanks(cptr);
3054 if (*cptr == L_CURL)
3055 /* avoid putting curly-braces in first column, to ease editing */
3056 mputc(code_mstr, '\t');
3057 else
3058 syntax_error(lineno, line, cptr);
3059
3060 a->a_lineno = lineno;
3061 a->a_line = dup_line();
3062 a->a_cptr = a->a_line + (cptr - line);
3063
3064 depth = 0;
3065 loop:
3066 c = *cptr;
3067 if (c == '$')
3068 {
3069 if (cptr[1] == '<')
3070 {
3071 int d_lineno = lineno;
3072 char *d_line = dup_line();
3073 char *d_cptr = d_line + (cptr - line);
3074
3075 ++cptr;
3076 tag = get_tag();
3077 c = *cptr;
3078 if (c == '$')
3079 {
3080 msprintf(code_mstr, "(*val).%s", tag);
3081 ++cptr;
3082 FREE(d_line);
3083 goto loop;
3084 }
3085 else
3086 dollar_error(d_lineno, d_line, d_cptr);
3087 }
3088 else if (cptr[1] == '$')
3089 {
3090 /* process '$$' later; replacement is context dependent */
3091 msprintf(code_mstr, "$$");
3092 cptr += 2;
3093 goto loop;
3094 }
3095 }
3096 if (c == '@' && cptr[1] == '$')
3097 {
3098 if (!locations)
3099 {
3100 int l_lineno = lineno;
3101 char *l_line = dup_line();
3102 char *l_cptr = l_line + (cptr - line);
3103 syntax_error(l_lineno, l_line, l_cptr);
3104 }
3105 msprintf(code_mstr, "%s", loc);
3106 cptr += 2;
3107 goto loop;
3108 }
3109 if (IS_NAME1(c))
3110 {
3111 do
3112 {
3113 mputc(code_mstr, c);
3114 c = *++cptr;
3115 }
3116 while (IS_NAME2(c));
3117 goto loop;
3118 }
3119 ++cptr;
3120 mputc(code_mstr, c);
3121 switch (c)
3122 {
3123 case '\n':
3124 get_line();
3125 if (line)
3126 goto loop;
3127 unterminated_action(a);
3128
3129 case L_CURL:
3130 ++depth;
3131 goto loop;
3132
3133 case R_CURL:
3134 if (--depth > 0)
3135 goto loop;
3136 goto out;
3137
3138 case '\'':
3139 case '"':
3140 {
3141 char *s = copy_string(c);
3142 msprintf(code_mstr, "%s", s);
3143 free(s);
3144 }
3145 goto loop;
3146
3147 case '/':
3148 {
3149 char *s = copy_comment();
3150 msprintf(code_mstr, "%s", s);
3151 free(s);
3152 }
3153 goto loop;
3154
3155 default:
3156 goto loop;
3157 }
3158 out:
3159 return msdone(code_mstr);
3160 }
3161
3162 static void
copy_initial_action(void)3163 copy_initial_action(void)
3164 {
3165 struct ainfo a;
3166
3167 initial_action = get_code(&a, "yyloc");
3168 free(a.a_line);
3169 }
3170
3171 static void
copy_destructor(void)3172 copy_destructor(void)
3173 {
3174 char *code_text;
3175 struct ainfo a;
3176 bucket *bp;
3177
3178 code_text = get_code(&a, "(*loc)");
3179
3180 for (;;)
3181 {
3182 int c = nextc();
3183 if (c == EOF)
3184 unexpected_EOF();
3185 if (c == '<')
3186 {
3187 if (cptr[1] == '>')
3188 { /* "no semantic type" default destructor */
3189 cptr += 2;
3190 if ((bp = default_destructor[UNTYPED_DEFAULT]) == NULL)
3191 {
3192 static char untyped_default[] = "<>";
3193 bp = make_bucket("untyped default");
3194 bp->tag = untyped_default;
3195 default_destructor[UNTYPED_DEFAULT] = bp;
3196 }
3197 if (bp->destructor != NULL)
3198 destructor_redeclared_warning(&a);
3199 else
3200 /* replace "$$" with "(*val)" in destructor code */
3201 bp->destructor = process_destructor_XX(code_text, NULL);
3202 }
3203 else if (cptr[1] == '*' && cptr[2] == '>')
3204 { /* "no per-symbol or per-type" default destructor */
3205 cptr += 3;
3206 if ((bp = default_destructor[TYPED_DEFAULT]) == NULL)
3207 {
3208 static char typed_default[] = "<*>";
3209 bp = make_bucket("typed default");
3210 bp->tag = typed_default;
3211 default_destructor[TYPED_DEFAULT] = bp;
3212 }
3213 if (bp->destructor != NULL)
3214 destructor_redeclared_warning(&a);
3215 else
3216 {
3217 /* postpone re-processing destructor $$s until end of grammar spec */
3218 bp->destructor = TMALLOC(char, strlen(code_text) + 1);
3219 NO_SPACE(bp->destructor);
3220 strcpy(bp->destructor, code_text);
3221 }
3222 }
3223 else
3224 { /* "semantic type" default destructor */
3225 char *tag = get_tag();
3226 bp = lookup_type_destructor(tag);
3227 if (bp->destructor != NULL)
3228 destructor_redeclared_warning(&a);
3229 else
3230 /* replace "$$" with "(*val).tag" in destructor code */
3231 bp->destructor = process_destructor_XX(code_text, tag);
3232 }
3233 }
3234 else if (isalpha(UCH(c)) || c == '_' || c == '.' || c == '$')
3235 { /* "symbol" destructor */
3236 bp = get_name();
3237 if (bp->destructor != NULL)
3238 destructor_redeclared_warning(&a);
3239 else
3240 {
3241 /* postpone re-processing destructor $$s until end of grammar spec */
3242 bp->destructor = TMALLOC(char, strlen(code_text) + 1);
3243 NO_SPACE(bp->destructor);
3244 strcpy(bp->destructor, code_text);
3245 }
3246 }
3247 else
3248 break;
3249 }
3250 free(a.a_line);
3251 free(code_text);
3252 }
3253
3254 static char *
process_destructor_XX(char * code,char * tag)3255 process_destructor_XX(char *code, char *tag)
3256 {
3257 int c;
3258 int quote;
3259 int depth;
3260 struct mstring *new_code = msnew();
3261 char *codeptr = code;
3262
3263 depth = 0;
3264 loop: /* step thru code */
3265 c = *codeptr;
3266 if (c == '$' && codeptr[1] == '$')
3267 {
3268 codeptr += 2;
3269 if (tag == NULL)
3270 msprintf(new_code, "(*val)");
3271 else
3272 msprintf(new_code, "(*val).%s", tag);
3273 goto loop;
3274 }
3275 if (IS_NAME1(c))
3276 {
3277 do
3278 {
3279 mputc(new_code, c);
3280 c = *++codeptr;
3281 }
3282 while (IS_NAME2(c));
3283 goto loop;
3284 }
3285 ++codeptr;
3286 mputc(new_code, c);
3287 switch (c)
3288 {
3289 case L_CURL:
3290 ++depth;
3291 goto loop;
3292
3293 case R_CURL:
3294 if (--depth > 0)
3295 goto loop;
3296 return msdone(new_code);
3297
3298 case '\'':
3299 case '"':
3300 quote = c;
3301 for (;;)
3302 {
3303 c = *codeptr++;
3304 mputc(new_code, c);
3305 if (c == quote)
3306 goto loop;
3307 if (c == '\\')
3308 {
3309 c = *codeptr++;
3310 mputc(new_code, c);
3311 }
3312 }
3313
3314 case '/':
3315 c = *codeptr;
3316 if (c == '*')
3317 {
3318 mputc(new_code, c);
3319 ++codeptr;
3320 for (;;)
3321 {
3322 c = *codeptr++;
3323 mputc(new_code, c);
3324 if (c == '*' && *codeptr == '/')
3325 {
3326 mputc(new_code, '/');
3327 ++codeptr;
3328 goto loop;
3329 }
3330 }
3331 }
3332 goto loop;
3333
3334 default:
3335 goto loop;
3336 }
3337 }
3338 #endif /* defined(YYBTYACC) */
3339
3340 static int
mark_symbol(void)3341 mark_symbol(void)
3342 {
3343 int c;
3344 bucket *bp = NULL;
3345
3346 c = cptr[1];
3347 if (c == '%' || c == '\\')
3348 {
3349 cptr += 2;
3350 return (1);
3351 }
3352
3353 if (c == '=')
3354 cptr += 2;
3355 else if ((c == 'p' || c == 'P') &&
3356 ((c = cptr[2]) == 'r' || c == 'R') &&
3357 ((c = cptr[3]) == 'e' || c == 'E') &&
3358 ((c = cptr[4]) == 'c' || c == 'C') &&
3359 ((c = cptr[5], !IS_IDENT(c))))
3360 cptr += 5;
3361 else if ((c == 'e' || c == 'E') &&
3362 ((c = cptr[2]) == 'm' || c == 'M') &&
3363 ((c = cptr[3]) == 'p' || c == 'P') &&
3364 ((c = cptr[4]) == 't' || c == 'T') &&
3365 ((c = cptr[5]) == 'y' || c == 'Y') &&
3366 ((c = cptr[6], !IS_IDENT(c))))
3367 {
3368 cptr += 6;
3369 return (1);
3370 }
3371 else
3372 syntax_error(lineno, line, cptr);
3373
3374 c = nextc();
3375 if (isalpha(UCH(c)) || c == '_' || c == '.' || c == '$')
3376 bp = get_name();
3377 else if (c == '\'' || c == '"')
3378 bp = get_literal();
3379 else
3380 {
3381 syntax_error(lineno, line, cptr);
3382 /*NOTREACHED */
3383 }
3384
3385 if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
3386 prec_redeclared();
3387
3388 rprec[nrules] = bp->prec;
3389 rassoc[nrules] = bp->assoc;
3390 return (0);
3391 }
3392
3393 static void
read_grammar(void)3394 read_grammar(void)
3395 {
3396 initialize_grammar();
3397 advance_to_start();
3398
3399 for (;;)
3400 {
3401 int c = nextc();
3402
3403 if (c == EOF)
3404 break;
3405 if (isalpha(UCH(c))
3406 || c == '_'
3407 || c == '.'
3408 || c == '$'
3409 || c == '\''
3410 || c == '"')
3411 {
3412 add_symbol();
3413 }
3414 else if (c == L_CURL || c == '='
3415 #if defined(YYBTYACC)
3416 || (backtrack && c == L_BRAC)
3417 #endif
3418 )
3419 {
3420 copy_action();
3421 }
3422 else if (c == '|')
3423 {
3424 end_rule();
3425 start_rule(plhs[nrules - 1], 0);
3426 ++cptr;
3427 }
3428 else if (c == '%')
3429 {
3430 if (mark_symbol())
3431 break;
3432 }
3433 else
3434 syntax_error(lineno, line, cptr);
3435 }
3436 end_rule();
3437 #if defined(YYBTYACC)
3438 if (goal->args > 0)
3439 start_requires_args(goal->name);
3440 #endif
3441 }
3442
3443 static void
free_tags(void)3444 free_tags(void)
3445 {
3446 int i;
3447
3448 if (tag_table == 0)
3449 return;
3450
3451 for (i = 0; i < ntags; ++i)
3452 {
3453 assert(tag_table[i]);
3454 FREE(tag_table[i]);
3455 }
3456 FREE(tag_table);
3457 }
3458
3459 static void
pack_names(void)3460 pack_names(void)
3461 {
3462 bucket *bp;
3463 char *p;
3464 char *t;
3465
3466 name_pool_size = 13; /* 13 == sizeof("$end") + sizeof("$accept") */
3467 for (bp = first_symbol; bp; bp = bp->next)
3468 name_pool_size += strlen(bp->name) + 1;
3469
3470 name_pool = TMALLOC(char, name_pool_size);
3471 NO_SPACE(name_pool);
3472
3473 strcpy(name_pool, "$accept");
3474 strcpy(name_pool + 8, "$end");
3475 t = name_pool + 13;
3476 for (bp = first_symbol; bp; bp = bp->next)
3477 {
3478 char *s = bp->name;
3479
3480 p = t;
3481 while ((*t++ = *s++) != 0)
3482 continue;
3483 FREE(bp->name);
3484 bp->name = p;
3485 }
3486 }
3487
3488 static void
check_symbols(void)3489 check_symbols(void)
3490 {
3491 bucket *bp;
3492
3493 if (goal->class == UNKNOWN)
3494 undefined_goal(goal->name);
3495
3496 for (bp = first_symbol; bp; bp = bp->next)
3497 {
3498 if (bp->class == UNKNOWN)
3499 {
3500 undefined_symbol_warning(bp->name);
3501 bp->class = TERM;
3502 }
3503 }
3504 }
3505
3506 static void
protect_string(char * src,char ** des)3507 protect_string(char *src, char **des)
3508 {
3509 *des = src;
3510 if (src)
3511 {
3512 char *s;
3513 char *d;
3514
3515 unsigned len = 1;
3516
3517 s = src;
3518 while (*s)
3519 {
3520 if ('\\' == *s || '"' == *s)
3521 len++;
3522 s++;
3523 len++;
3524 }
3525
3526 *des = d = TMALLOC(char, len);
3527 NO_SPACE(d);
3528
3529 s = src;
3530 while (*s)
3531 {
3532 if ('\\' == *s || '"' == *s)
3533 *d++ = '\\';
3534 *d++ = *s++;
3535 }
3536 *d = '\0';
3537 }
3538 }
3539
3540 static void
pack_symbols(void)3541 pack_symbols(void)
3542 {
3543 bucket *bp;
3544 bucket **v;
3545 Value_t i, j, k, n;
3546 #if defined(YYBTYACC)
3547 Value_t max_tok_pval;
3548 #endif
3549
3550 nsyms = 2;
3551 ntokens = 1;
3552 for (bp = first_symbol; bp; bp = bp->next)
3553 {
3554 ++nsyms;
3555 if (bp->class == TERM)
3556 ++ntokens;
3557 }
3558 start_symbol = (Value_t)ntokens;
3559 nvars = (Value_t)(nsyms - ntokens);
3560
3561 symbol_name = TMALLOC(char *, nsyms);
3562 NO_SPACE(symbol_name);
3563
3564 symbol_value = TMALLOC(Value_t, nsyms);
3565 NO_SPACE(symbol_value);
3566
3567 symbol_prec = TMALLOC(Value_t, nsyms);
3568 NO_SPACE(symbol_prec);
3569
3570 symbol_assoc = TMALLOC(char, nsyms);
3571 NO_SPACE(symbol_assoc);
3572
3573 #if defined(YYBTYACC)
3574 symbol_pval = TMALLOC(Value_t, nsyms);
3575 NO_SPACE(symbol_pval);
3576
3577 if (destructor)
3578 {
3579 symbol_destructor = CALLOC(sizeof(char *), nsyms);
3580 NO_SPACE(symbol_destructor);
3581
3582 symbol_type_tag = CALLOC(sizeof(char *), nsyms);
3583 NO_SPACE(symbol_type_tag);
3584 }
3585 #endif
3586
3587 v = TMALLOC(bucket *, nsyms);
3588 NO_SPACE(v);
3589
3590 v[0] = 0;
3591 v[start_symbol] = 0;
3592
3593 i = 1;
3594 j = (Value_t)(start_symbol + 1);
3595 for (bp = first_symbol; bp; bp = bp->next)
3596 {
3597 if (bp->class == TERM)
3598 v[i++] = bp;
3599 else
3600 v[j++] = bp;
3601 }
3602 assert(i == ntokens && j == nsyms);
3603
3604 for (i = 1; i < ntokens; ++i)
3605 v[i]->index = i;
3606
3607 goal->index = (Index_t)(start_symbol + 1);
3608 k = (Value_t)(start_symbol + 2);
3609 while (++i < nsyms)
3610 if (v[i] != goal)
3611 {
3612 v[i]->index = k;
3613 ++k;
3614 }
3615
3616 goal->value = 0;
3617 k = 1;
3618 for (i = (Value_t)(start_symbol + 1); i < nsyms; ++i)
3619 {
3620 if (v[i] != goal)
3621 {
3622 v[i]->value = k;
3623 ++k;
3624 }
3625 }
3626
3627 k = 0;
3628 for (i = 1; i < ntokens; ++i)
3629 {
3630 n = v[i]->value;
3631 if (n > 256)
3632 {
3633 for (j = k++; j > 0 && symbol_value[j - 1] > n; --j)
3634 symbol_value[j] = symbol_value[j - 1];
3635 symbol_value[j] = n;
3636 }
3637 }
3638
3639 assert(v[1] != 0);
3640
3641 if (v[1]->value == UNDEFINED)
3642 v[1]->value = 256;
3643
3644 j = 0;
3645 n = 257;
3646 for (i = 2; i < ntokens; ++i)
3647 {
3648 if (v[i]->value == UNDEFINED)
3649 {
3650 while (j < k && n == symbol_value[j])
3651 {
3652 while (++j < k && n == symbol_value[j])
3653 continue;
3654 ++n;
3655 }
3656 v[i]->value = n;
3657 ++n;
3658 }
3659 }
3660
3661 symbol_name[0] = name_pool + 8;
3662 symbol_value[0] = 0;
3663 symbol_prec[0] = 0;
3664 symbol_assoc[0] = TOKEN;
3665 #if defined(YYBTYACC)
3666 symbol_pval[0] = 0;
3667 max_tok_pval = 0;
3668 #endif
3669 for (i = 1; i < ntokens; ++i)
3670 {
3671 symbol_name[i] = v[i]->name;
3672 symbol_value[i] = v[i]->value;
3673 symbol_prec[i] = v[i]->prec;
3674 symbol_assoc[i] = v[i]->assoc;
3675 #if defined(YYBTYACC)
3676 symbol_pval[i] = v[i]->value;
3677 if (symbol_pval[i] > max_tok_pval)
3678 max_tok_pval = symbol_pval[i];
3679 if (destructor)
3680 {
3681 symbol_destructor[i] = v[i]->destructor;
3682 symbol_type_tag[i] = v[i]->tag;
3683 }
3684 #endif
3685 }
3686 symbol_name[start_symbol] = name_pool;
3687 symbol_value[start_symbol] = -1;
3688 symbol_prec[start_symbol] = 0;
3689 symbol_assoc[start_symbol] = TOKEN;
3690 #if defined(YYBTYACC)
3691 symbol_pval[start_symbol] = (Value_t)(max_tok_pval + 1);
3692 #endif
3693 for (++i; i < nsyms; ++i)
3694 {
3695 k = v[i]->index;
3696 symbol_name[k] = v[i]->name;
3697 symbol_value[k] = v[i]->value;
3698 symbol_prec[k] = v[i]->prec;
3699 symbol_assoc[k] = v[i]->assoc;
3700 #if defined(YYBTYACC)
3701 symbol_pval[k] = (Value_t)((max_tok_pval + 1) + v[i]->value + 1);
3702 if (destructor)
3703 {
3704 symbol_destructor[k] = v[i]->destructor;
3705 symbol_type_tag[k] = v[i]->tag;
3706 }
3707 #endif
3708 }
3709
3710 if (gflag)
3711 {
3712 symbol_pname = TMALLOC(char *, nsyms);
3713 NO_SPACE(symbol_pname);
3714
3715 for (i = 0; i < nsyms; ++i)
3716 protect_string(symbol_name[i], &(symbol_pname[i]));
3717 }
3718
3719 FREE(v);
3720 }
3721
3722 static void
pack_grammar(void)3723 pack_grammar(void)
3724 {
3725 int i;
3726 Value_t j;
3727
3728 ritem = TMALLOC(Value_t, nitems);
3729 NO_SPACE(ritem);
3730
3731 rlhs = TMALLOC(Value_t, nrules);
3732 NO_SPACE(rlhs);
3733
3734 rrhs = TMALLOC(Value_t, nrules + 1);
3735 NO_SPACE(rrhs);
3736
3737 rprec = TREALLOC(Value_t, rprec, nrules);
3738 NO_SPACE(rprec);
3739
3740 rassoc = TREALLOC(Assoc_t, rassoc, nrules);
3741 NO_SPACE(rassoc);
3742
3743 ritem[0] = -1;
3744 ritem[1] = goal->index;
3745 ritem[2] = 0;
3746 ritem[3] = -2;
3747 rlhs[0] = 0;
3748 rlhs[1] = 0;
3749 rlhs[2] = start_symbol;
3750 rrhs[0] = 0;
3751 rrhs[1] = 0;
3752 rrhs[2] = 1;
3753
3754 j = 4;
3755 for (i = 3; i < nrules; ++i)
3756 {
3757 Assoc_t assoc;
3758 Value_t prec2;
3759
3760 #if defined(YYBTYACC)
3761 if (plhs[i]->args > 0)
3762 {
3763 if (plhs[i]->argnames)
3764 {
3765 FREE(plhs[i]->argnames);
3766 plhs[i]->argnames = NULL;
3767 }
3768 if (plhs[i]->argtags)
3769 {
3770 FREE(plhs[i]->argtags);
3771 plhs[i]->argtags = NULL;
3772 }
3773 }
3774 #endif /* defined(YYBTYACC) */
3775 rlhs[i] = plhs[i]->index;
3776 rrhs[i] = j;
3777 assoc = TOKEN;
3778 prec2 = 0;
3779 while (pitem[j])
3780 {
3781 ritem[j] = pitem[j]->index;
3782 if (pitem[j]->class == TERM)
3783 {
3784 prec2 = pitem[j]->prec;
3785 assoc = pitem[j]->assoc;
3786 }
3787 ++j;
3788 }
3789 ritem[j] = (Value_t)-i;
3790 ++j;
3791 if (rprec[i] == UNDEFINED)
3792 {
3793 rprec[i] = prec2;
3794 rassoc[i] = assoc;
3795 }
3796 }
3797 rrhs[i] = j;
3798
3799 FREE(plhs);
3800 FREE(pitem);
3801 #if defined(YYBTYACC)
3802 clean_arg_cache();
3803 #endif
3804 }
3805
3806 static void
print_grammar(void)3807 print_grammar(void)
3808 {
3809 int i, k;
3810 size_t j, spacing = 0;
3811 FILE *f = verbose_file;
3812
3813 if (!vflag)
3814 return;
3815
3816 k = 1;
3817 for (i = 2; i < nrules; ++i)
3818 {
3819 if (rlhs[i] != rlhs[i - 1])
3820 {
3821 if (i != 2)
3822 fprintf(f, "\n");
3823 fprintf(f, "%4d %s :", i - 2, symbol_name[rlhs[i]]);
3824 spacing = strlen(symbol_name[rlhs[i]]) + 1;
3825 }
3826 else
3827 {
3828 fprintf(f, "%4d ", i - 2);
3829 j = spacing;
3830 while (j-- != 0)
3831 putc(' ', f);
3832 putc('|', f);
3833 }
3834
3835 while (ritem[k] >= 0)
3836 {
3837 fprintf(f, " %s", symbol_name[ritem[k]]);
3838 ++k;
3839 }
3840 ++k;
3841 putc('\n', f);
3842 }
3843 }
3844
3845 #if defined(YYBTYACC)
3846 static void
finalize_destructors(void)3847 finalize_destructors(void)
3848 {
3849 int i;
3850 bucket *bp;
3851
3852 for (i = 2; i < nsyms; ++i)
3853 {
3854 char *tag = symbol_type_tag[i];
3855
3856 if (symbol_destructor[i] == NULL)
3857 {
3858 if (tag == NULL)
3859 { /* use <> destructor, if there is one */
3860 if ((bp = default_destructor[UNTYPED_DEFAULT]) != NULL)
3861 {
3862 symbol_destructor[i] = TMALLOC(char,
3863 strlen(bp->destructor) + 1);
3864 NO_SPACE(symbol_destructor[i]);
3865 strcpy(symbol_destructor[i], bp->destructor);
3866 }
3867 }
3868 else
3869 { /* use type destructor for this tag, if there is one */
3870 bp = lookup_type_destructor(tag);
3871 if (bp->destructor != NULL)
3872 {
3873 symbol_destructor[i] = TMALLOC(char,
3874 strlen(bp->destructor) + 1);
3875 NO_SPACE(symbol_destructor[i]);
3876 strcpy(symbol_destructor[i], bp->destructor);
3877 }
3878 else
3879 { /* use <*> destructor, if there is one */
3880 if ((bp = default_destructor[TYPED_DEFAULT]) != NULL)
3881 /* replace "$$" with "(*val).tag" in destructor code */
3882 symbol_destructor[i]
3883 = process_destructor_XX(bp->destructor, tag);
3884 }
3885 }
3886 }
3887 else
3888 { /* replace "$$" with "(*val)[.tag]" in destructor code */
3889 char *destructor_source = symbol_destructor[i];
3890 symbol_destructor[i]
3891 = process_destructor_XX(destructor_source, tag);
3892 FREE(destructor_source);
3893 }
3894 }
3895 /* 'symbol_type_tag[]' elements are freed by 'free_tags()' */
3896 DO_FREE(symbol_type_tag); /* no longer needed */
3897 if ((bp = default_destructor[UNTYPED_DEFAULT]) != NULL)
3898 {
3899 FREE(bp->name);
3900 /* 'bp->tag' is a static value, don't free */
3901 FREE(bp->destructor);
3902 FREE(bp);
3903 }
3904 if ((bp = default_destructor[TYPED_DEFAULT]) != NULL)
3905 {
3906 FREE(bp->name);
3907 /* 'bp->tag' is a static value, don't free */
3908 FREE(bp->destructor);
3909 FREE(bp);
3910 }
3911 if ((bp = default_destructor[TYPE_SPECIFIED]) != NULL)
3912 {
3913 bucket *p;
3914 for (; bp; bp = p)
3915 {
3916 p = bp->link;
3917 FREE(bp->name);
3918 /* 'bp->tag' freed by 'free_tags()' */
3919 FREE(bp->destructor);
3920 FREE(bp);
3921 }
3922 }
3923 }
3924 #endif /* defined(YYBTYACC) */
3925
3926 void
reader(void)3927 reader(void)
3928 {
3929 write_section(code_file, banner);
3930 create_symbol_table();
3931 read_declarations();
3932 read_grammar();
3933 free_symbol_table();
3934 pack_names();
3935 check_symbols();
3936 pack_symbols();
3937 pack_grammar();
3938 free_symbols();
3939 print_grammar();
3940 #if defined(YYBTYACC)
3941 if (destructor)
3942 finalize_destructors();
3943 #endif
3944 free_tags();
3945 }
3946
3947 #ifdef NO_LEAKS
3948 static param *
free_declarations(param * list)3949 free_declarations(param *list)
3950 {
3951 while (list != 0)
3952 {
3953 param *next = list->next;
3954 free(list->type);
3955 free(list->name);
3956 free(list->type2);
3957 free(list);
3958 list = next;
3959 }
3960 return list;
3961 }
3962
3963 void
reader_leaks(void)3964 reader_leaks(void)
3965 {
3966 lex_param = free_declarations(lex_param);
3967 parse_param = free_declarations(parse_param);
3968
3969 DO_FREE(line);
3970 DO_FREE(rrhs);
3971 DO_FREE(rlhs);
3972 DO_FREE(rprec);
3973 DO_FREE(ritem);
3974 DO_FREE(rassoc);
3975 DO_FREE(cache);
3976 DO_FREE(name_pool);
3977 DO_FREE(symbol_name);
3978 DO_FREE(symbol_prec);
3979 DO_FREE(symbol_assoc);
3980 DO_FREE(symbol_value);
3981 #if defined(YYBTYACC)
3982 DO_FREE(symbol_pval);
3983 DO_FREE(symbol_destructor);
3984 DO_FREE(symbol_type_tag);
3985 #endif
3986 }
3987 #endif
3988