From f13bbff7f1eacbdca679cd6c1a2fc536d9b90b60 Mon Sep 17 00:00:00 2001 From: "Thomas E. Dickey" Date: Fri, 4 Apr 2014 01:13:50 -0400 Subject: [PATCH] snapshot of project "byacc", label t20140403-gcov --- CHANGES | 14 + MANIFEST | 2 +- makefile.in | 6 +- output.c | 301 +++++++++++- reader.c | 1362 +++++++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 1456 insertions(+), 229 deletions(-) diff --git a/CHANGES b/CHANGES index 612f663..5aa010e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,17 @@ +2014-04-03 Thomas E. Dickey + + * reader.c: + merge-in 3/4 of btyacc's changes, deferring those which change test-outputs. + Tom Shield's changes split-out copy_string() and copy_comment() functions + to simplify some logic, as well as adding btyacc-only chunks + + * makefile.in: build mstring.o, needed for changes in reader.c + + * output.c: + merge-in all of btyacc's changes which do not change byacc's test-output. + Some of the merge uses ifdef-changes which I applied to ongoing resync, + e.g., the introduction of PER_STATE. + 2014-04-02 Thomas E. Dickey * output.c: fix typo diff --git a/MANIFEST b/MANIFEST index dd06b27..16b5c52 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,4 +1,4 @@ -MANIFEST for byacc, version t20140402-gcov +MANIFEST for byacc, version t20140403-gcov -------------------------------------------------------------------------------- MANIFEST this file ACKNOWLEDGEMENTS original version of byacc - 1993 diff --git a/makefile.in b/makefile.in index 7486ea6..4e29711 100644 --- a/makefile.in +++ b/makefile.in @@ -1,4 +1,4 @@ -# $Id: makefile.in,v 1.20 2014/03/25 23:14:31 Tom.Shields Exp $ +# $Id: makefile.in,v 1.21 2014/04/04 00:25:27 tom Exp $ # # UNIX template-makefile for Berkeley Yacc @@ -58,6 +58,7 @@ C_FILES = \ lr0.c \ main.c \ mkpar.c \ + mstring.c \ output.c \ reader.c \ skeleton.c \ @@ -73,6 +74,7 @@ OBJS = \ lr0$o \ main$o \ mkpar$o \ + mstring$o \ output$o \ reader$o \ skeleton$o \ @@ -80,6 +82,8 @@ OBJS = \ verbose$o \ warshall$o +SKELETON = yaccpar.skel + TRANSFORM_BIN = sed 's/$x$$//' |sed '$(transform)'|sed 's/$$/$x/' TRANSFORM_MAN = sed 's/$(manext)$$//'|sed '$(transform)'|sed 's/$$/$(manext)/' diff --git a/output.c b/output.c index 6e5f055..e9b396c 100644 --- a/output.c +++ b/output.c @@ -1,10 +1,16 @@ -/* $Id: output.c,v 1.51 2014/04/03 00:40:29 tom Exp $ */ +/* $Id: output.c,v 1.52 2014/04/03 23:35:15 tom Exp $ */ #include "defs.h" #define StaticOrR (rflag ? "" : "static ") #define CountLine(fp) (!rflag || ((fp) == code_file)) +#if defined(YYBTYACC) +#define PER_STATE 3 +#else +#define PER_STATE 2 +#endif + static int nvectors; static int nentries; static Value_t **froms; @@ -23,7 +29,7 @@ static int maxtable; static Value_t *table; static Value_t *check; static int lowzero; -static int high; +static long high; static void putc_code(FILE * fp, int c) @@ -109,6 +115,9 @@ output_prefix(FILE * fp) define_prefixed(fp, "yylhs"); define_prefixed(fp, "yylen"); define_prefixed(fp, "yydefred"); +#if defined(YYBTYACC) + define_prefixed(fp, "yystos"); +#endif define_prefixed(fp, "yydgoto"); define_prefixed(fp, "yysindex"); define_prefixed(fp, "yyrindex"); @@ -188,12 +197,27 @@ end_table(void) output_line("};"); } +#if defined(YYBTYACC) +static void +output_YYINT_typedef(FILE * fp) +{ + /* generate the type used to index the various parser tables */ + if (CountLine(fp)) + ++outline; + fprintf(fp, "typedef %s YYINT;\n", CONCAT1("", YYINT)); +} +#endif + static void output_rule_data(void) { int i; int j; +#if defined(YYBTYACC) + output_YYINT_typedef(output_file); +#endif + start_int_table("lhs", symbol_value[start_symbol]); j = 10; @@ -253,27 +277,118 @@ output_yydefred(void) end_table(); } +#if defined(YYBTYACC) +static void +output_accessing_symbols(void) +{ + int i, j; + int *translate; + + translate = TMALLOC(int, nstates); + NO_SPACE(translate); + + for (i = 0; i < nstates; ++i) + { + int gsymb = accessing_symbol[i]; + + translate[i] = symbol_pval[gsymb]; + } + + /* yystos[] may be unused, depending on compile-time defines */ + start_int_table("stos", translate[0]); + + j = 10; + for (i = 1; i < nstates; ++i) + { + if (j < 10) + ++j; + else + { + output_newline(); + j = 1; + } + + output_int(translate[i]); + } + + end_table(); + FREE(translate); +} + +static Value_t +find_conflict_base(Value_t cbase) +{ + Value_t i, j; + + for (i = 0; i < cbase; i++) + { + for (j = 0; j + cbase < nconflicts; j++) + { + if (conflicts[i + j] != conflicts[cbase + j]) + break; + } + if (j + cbase >= nconflicts) + return i; + } + return cbase; +} +#endif + static void token_actions(void) { int i, j; Value_t shiftcount, reducecount; +#if defined(YYBTYACC) + Value_t conflictcount, csym, cbase; +#endif int max, min; Value_t *actionrow, *r, *s; action *p; - actionrow = NEW2(2 * ntokens, Value_t); + actionrow = NEW2(PER_STATE * ntokens, Value_t); for (i = 0; i < nstates; ++i) { if (parser[i]) { - for (j = 0; j < 2 * ntokens; ++j) + for (j = 0; j < PER_STATE * ntokens; ++j) actionrow[j] = 0; shiftcount = 0; reducecount = 0; +#if defined(YYBTYACC) + if (backtrack) + { + conflictcount = 0; + csym = -1; + cbase = nconflicts; + } +#endif for (p = parser[i]; p; p = p->next) { +#if defined(YYBTYACC) + if (backtrack) + { + if (csym != -1 && csym != p->symbol) + { + conflictcount++; + conflicts[nconflicts++] = -1; + j = find_conflict_base(cbase); + actionrow[csym + 2 * ntokens] = (Value_t) (j + 1); + if (j == cbase) + { + cbase = nconflicts; + } + else + { + if (conflicts[cbase] == -1) + cbase++; + nconflicts = cbase; + } + csym = -1; + } + } +#endif if (p->suppressed == 0) { if (p->action_code == SHIFT) @@ -287,12 +402,60 @@ token_actions(void) actionrow[p->symbol + ntokens] = p->number; } } +#if defined(YYBTYACC) + else if (backtrack && p->suppressed == 1) + { + csym = p->symbol; + if (p->action_code == SHIFT) + { + conflicts[nconflicts++] = p->number; + } + else if (p->action_code == REDUCE && p->number != defred[i]) + { + if (cbase == nconflicts) + { + if (cbase) + cbase--; + else + conflicts[nconflicts++] = -1; + } + conflicts[nconflicts++] = (Value_t) (p->number - 2); + } + } +#endif } +#if defined(YYBTYACC) + if (backtrack && csym != -1) + { + conflictcount++; + conflicts[nconflicts++] = -1; + j = find_conflict_base(cbase); + actionrow[csym + 2 * ntokens] = (Value_t) (j + 1); + if (j == cbase) + { + cbase = nconflicts; + } + else + { + if (conflicts[cbase] == -1) + cbase++; + nconflicts = cbase; + } + } +#endif tally[i] = shiftcount; tally[nstates + i] = reducecount; +#if defined(YYBTYACC) + if (backtrack) + tally[2 * nstates + i] = conflictcount; +#endif width[i] = 0; width[nstates + i] = 0; +#if defined(YYBTYACC) + if (backtrack) + width[2 * nstates + i] = 0; +#endif if (shiftcount > 0) { froms[i] = r = NEW2(shiftcount, Value_t); @@ -333,6 +496,28 @@ token_actions(void) } width[nstates + i] = (Value_t) (max - min + 1); } +#if defined(YYBTYACC) + if (backtrack && conflictcount > 0) + { + froms[2 * nstates + i] = r = NEW2(conflictcount, Value_t); + tos[2 * nstates + i] = s = NEW2(conflictcount, Value_t); + min = MAXYYINT; + max = 0; + for (j = 0; j < ntokens; ++j) + { + if (actionrow[2 * ntokens + j]) + { + if (min > symbol_value[j]) + min = symbol_value[j]; + if (max < symbol_value[j]) + max = symbol_value[j]; + *r++ = symbol_value[j]; + *s++ = (Value_t) (actionrow[2 * ntokens + j] - 1); + } + } + width[2 * nstates + i] = (Value_t) (max - min + 1); + } +#endif } } FREE(actionrow); @@ -397,7 +582,7 @@ save_column(int symbol, int default_state) if (count == 0) return; - symno = symbol_value[symbol] + 2 * nstates; + symno = symbol_value[symbol] + PER_STATE * nstates; froms[symno] = sp1 = sp = NEW2(count, Value_t); tos[symno] = sp2 = NEW2(count, Value_t); @@ -496,6 +681,11 @@ sort_actions(void) /* Matching_vector is poorly designed. The test could easily be made */ /* faster. Also, it depends on the vectors being in a specific */ /* order. */ +#if defined(YYBTYACC) +/* */ +/* Not really any point in checking for matching conflicts -- it is */ +/* extremely unlikely to occur, and conflicts are (hopefully) rare. */ +#endif static int matching_vector(int vector) @@ -705,10 +895,32 @@ output_base(void) end_table(); - start_int_table("gindex", base[2 * nstates]); +#if defined(YYBTYACC) + output_line("#if YYBTYACC"); + start_int_table("cindex", base[2 * nstates]); j = 10; - for (i = 2 * nstates + 1; i < nvectors - 1; i++) + for (i = 2 * nstates + 1; i < 3 * nstates; i++) + { + if (j >= 10) + { + output_newline(); + j = 1; + } + else + ++j; + + output_int(base[i]); + } + + end_table(); + output_line("#endif"); +#endif + + start_int_table("gindex", base[PER_STATE * nstates]); + + j = 10; + for (i = PER_STATE * nstates + 1; i < nvectors - 1; i++) { if (j >= 10) { @@ -731,8 +943,17 @@ output_table(void) int i; int j; +#if defined(YYBTYACC) + if (high >= MAXYYINT) + { + fprintf(stderr, "YYTABLESIZE: %ld\n", high); + fprintf(stderr, "Table is longer than %d elements.\n", MAXYYINT); + exit(1); + } +#endif + ++outline; - fprintf(code_file, "#define YYTABLESIZE %d\n", high); + fprintf(code_file, "#define YYTABLESIZE %ld\n", high); start_int_table("table", table[0]); j = 10; @@ -812,13 +1033,18 @@ output_ctable(void) static void output_actions(void) { - nvectors = 2 * nstates + nvars; + nvectors = PER_STATE * nstates + nvars; froms = NEW2(nvectors, Value_t *); tos = NEW2(nvectors, Value_t *); tally = NEW2(nvectors, Value_t); width = NEW2(nvectors, Value_t); +#if defined(YYBTYACC) + if (backtrack && (SRtotal + RRtotal) != 0) + conflicts = NEW2(4 * (SRtotal + RRtotal), Value_t); +#endif + token_actions(); FREE(lookaheads); FREE(LA); @@ -936,7 +1162,7 @@ output_defines(FILE * fp) { rewind(union_file); while ((c = getc(union_file)) != EOF) - putc(c, fp); + putc_code(fp, c); } fprintf(fp, "extern YYSTYPE %slval;\n", symbol_prefix); } @@ -1204,6 +1430,27 @@ output_debug(void) output_line("#endif"); } +#if defined(YYBTYACC) +static void +output_backtracking_parser(FILE * fp) +{ + putl_code(fp, "#undef YYBTYACC\n"); +#if defined(YYBTYACC) + if (backtrack) + { + putl_code(fp, "#define YYBTYACC 1\n"); + putl_code(fp, + "#define YYDEBUGSTR (yytrial ? YYPREFIX \"debug(trial)\" : YYPREFIX \"debug\")\n"); + } + else +#endif + { + putl_code(fp, "#define YYBTYACC 0\n"); + putl_code(fp, "#define YYDEBUGSTR YYPREFIX \"debug\"\n"); + } +} +#endif + static void output_pure_parser(FILE * fp) { @@ -1440,6 +1687,7 @@ output_lex_decl(FILE * fp) else if (lex_param) { param *p; + puts_code(fp, "# define YYLEX_DECL() yylex("); for (p = lex_param; p; p = p->next) fprintf(fp, "%s %s%s%s", p->type, p->name, p->type2, @@ -1639,22 +1887,18 @@ output_yyerror_call(const char *msg) static void output_externs(FILE * fp, const char *const section[]) { - int c; int i; const char *s; for (i = 0; (s = section[i]) != 0; ++i) { - if (*s && *s != '#') + /* prefix non-blank lines that don't start with + C pre-processor directives with 'extern ' */ + if (*s && (*s != '#')) fputs("extern\t", fp); - while ((c = *s) != 0) - { - putc(c, fp); - ++s; - } if (fp == code_file) ++outline; - putc('\n', fp); + fprintf(fp, "%s\n", s); } } @@ -1667,8 +1911,15 @@ output(void) free_shifts(); free_reductions(); +#if defined(YYBTYACC) + output_backtracking_parser(output_file); + if (rflag) + output_backtracking_parser(code_file); +#endif + if (iflag) { + write_code_lineno(code_file); ++outline; fprintf(code_file, "#include \"%s\"\n", externs_file_name); fp = externs_file; @@ -1691,7 +1942,15 @@ output(void) if (destructor) output_yydestruct_decl(fp); #endif +#if defined(YYBTYACC) + if (iflag || !rflag) + { + write_section(fp, xdecls); + write_code_lineno(fp); + } +#else write_section(fp, xdecls); +#endif if (iflag) { @@ -1725,6 +1984,9 @@ output(void) output_rule_data(); output_yydefred(); +#if defined(YYBTYACC) + output_accessing_symbols(); +#endif output_actions(); free_parser(); output_debug(); @@ -1732,6 +1994,9 @@ output(void) { output_prefix(code_file); write_section(code_file, xdecls); +#if defined(YYBTYACC) + output_YYINT_typedef(code_file); +#endif write_section(code_file, tables); } write_section(code_file, global_vars); diff --git a/reader.c b/reader.c index f6de643..677c59a 100644 --- a/reader.c +++ b/reader.c @@ -1,4 +1,4 @@ -/* $Id: reader.c,v 1.40 2014/04/03 00:38:18 tom Exp $ */ +/* $Id: reader.c,v 1.41 2014/04/04 01:13:50 tom Exp $ */ #include "defs.h" @@ -11,8 +11,20 @@ #define L_CURL '{' #define R_CURL '}' +#define L_PAREN '(' +#define R_PAREN ')' +#define L_BRAC '[' +#define R_BRAC ']' + +/* the maximum number of arguments (inherited attributes) to a non-terminal */ +/* this is a hard limit, but seems more than adequate */ +#define MAXARGS 20 static void start_rule(bucket *bp, int s_lineno); +#if defined(YYBTYACC) +static void copy_destructor(void); +static char *process_destructor_XX(char *code, char *tag); +#endif static char *cache; static int cinc, cache_size; @@ -390,11 +402,93 @@ copy_ident(void) } } +static char * +copy_string(int quote) +{ + struct mstring *temp = msnew(); + int c; + int s_lineno = lineno; + char *s_line = dup_line(); + char *s_cptr = s_line + (cptr - line - 1); + + for (;;) + { + c = *cptr++; + mputc(temp, c); + if (c == quote) + { + FREE(s_line); + return msdone(temp); + } + if (c == '\n') + unterminated_string(s_lineno, s_line, s_cptr); + if (c == '\\') + { + c = *cptr++; + mputc(temp, c); + if (c == '\n') + { + get_line(); + if (line == 0) + unterminated_string(s_lineno, s_line, s_cptr); + } + } + } +} + +static char * +copy_comment(void) +{ + struct mstring *temp = msnew(); + int c; + + c = *cptr; + if (c == '/') + { + mputc(temp, '*'); + while ((c = *++cptr) != '\n') + { + mputc(temp, c); + if (c == '*' && cptr[1] == '/') + mputc(temp, ' '); + } + mputc(temp, '*'); + mputc(temp, '/'); + } + else if (c == '*') + { + int c_lineno = lineno; + char *c_line = dup_line(); + char *c_cptr = c_line + (cptr - line - 1); + + mputc(temp, c); + ++cptr; + for (;;) + { + c = *cptr++; + mputc(temp, c); + if (c == '*' && *cptr == '/') + { + mputc(temp, '/'); + ++cptr; + FREE(c_line); + return msdone(temp); + } + if (c == '\n') + { + get_line(); + if (line == 0) + unterminated_comment(c_lineno, c_line, c_cptr); + } + } + } + return msdone(temp); +} + static void copy_text(void) { int c; - int quote; FILE *f = text_file; int need_newline = 0; int t_lineno = lineno; @@ -415,7 +509,6 @@ copy_text(void) switch (c) { case '\n': - next_line: putc('\n', f); need_newline = 0; get_line(); @@ -425,82 +518,21 @@ copy_text(void) case '\'': case '"': + putc(c, f); { - int s_lineno = lineno; - char *s_line = dup_line(); - char *s_cptr = s_line + (cptr - line - 1); - - quote = c; - putc(c, f); - for (;;) - { - c = *cptr++; - putc(c, f); - if (c == quote) - { - need_newline = 1; - FREE(s_line); - goto loop; - } - if (c == '\n') - unterminated_string(s_lineno, s_line, s_cptr); - if (c == '\\') - { - c = *cptr++; - putc(c, f); - if (c == '\n') - { - get_line(); - if (line == 0) - unterminated_string(s_lineno, s_line, s_cptr); - } - } - } + char *s = copy_string(c); + fputs(s, f); + free(s); } + need_newline = 1; + goto loop; case '/': putc(c, f); - need_newline = 1; - c = *cptr; - if (c == '/') { - putc('*', f); - while ((c = *++cptr) != '\n') - { - if (c == '*' && cptr[1] == '/') - fprintf(f, "* "); - else - putc(c, f); - } - fprintf(f, "*/"); - goto next_line; - } - if (c == '*') - { - int c_lineno = lineno; - char *c_line = dup_line(); - char *c_cptr = c_line + (cptr - line - 1); - - putc('*', f); - ++cptr; - for (;;) - { - c = *cptr++; - putc(c, f); - if (c == '*' && *cptr == '/') - { - putc('/', f); - ++cptr; - FREE(c_line); - goto loop; - } - if (c == '\n') - { - get_line(); - if (line == 0) - unterminated_comment(c_lineno, c_line, c_cptr); - } - } + char *s = copy_comment(); + fputs(s, f); + free(s); } need_newline = 1; goto loop; @@ -544,7 +576,6 @@ static void copy_union(void) { int c; - int quote; int depth; int u_lineno = lineno; char *u_line = dup_line(); @@ -572,7 +603,6 @@ copy_union(void) switch (c) { case '\n': - next_line: get_line(); if (line == 0) unterminated_union(u_lineno, u_line, u_cptr); @@ -595,84 +625,20 @@ copy_union(void) case '\'': case '"': { - int s_lineno = lineno; - char *s_line = dup_line(); - char *s_cptr = s_line + (cptr - line - 1); - - quote = c; - for (;;) - { - c = *cptr++; - putc_both(c); - if (c == quote) - { - FREE(s_line); - goto loop; - } - if (c == '\n') - unterminated_string(s_lineno, s_line, s_cptr); - if (c == '\\') - { - c = *cptr++; - putc_both(c); - if (c == '\n') - { - get_line(); - if (line == 0) - unterminated_string(s_lineno, s_line, s_cptr); - } - } - } - } - - case '/': - c = *cptr; - if (c == '/') - { - putc_both('*'); - while ((c = *++cptr) != '\n') - { - if (c == '*' && cptr[1] == '/') - { - puts_both("* "); - } - else - { - putc_both(c); - } - } - puts_both("*/\n"); - goto next_line; - } - if (c == '*') - { - int c_lineno = lineno; - char *c_line = dup_line(); - char *c_cptr = c_line + (cptr - line - 1); - - putc_both('*'); - ++cptr; - for (;;) - { - c = *cptr++; - putc_both(c); - if (c == '*' && *cptr == '/') - { - putc_both('/'); - ++cptr; - FREE(c_line); - goto loop; - } - if (c == '\n') - { - get_line(); - if (line == 0) - unterminated_comment(c_lineno, c_line, c_cptr); - } - } + char *s = copy_string(c); + puts_both(s); + free(s); } goto loop; + case '/': + { + char *s = copy_comment(); + puts_both(s); + free(s); + } + goto loop; + default: goto loop; } @@ -693,20 +659,20 @@ copy_param(int k) c = nextc(); if (c == EOF) unexpected_EOF(); - if (c != '{') + if (c != L_CURL) goto out; cptr++; c = nextc(); if (c == EOF) unexpected_EOF(); - if (c == '}') + if (c == R_CURL) goto out; buf = TMALLOC(char, linesize); NO_SPACE(buf); - for (i = 0; (c = *cptr++) != '}'; i++) + for (i = 0; (c = *cptr++) != R_CURL; i++) { if (c == '\0') missing_brace(); @@ -1093,6 +1059,18 @@ get_tag(void) return (s); } +#if defined(YYBTYACC) +static char * +scan_id(void) +{ + char *b = cptr; + + while (isalnum(*cptr) || *cptr == '_' || *cptr == '$') + cptr++; + return cache_tag(b, (size_t) (cptr - b)); +} +#endif + static void declare_tokens(int assoc) { @@ -1209,6 +1187,44 @@ declare_expect(int assoc) } } +#if defined(YYBTYACC) +static void +declare_argtypes(bucket *bp) +{ + char *tags[MAXARGS]; + int args = 0, c; + + if (bp->args >= 0) + retyped_warning(bp->name); + cptr++; /* skip open paren */ + for (;;) + { + c = nextc(); + if (c == EOF) + unexpected_EOF(); + if (c != '<') + syntax_error(lineno, line, cptr); + tags[args++] = get_tag(); + c = nextc(); + if (c == R_PAREN) + break; + if (c == EOF) + unexpected_EOF(); + } + cptr++; /* skip close paren */ + bp->args = args; + bp->argnames = TMALLOC(char *, args); + NO_SPACE(bp->argnames); + bp->argtags = TMALLOC(char *, args); + NO_SPACE(bp->argtags); + while (--args >= 0) + { + bp->argtags[args] = tags[args]; + bp->argnames[args] = NULL; + } +} +#endif + static void declare_types(void) { @@ -1227,9 +1243,22 @@ declare_types(void) { c = nextc(); if (isalpha(c) || c == '_' || c == '.' || c == '$') + { bp = get_name(); +#if defined(YYBTYACC) + if (nextc() == L_PAREN) + declare_argtypes(bp); + else + bp->args = 0; +#endif + } else if (c == '\'' || c == '"') + { bp = get_literal(); +#if defined(YYBTYACC) + bp->args = 0; +#endif + } else return; @@ -1324,6 +1353,17 @@ read_declarations(void) token_table = 1; break; +#if defined(YYBTYACC) + case LOCATIONS: + locations = 1; + break; + + case DESTRUCTOR: + destructor = 1; + copy_destructor(); + break; +#endif + case POSIX_YACC: /* noop for bison compatibility. byacc is already designed to be posix * yacc compatible. */ @@ -1394,6 +1434,331 @@ expand_rules(void) NO_SPACE(rassoc); } +/* set immediately prior to where copy_args() could be called, and incremented by + the various routines that will rescan the argument list as appropriate */ +static int rescan_lineno; +#if defined(YYBTYACC) + +static char * +copy_args(int *alen) +{ + struct mstring *s = msnew(); + int depth = 0, len = 1; + char c, quote = 0; + int a_lineno = lineno; + char *a_line = dup_line(); + char *a_cptr = a_line + (cptr - line - 1); + + while ((c = *cptr++) != R_PAREN || depth || quote) + { + if (c == ',' && !quote && !depth) + { + len++; + mputc(s, 0); + continue; + } + mputc(s, c); + if (c == '\n') + { + get_line(); + if (!line) + { + if (quote) + unterminated_string(a_lineno, a_line, a_cptr); + else + unterminated_arglist(a_lineno, a_line, a_cptr); + } + } + else if (quote) + { + if (c == quote) + quote = 0; + else if (c == '\\') + { + if (*cptr != '\n') + mputc(s, *cptr++); + } + } + else + { + if (c == L_PAREN) + depth++; + else if (c == R_PAREN) + depth--; + else if (c == '\"' || c == '\'') + quote = c; + } + } + if (alen) + *alen = len; + FREE(a_line); + return msdone(s); +} + +static char * +parse_id(char *p, char **save) +{ + char *b; + + while (isspace(*p)) + if (*p++ == '\n') + rescan_lineno++; + if (!isalpha(*p) && *p != '_') + return NULL; + b = p; + while (isalnum(*p) || *p == '_' || *p == '$') + p++; + if (save) + { + *save = cache_tag(b, (size_t) (p - b)); + } + return p; +} + +static char * +parse_int(char *p, int *save) +{ + int neg = 0, val = 0; + + while (isspace(*p)) + if (*p++ == '\n') + rescan_lineno++; + if (*p == '-') + { + neg = 1; + p++; + } + if (!isdigit(*p)) + return NULL; + while (isdigit(*p)) + val = val * 10 + *p++ - '0'; + if (neg) + val = -val; + if (save) + *save = val; + return p; +} + +static void +parse_arginfo(bucket *a, char *args, int argslen) +{ + char *p = args, *tmp; + int i, redec = 0; + + if (a->args > 0) + { + if (a->args != argslen) + arg_number_disagree_warning(rescan_lineno, a->name); + redec = 1; + } + else + { + if ((a->args = argslen) == 0) + return; + a->argnames = TMALLOC(char *, argslen); + NO_SPACE(a->argnames); + a->argtags = TMALLOC(char *, argslen); + NO_SPACE(a->argtags); + } + if (!args) + return; + for (i = 0; i < argslen; i++) + { + while (isspace(*p)) + if (*p++ == '\n') + rescan_lineno++; + if (*p++ != '$') + bad_formals(); + while (isspace(*p)) + if (*p++ == '\n') + rescan_lineno++; + if (*p == '<') + { + havetags = 1; + if (!(p = parse_id(p + 1, &tmp))) + bad_formals(); + while (isspace(*p)) + if (*p++ == '\n') + rescan_lineno++; + if (*p++ != '>') + bad_formals(); + if (redec) + { + if (a->argtags[i] != tmp) + arg_type_disagree_warning(rescan_lineno, i + 1, a->name); + } + else + a->argtags[i] = tmp; + } + else if (!redec) + a->argtags[i] = NULL; + if (!(p = parse_id(p, &a->argnames[i]))) + bad_formals(); + while (isspace(*p)) + if (*p++ == '\n') + rescan_lineno++; + if (*p++) + bad_formals(); + } + free(args); +} + +static char * +compile_arg(char **theptr, char *yyvaltag) +{ + char *p = *theptr; + struct mstring *c = msnew(); + int i, j, n; + Value_t *offsets = NULL, maxoffset; + bucket **rhs; + + maxoffset = 0; + n = 0; + for (i = nitems - 1; pitem[i]; --i) + { + n++; + if (pitem[i]->class != ARGUMENT) + maxoffset++; + } + if (maxoffset > 0) + { + offsets = TMALLOC(Value_t, maxoffset + 1); + NO_SPACE(offsets); + } + for (j = 0, i++; i < nitems; i++) + if (pitem[i]->class != ARGUMENT) + offsets[++j] = (Value_t) (i - nitems + 1); + rhs = pitem + nitems - 1; + + if (yyvaltag) + msprintf(c, "yyval.%s = ", yyvaltag); + else + msprintf(c, "yyval = "); + while (*p) + { + if (*p == '$') + { + char *tag = NULL; + if (*++p == '<') + if (!(p = parse_id(++p, &tag)) || *p++ != '>') + illegal_tag(rescan_lineno, NULL, NULL); + if (isdigit(*p) || *p == '-') + { + int val; + if (!(p = parse_int(p, &val))) + dollar_error(rescan_lineno, NULL, NULL); + if (val <= 0) + i = val - n; + else if (val > maxoffset) + { + dollar_warning(rescan_lineno, val); + i = val - maxoffset; + } + else + { + i = offsets[val]; + if (!tag && !(tag = rhs[i]->tag) && havetags) + untyped_rhs(val, rhs[i]->name); + } + msprintf(c, "yystack.l_mark[%d]", i); + if (tag) + msprintf(c, ".%s", tag); + else if (havetags) + unknown_rhs(val); + } + else if (isalpha(*p) || *p == '_') + { + char *arg; + if (!(p = parse_id(p, &arg))) + dollar_error(rescan_lineno, NULL, NULL); + for (i = plhs[nrules]->args - 1; i >= 0; i--) + if (arg == plhs[nrules]->argnames[i]) + break; + if (i < 0) + unknown_arg_warning(rescan_lineno, "$", arg, NULL, NULL); + else if (!tag) + tag = plhs[nrules]->argtags[i]; + msprintf(c, "yystack.l_mark[%d]", i - plhs[nrules]->args + 1 + - n); + if (tag) + msprintf(c, ".%s", tag); + else if (havetags) + untyped_arg_warning(rescan_lineno, "$", arg); + } + else + dollar_error(rescan_lineno, NULL, NULL); + } + else if (*p == '@') + { + at_error(rescan_lineno, NULL, NULL); + /*NOTREACHED */ + } + else + { + if (*p == '\n') + rescan_lineno++; + mputc(c, *p++); + } + } + *theptr = p; + if (maxoffset > 0) + FREE(offsets); + return msdone(c); +} + +#define ARG_CACHE_SIZE 1024 +static struct arg_cache +{ + struct arg_cache *next; + char *code; + int rule; +} + *arg_cache[ARG_CACHE_SIZE]; + +static int +lookup_arg_cache(char *code) +{ + struct arg_cache *entry; + + entry = arg_cache[strnshash(code) % ARG_CACHE_SIZE]; + while (entry) + { + if (!strnscmp(entry->code, code)) + return entry->rule; + entry = entry->next; + } + return -1; +} + +static void +insert_arg_cache(char *code, int rule) +{ + struct arg_cache *entry = NEW(struct arg_cache); + int i; + + NO_SPACE(entry); + i = strnshash(code) % ARG_CACHE_SIZE; + entry->code = code; + entry->rule = rule; + entry->next = arg_cache[i]; + arg_cache[i] = entry; +} + +static void +clean_arg_cache(void) +{ + struct arg_cache *e, *t; + int i; + + for (i = 0; i < ARG_CACHE_SIZE; i++) + { + for (e = arg_cache[i]; (t = e); e = e->next, FREE(t)) + free(e->code); + arg_cache[i] = NULL; + } +} +#endif + static void advance_to_start(void) { @@ -1401,6 +1766,10 @@ advance_to_start(void) bucket *bp; char *s_cptr; int s_lineno; +#if defined(YYBTYACC) + char *args = NULL; + int argslen = 0; +#endif for (;;) { @@ -1441,9 +1810,22 @@ advance_to_start(void) c = nextc(); if (c == EOF) unexpected_EOF(); + rescan_lineno = lineno; /* line# for possible inherited args rescan */ +#if defined(YYBTYACC) + if (c == L_PAREN) + { + ++cptr; + args = copy_args(&argslen); + NO_SPACE(args); + c = nextc(); + } +#endif if (c != ':') syntax_error(lineno, line, cptr); start_rule(bp, s_lineno); +#if defined(YYBTYACC) + parse_arginfo(bp, args, argslen); +#endif ++cptr; } @@ -1519,12 +1901,49 @@ insert_empty_rule(void) rassoc[nrules - 1] = TOKEN; } +#if defined(YYBTYACC) +static char * +insert_arg_rule(char *arg, char *tag) +{ + int line_number = rescan_lineno; + char *code = compile_arg(&arg, tag); + int rule = lookup_arg_cache(code); + FILE *f = action_file; + + if (rule < 0) + { + rule = nrules; + insert_arg_cache(code, rule); + fprintf(f, "case %d:\n", rule - 2); + if (!lflag) + fprintf(f, line_format, line_number, input_file_name); + fprintf(f, "%s;\n", code); + fprintf(f, "break;\n"); + insert_empty_rule(); + plhs[rule]->tag = tag; + plhs[rule]->class = ARGUMENT; + } + else + { + if (++nitems > maxitems) + expand_items(); + pitem[nitems - 1] = plhs[rule]; + free(code); + } + return arg + 1; +} +#endif + static void add_symbol(void) { int c; bucket *bp; int s_lineno = lineno; +#if defined(YYBTYACC) + char *args = NULL; + int argslen = 0; +#endif c = *cptr; if (c == '\'' || c == '"') @@ -1533,6 +1952,16 @@ add_symbol(void) bp = get_name(); c = nextc(); + rescan_lineno = lineno; /* line# for possible inherited args rescan */ +#if defined(YYBTYACC) + if (c == L_PAREN) + { + ++cptr; + args = copy_args(&argslen); + NO_SPACE(args); + c = nextc(); + } +#endif if (c == ':') { end_rule(); @@ -1545,6 +1974,30 @@ add_symbol(void) insert_empty_rule(); last_was_action = 0; +#if defined(YYBTYACC) + if (bp->args < 0) + bp->args = argslen; + if (argslen == 0 && bp->args > 0 && pitem[nitems - 1] == NULL) + { + int i; + if (plhs[nrules]->args != bp->args) + wrong_number_args_warning("default ", bp->name); + for (i = bp->args - 1; i >= 0; i--) + if (plhs[nrules]->argtags[i] != bp->argtags[i]) + wrong_type_for_arg_warning(i + 1, bp->name); + } + else if (bp->args != argslen) + wrong_number_args_warning("", bp->name); + if (bp->args > 0 && argslen > 0) + { + char *ap; + int i; + for (ap = args, i = 0; i < argslen; i++) + ap = insert_arg_rule(ap, bp->argtags[i]); + free(args); + } +#endif /* defined(YYBTYACC) */ + if (++nitems > maxitems) expand_items(); pitem[nitems - 1] = bp; @@ -1564,7 +2017,6 @@ copy_action(void) int c; int i, n; int depth; - int quote; char *tag; FILE *f = action_file; int a_lineno = lineno; @@ -1576,6 +2028,15 @@ copy_action(void) last_was_action = 1; fprintf(f, "case %d:\n", nrules - 2); +#if defined(YYBTYACC) + if (backtrack) + { + if (*cptr != L_BRAC) + fprintf(f, " if (!yytrial)\n"); + else + trialaction = 1; + } +#endif if (!lflag) fprintf(f, line_format, lineno, input_file_name); if (*cptr == '=') @@ -1630,6 +2091,21 @@ copy_action(void) FREE(d_line); goto loop; } +#if defined(YYBTYACC) + else if (isalpha(c) || c == '_') + { + char *arg = scan_id(); + for (i = plhs[nrules]->args - 1; i >= 0; i--) + if (arg == plhs[nrules]->argnames[i]) + break; + if (i < 0) + unknown_arg_warning(d_lineno, "$", arg, d_line, d_cptr); + fprintf(f, "yystack.l_mark[%d].%s", i - plhs[nrules]->args + + 1 - n, tag); + FREE(d_line); + goto loop; + } +#endif else dollar_error(d_lineno, d_line, d_cptr); } @@ -1677,7 +2153,61 @@ copy_action(void) fprintf(f, "yystack.l_mark[%d]", -i - n); goto loop; } +#if defined(YYBTYACC) + else if (isalpha(cptr[1]) || cptr[1] == '_') + { + char *arg; + ++cptr; + arg = scan_id(); + for (i = plhs[nrules]->args - 1; i >= 0; i--) + if (arg == plhs[nrules]->argnames[i]) + break; + if (i < 0) + unknown_arg_warning(lineno, "$", arg, line, cptr); + tag = (i < 0 ? NULL : plhs[nrules]->argtags[i]); + fprintf(f, "yystack.l_mark[%d]", i - plhs[nrules]->args + 1 - n); + if (tag) + fprintf(f, ".%s", tag); + else if (havetags) + untyped_arg_warning(lineno, "$", arg); + goto loop; + } +#endif } +#if defined(YYBTYACC) + if (c == '@') + { + if (!locations) + { + int l_lineno = lineno; + char *l_line = dup_line(); + char *l_cptr = l_line + (cptr - line); + syntax_error(l_lineno, l_line, l_cptr); + /*NOTREACHED */ + } + if (cptr[1] == '$') + { + fprintf(f, "yyloc"); + cptr += 2; + goto loop; + } + else if (isdigit(UCH(cptr[1]))) + { + ++cptr; + i = get_number(); + if (i == 0) + fprintf(f, "yystack.p_mark[%d]", -n); + else if (i > maxoffset) + { + at_warning(lineno, i); + fprintf(f, "yystack.p_mark[%d]", i - maxoffset); + } + else + fprintf(f, "yystack.p_mark[%d]", offsets[i]); + goto loop; + } + } +#endif if (isalpha(c) || c == '_' || c == '$') { do @@ -1688,12 +2218,45 @@ copy_action(void) while (isalnum(c) || c == '_' || c == '$'); goto loop; } - putc(c, f); ++cptr; +#if defined(YYBTYACC) + if (backtrack) + { + if (trialaction && c == L_BRAC && depth == 0) + { + ++depth; + putc(L_CURL, f); + goto loop; + } + if (trialaction && c == R_BRAC && depth == 1) + { + --depth; + putc(R_CURL, f); + c = nextc(); + if (c == L_BRAC && !haveyyval) + { + goto loop; + } + if (c == L_CURL && !haveyyval) + { + fprintf(f, " if (!yytrial)\n"); + if (!lflag) + fprintf(f, line_format, lineno, input_file_name); + trialaction = 0; + goto loop; + } + fprintf(f, "\nbreak;\n"); + FREE(a_line); + if (maxoffset > 0) + FREE(offsets); + return; + } + } +#endif + putc(c, f); switch (c) { case '\n': - next_line: get_line(); if (line) goto loop; @@ -1706,6 +2269,18 @@ copy_action(void) free(a_line); return; +#if defined(YYBTYACC) + case L_BRAC: + if (backtrack) + ++depth; + goto loop; + + case R_BRAC: + if (backtrack) + --depth; + goto loop; +#endif + case L_CURL: ++depth; goto loop; @@ -1713,6 +2288,24 @@ copy_action(void) case R_CURL: if (--depth > 0) goto loop; +#if defined(YYBTYACC) + if (backtrack) + { + c = nextc(); + if (c == L_BRAC && !haveyyval) + { + trialaction = 1; + goto loop; + } + if (c == L_CURL && !haveyyval) + { + fprintf(f, " if (!yytrial)\n"); + if (!lflag) + fprintf(f, line_format, lineno, input_file_name); + goto loop; + } + } +#endif fprintf(f, "\nbreak;\n"); free(a_line); return; @@ -1720,76 +2313,298 @@ copy_action(void) case '\'': case '"': { - int s_lineno = lineno; - char *s_line = dup_line(); - char *s_cptr = s_line + (cptr - line - 1); + char *s = copy_string(c); + fputs(s, f); + free(s); + } + goto loop; - quote = c; - for (;;) + case '/': + { + char *s = copy_comment(); + fputs(s, f); + free(s); + } + goto loop; + + default: + goto loop; + } +} + +#if defined(YYBTYACC) +static void +copy_destructor(void) +{ + int c; + int depth; + char *tag; + bucket *bp; + struct mstring *destructor_text = msnew(); + char *code_text; + int a_lineno; + char *a_line; + char *a_cptr; + + if (!lflag) + msprintf(destructor_text, line_format, lineno, input_file_name); + + cptr = after_blanks(cptr); + if (*cptr == L_CURL) + /* avoid putting curly-braces in first column, to ease editing */ + mputc(destructor_text, '\t'); + else + syntax_error(lineno, line, cptr); + + a_lineno = lineno; + a_line = dup_line(); + a_cptr = a_line + (cptr - line); + + depth = 0; + loop: + c = *cptr; + if (c == '$') + { + if (cptr[1] == '<') + { + int d_lineno = lineno; + char *d_line = dup_line(); + char *d_cptr = d_line + (cptr - line); + + ++cptr; + tag = get_tag(); + c = *cptr; + if (c == '$') { - c = *cptr++; - putc(c, f); - if (c == quote) + msprintf(destructor_text, "(*val).%s", tag); + ++cptr; + FREE(d_line); + goto loop; + } + else + dollar_error(d_lineno, d_line, d_cptr); + } + else if (cptr[1] == '$') + { + /* process '$$' later; replacement is context dependent */ + msprintf(destructor_text, "$$"); + cptr += 2; + goto loop; + } + } + if (c == '@' && cptr[1] == '$') + { + if (!locations) + { + int l_lineno = lineno; + char *l_line = dup_line(); + char *l_cptr = l_line + (cptr - line); + syntax_error(l_lineno, l_line, l_cptr); + /*NOTREACHED */ + } + msprintf(destructor_text, "(*loc)"); + cptr += 2; + goto loop; + } + if (isalpha(c) || c == '_' || c == '$') + { + do + { + mputc(destructor_text, c); + c = *++cptr; + } + while (isalnum(c) || c == '_' || c == '$'); + goto loop; + } + ++cptr; + mputc(destructor_text, c); + switch (c) + { + case '\n': + get_line(); + if (line) + goto loop; + unterminated_action(a_lineno, a_line, a_cptr); + + case L_CURL: + ++depth; + goto loop; + + case R_CURL: + if (--depth > 0) + goto loop; + goto process_symbols; + + case '\'': + case '"': + { + char *s = copy_string(c); + msprintf(destructor_text, "%s", s); + free(s); + } + goto loop; + + case '/': + { + char *s = copy_comment(); + msprintf(destructor_text, "%s", s); + free(s); + } + goto loop; + + default: + goto loop; + } + process_symbols: + code_text = msdone(destructor_text); + for (;;) + { + c = nextc(); + if (c == EOF) + unexpected_EOF(); + if (c == '<') + { + if (cptr[1] == '>') + { /* "no semantic type" default destructor */ + cptr += 2; + if ((bp = default_destructor[UNTYPED_DEFAULT]) == NULL) { - FREE(s_line); - goto loop; + bp = make_bucket("untyped default"); + bp->tag = (char *)"<>"; + default_destructor[UNTYPED_DEFAULT] = bp; } - if (c == '\n') - unterminated_string(s_lineno, s_line, s_cptr); - if (c == '\\') + if (bp->destructor != NULL) + destructor_redeclared_warning(a_lineno, a_line, a_cptr); + else + /* replace "$$" with "(*val)" in destructor code */ + bp->destructor = process_destructor_XX(code_text, NULL); + } + else if (cptr[1] == '*' && cptr[2] == '>') + { /* "no per-symbol or per-type" default destructor */ + cptr += 3; + if ((bp = default_destructor[TYPED_DEFAULT]) == NULL) { - c = *cptr++; - putc(c, f); - if (c == '\n') - { - get_line(); - if (line == 0) - unterminated_string(s_lineno, s_line, s_cptr); - } + bp = make_bucket("typed default"); + bp->tag = (char *)"<*>"; + default_destructor[TYPED_DEFAULT] = bp; } + if (bp->destructor != NULL) + destructor_redeclared_warning(a_lineno, a_line, a_cptr); + else + { + /* postpone re-processing destructor $$s until end of grammar spec */ + bp->destructor = TMALLOC(char, strlen(code_text) + 1); + NO_SPACE(bp->destructor); + strcpy(bp->destructor, code_text); + } + } + else + { /* "semantic type" default destructor */ + tag = get_tag(); + bp = lookup_type_destructor(tag); + if (bp->destructor != NULL) + destructor_redeclared_warning(a_lineno, a_line, a_cptr); + else + /* replace "$$" with "(*val).tag" in destructor code */ + bp->destructor = process_destructor_XX(code_text, tag); + } + } + else if (isalpha(c) || c == '_' || c == '.' || c == '$') + { /* "symbol" destructor */ + bp = get_name(); + if (bp->destructor != NULL) + destructor_redeclared_warning(a_lineno, a_line, a_cptr); + else + { + /* postpone re-processing destructor $$s until end of grammar spec */ + bp->destructor = TMALLOC(char, strlen(code_text) + 1); + NO_SPACE(bp->destructor); + strcpy(bp->destructor, code_text); + } + } + else + break; + } + free(a_line); + free(code_text); +} + +static char * +process_destructor_XX(char *code, char *tag) +{ + int c; + int quote; + int depth; + struct mstring *new_code = msnew(); + char *codeptr = code; + + depth = 0; + loop: /* step thru code */ + c = *codeptr; + if (c == '$' && codeptr[1] == '$') + { + codeptr += 2; + if (tag == NULL) + msprintf(new_code, "(*val)"); + else + msprintf(new_code, "(*val).%s", tag); + goto loop; + } + if (isalpha(c) || c == '_' || c == '$') + { + do + { + mputc(new_code, c); + c = *++codeptr; + } + while (isalnum(c) || c == '_' || c == '$'); + goto loop; + } + ++codeptr; + mputc(new_code, c); + switch (c) + { + case L_CURL: + ++depth; + goto loop; + + case R_CURL: + if (--depth > 0) + goto loop; + return msdone(new_code); + + case '\'': + case '"': + quote = c; + for (;;) + { + c = *codeptr++; + mputc(new_code, c); + if (c == quote) + goto loop; + if (c == '\\') + { + c = *codeptr++; + mputc(new_code, c); } } case '/': - c = *cptr; - if (c == '/') - { - putc('*', f); - while ((c = *++cptr) != '\n') - { - if (c == '*' && cptr[1] == '/') - fprintf(f, "* "); - else - putc(c, f); - } - fprintf(f, "*/\n"); - goto next_line; - } + c = *codeptr; if (c == '*') { - int c_lineno = lineno; - char *c_line = dup_line(); - char *c_cptr = c_line + (cptr - line - 1); - - putc('*', f); - ++cptr; + mputc(new_code, c); + ++codeptr; for (;;) { - c = *cptr++; - putc(c, f); - if (c == '*' && *cptr == '/') + c = *codeptr++; + mputc(new_code, c); + if (c == '*' && *codeptr == '/') { - putc('/', f); - ++cptr; - FREE(c_line); + mputc(new_code, '/'); + ++codeptr; goto loop; } - if (c == '\n') - { - get_line(); - if (line == 0) - unterminated_comment(c_lineno, c_line, c_cptr); - } } } goto loop; @@ -1798,6 +2613,7 @@ copy_action(void) goto loop; } } +#endif /* defined(YYBTYACC) */ static int mark_symbol(void) @@ -1879,6 +2695,10 @@ read_grammar(void) syntax_error(lineno, line, cptr); } end_rule(); +#if defined(YYBTYACC) + if (goal->args > 0) + start_requires_args(goal->name); +#endif } static void @@ -2006,6 +2826,17 @@ pack_symbols(void) symbol_assoc = TMALLOC(char, nsyms); NO_SPACE(symbol_assoc); +#if defined(YYBTYACC) + if (destructor) + { + symbol_destructor = TMALLOC(char *, nsyms); + NO_SPACE(symbol_destructor); + + symbol_type_tag = TMALLOC(char *, nsyms); + NO_SPACE(symbol_type_tag); + } +#endif + v = TMALLOC(bucket *, nsyms); NO_SPACE(v); @@ -2090,6 +2921,13 @@ pack_symbols(void) symbol_value[i] = v[i]->value; symbol_prec[i] = v[i]->prec; symbol_assoc[i] = v[i]->assoc; +#if defined(YYBTYACC) + if (destructor) + { + symbol_destructor[i] = v[i]->destructor; + symbol_type_tag[i] = v[i]->tag; + } +#endif } symbol_name[start_symbol] = name_pool; symbol_value[start_symbol] = -1; @@ -2102,6 +2940,13 @@ pack_symbols(void) symbol_value[k] = v[i]->value; symbol_prec[k] = v[i]->prec; symbol_assoc[k] = v[i]->assoc; +#if defined(YYBTYACC) + if (destructor) + { + symbol_destructor[k] = v[i]->destructor; + symbol_type_tag[k] = v[i]->tag; + } +#endif } if (gflag) @@ -2153,6 +2998,21 @@ pack_grammar(void) j = 4; for (i = 3; i < nrules; ++i) { +#if defined(YYBTYACC) + if (plhs[i]->args > 0) + { + if (plhs[i]->argnames) + { + FREE(plhs[i]->argnames); + plhs[i]->argnames = NULL; + } + if (plhs[i]->argtags) + { + FREE(plhs[i]->argtags); + plhs[i]->argtags = NULL; + } + } +#endif /* defined(YYBTYACC) */ rlhs[i] = plhs[i]->index; rrhs[i] = j; assoc = TOKEN; @@ -2220,6 +3080,85 @@ print_grammar(void) } } +#if defined(YYBTYACC) +static void +finalize_destructors(void) +{ + int i; + bucket *bp; + char *tag; + + for (i = 2; i < nsyms; ++i) + { + tag = symbol_type_tag[i]; + if (symbol_destructor[i] == NULL) + { + if (tag == NULL) + { /* use <> destructor, if there is one */ + if ((bp = default_destructor[UNTYPED_DEFAULT]) != NULL) + { + symbol_destructor[i] = TMALLOC(char, + strlen(bp->destructor) + 1); + NO_SPACE(symbol_destructor[i]); + strcpy(symbol_destructor[i], bp->destructor); + } + } + else + { /* use type destructor for this tag, if there is one */ + bp = lookup_type_destructor(tag); + if (bp->destructor != NULL) + { + symbol_destructor[i] = TMALLOC(char, + strlen(bp->destructor) + 1); + NO_SPACE(symbol_destructor[i]); + strcpy(symbol_destructor[i], bp->destructor); + } + else + { /* use <*> destructor, if there is one */ + if ((bp = default_destructor[TYPED_DEFAULT]) != NULL) + /* replace "$$" with "(*val).tag" in destructor code */ + symbol_destructor[i] = + process_destructor_XX(bp->destructor, tag); + } + } + } + else + { /* replace "$$" with "(*val)[.tag]" in destructor code */ + symbol_destructor[i] = + process_destructor_XX(symbol_destructor[i], tag); + } + } + /* 'symbol_type_tag[]' elements are freed by 'free_tags()' */ + free(symbol_type_tag); /* no longer needed */ + if ((bp = default_destructor[UNTYPED_DEFAULT]) != NULL) + { + FREE(bp->name); + /* 'bp->tag' is a static value, don't free */ + FREE(bp->destructor); + FREE(bp); + } + if ((bp = default_destructor[TYPED_DEFAULT]) != NULL) + { + FREE(bp->name); + /* 'bp->tag' is a static value, don't free */ + FREE(bp->destructor); + FREE(bp); + } + if ((bp = default_destructor[TYPE_SPECIFIED]) != NULL) + { + bucket *p; + for (; bp; bp = p) + { + p = bp->link; + FREE(bp->name); + /* 'bp->tag' freed by 'free_tags()' */ + FREE(bp->destructor); + FREE(bp); + } + } +} +#endif /* defined(YYBTYACC) */ + void reader(void) { @@ -2271,5 +3210,10 @@ reader_leaks(void) DO_FREE(symbol_prec); DO_FREE(symbol_assoc); DO_FREE(symbol_value); +#if defined(YYBTYACC) + DO_FREE(symbol_pval); + DO_FREE(symbol_destructor); + DO_FREE(symbol_type_tag); +#endif } #endif