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