From 5426d9e2a6b820e34809d639838b26643df9ab17 Mon Sep 17 00:00:00 2001 From: JSDurand Date: Tue, 8 Feb 2022 00:29:10 +0800 Subject: fix errors There are multiple subtle errors in the previous version, both in the codes and in the description of the BNF format. This version should fix some problems now. This version can successfully parse the grammar of its own grammar format, which is quite nice. See test/check_reader.c for parsing this format. --- src/Makefile.am | 4 +- src/bnf.bnf | 81 ++++--- src/bsr.c | 54 ++++- src/bsr.h | 2 - src/cnp.c | 131 ++++++++--- src/crf.c | 8 +- src/dfa.c | 11 +- src/grammar.c | 150 ++++++++++-- src/grammar.h | 9 +- src/test/check_reader.c | 594 ++++++++++++++++++++++++++++++++++++++++++++++-- src/tuple.c | 10 +- 11 files changed, 951 insertions(+), 103 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 77c2dfe..5375d8e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,8 +30,8 @@ check_list_SOURCES = test/check_list.c list.c check_grammar_SOURCES = test/check_grammar.c list.c ht.c grammar.c \ utf8.c str.c dfa.c -check_reader_SOURCES = test/check_reader.c list.c grammar.c reader.c \ -str.c utf8.c util.c ht.c dfa.c +check_reader_SOURCES = test/check_reader.c crf.c cnp.c grammar.c list.c \ +util.c ht.c utf8.c str.c dfa.c bsr.c tuple.c check_dfa_SOURCES = test/check_dfa.c dfa.c list.c str.c utf8.c diff --git a/src/bnf.bnf b/src/bnf.bnf index df8ef3c..0a339fc 100644 --- a/src/bnf.bnf +++ b/src/bnf.bnf @@ -1,27 +1,41 @@ # A grammar file for reading BNF notation +# FIXME: Too many errors! -[id]: a-zA-Z-_+*@ +[space]: %x20\t -[notbracket]: ^[] +[id]: a-zA-Z\-_+*@ + +[rule_name_char]: ^[]:%x20\n [notnewline]: ^\n\r +[class_range_char]: ^\n\r\^\\ + +[class_single_char]: ^\n\r\^\\\- + +[any]: + +[double_string_char]: ^"\n + +[single_string_char]: ^'\n + -- -BNF: predicate_section "--\n" rules_section +BNF: "#" notnewlines empty BNF +BNF: predicate_section "--\n" empty rules_section BNF: rules_section BNF: -spaces: space spaces -spaces: space +spaces: [space] spaces +spaces: [space] -space: " " -space: "\t" +optional_spaces: [space] optional_spaces +optional_spaces: -empty: spaces empty -empty: "\n" empty "\n" -empty: "\r" empty "\n" -empty: "#" notnewlines "\n" +empty: [space] empty +empty: "\n" empty +empty: "\r" empty +empty: "\n#" notnewlines empty: notnewlines: [notnewline] notnewlines @@ -30,13 +44,13 @@ notnewlines: predicate_section: predicate empty "\n" predicate_section predicate_section: -predicate: "[" ids "]:" spaces class +predicate: "[" ids "]:" optional_spaces class ids: [id] ids -ids: +ids: [id] # Yes, a class specification can be empty, in which case the predicate -# is equivalent with the default "any" predicate. +# matches everything. class: positive_class class: "^" positive_class @@ -44,23 +58,38 @@ class: "^" positive_class positive_class: positive_specification positive_class positive_class: -positive_specification: enotnewline -positive_specification: enotnewline "-" enotnewline +positive_specification: class_single_chars +positive_specification: class_range_chars "-" class_range_chars + +class_single_chars: [class_single_char] +class_single_chars: "\\" [any] -# Extended not-newline, or escaped not-newline -enotnewline: [notnewline] -enotnewline: "\\" [any] +class_range_chars: [class_range_char] +class_range_chars: "\\" [any] rules_section: rule empty "\n" rules_section +rules_section: -rule: rule_name ":" spaces rule_rhs -rule: rule_name ":" rule_rhs +rule: rule_name optional_spaces ":" optional_spaces rule_rhs -rule_name: [notbracket] rule_name +rule_name: [rule_name_char] rule_name rule_name: -spaces-or-escaped-newline: spaces -spaces-or-escaped-newline: "\\\n" +spaces_or_escaped_newline: optional_spaces +spaces_or_escaped_newline: "\\\n" + +rule_rhs: ids spaces_or_escaped_newline rule_rhs +rule_rhs: '[' ids ']' spaces_or_escaped_newline rule_rhs +rule_rhs: '"' double_string_chars '"' spaces_or_escaped_newline rule_rhs +rule_rhs: "'" single_string_chars "'" spaces_or_escaped_newline rule_rhs +rule_rhs: + +double_string_chars: [double_string_char] +double_string_chars: "\\" [any] +double_string_chars: [double_string_char] double_string_char +double_string_chars: "\\" [any] double_string_chars -rule_rhs: ids spaces-or-escaped-newline rule_rhs -rule_rhs: +single_string_chars: [single_string_char] +single_string_chars: "\\" [any] +single_string_chars: [single_string_char] single_string_char +single_string_chars: "\\" [any] single_string_chars diff --git a/src/bsr.c b/src/bsr.c index 4b7953a..2736a1b 100644 --- a/src/bsr.c +++ b/src/bsr.c @@ -242,8 +242,60 @@ print_bsr_f(pair5 label) print_name(list_nth(grammar_names(bsr_print_grammar), label.x)); printf(" := "); + /* List *string = rg_nth(grammar_rule(bsr_print_grammar, label.x), + * label.u); + * + * char s[5]; + * str *strp = (str *) new_utf8(s, 5); + * + * for (NUM i = 0; i < list_length(string); i++) { + * TNT *tntp = (TNT *)list_nth(string, i); + * PTD *ptdp = NULL; + * switch (tntp->type) { + * case TERMINAL: + * printf("'"); + * if (encode + * (tntp->data.t, strp)) { + * destroy_str(strp, 0); + * fleprintf0("Fail to encode\n"); + * return; + * } + * printf("%s'", s); + * str_set_length(strp, 5); + * break; + * case NONTERMINAL: + * for (int k = 0; + * (UNUM) k < + * ((cpa *) list_nth(grammar_names(bsr_print_grammar), + * tntp->data.nt))->size; + * k++) { + * if (encode + * (*(((cpa *)list_nth + * (grammar_names(bsr_print_grammar), + * tntp->data.nt))->array+k), + * strp)) { + * destroy_str(strp, 0); + * fleprintf0("Fail to encode!\n"); + * return; + * } + * printf("%s", s); + * str_set_length(strp, 5); + * } + * break; + * default: + * ptdp = (PTD *) list_nth + * (grammar_preds(bsr_print_grammar), tntp->data.pt); + * printf("[%s]", get_data(ptd_user_name(ptdp))); + * break; + * } + * if (i+1 #include #include "cnp.h" +#define TITO struct timespec tic, toc + +#define TIC do { \ + clock_gettime(CLOCK_MONOTONIC_RAW, &tic); \ + } while (0) + +#define TOC do { \ + clock_gettime(CLOCK_MONOTONIC_RAW, &toc); \ + printf("\nTotal time = %f seconds\n", \ + (toc.tv_nsec - tic.tv_nsec) / \ + 1000000000.0 + \ + toc.tv_sec - tic.tv_sec); \ + } while (0) + struct Environment_s { grammar_info *gi; /* RESULT_TS and RESULT_PS are temporary arrays used in the @@ -32,7 +47,6 @@ nt_add(Environment *env, NUM X, NUM j) for (NUM i = 0; i < rg_len(RG); i++) { BOOL result = test_select(env, *(env->string+j), X, rg_nth(RG, i)); - /* fleprintf("i = %ld, after test select\n", i); */ for (NUM k = 0; k < grammar_left_len(GI->g); k++) { ht_reset(env->result_ts+k, DELETE_KEY); @@ -42,12 +56,10 @@ nt_add(Environment *env, NUM X, NUM j) if (env->error) break; if (result) { - /* fleprintf("i = %ld, j = %ld\n", i, j); */ env->error = desc_add(env->pr, env->pu, j, (pair4) { .x = X, .y = i, .z = 0, .u = j }); - /* fleprintf("env->error = %d\n", env->error); */ /* print_procr(env->pr); */ /* fleprintf("pr len = %ld\n", env->pr->len); * fleprintf("pr ini = %d\n", (env->pr->array)->initialized); */ @@ -73,22 +85,40 @@ test_select(Environment *env, NUM b, NUM X, CCR_MOD(List *) tnts) ht *result_ts = env->result_ts; ht *result_ps = env->result_ps; + ht_reset(result_ts, DELETE_KEY); + ht_reset(result_ps, DELETE_KEY); + if (tnt_first(gi->pts, gi->pps, gi->nts, grammar_left_len(gi->g), tnts, result_ts, result_ps)) { fleprintf0("Fail to find the first set of the TNT string.\n"); goto cleanup; } + /* if (X == 3) { + * fleprintf0("for empty the first has "); + * for (NUM i = 0; i < ht_size(result_ts); i++) { + * eprintf("%ld", **((NUM **)ht_keys(result_ts)+i)); + * if (i+1data.nt == 1) + * fleprintf("first of tnts is %ld\n", + * ((TNT *)list_nth(tnts, 0))->data.nt); + * } */ if (ht_find(result_ts, &b) != NULL) { result = 1; + +#ifdef DEBUG + fleprintf("test succeeds against %ld\n", b); +#endif + goto success; } - + /* fleprintf("hi, size = %ld\n", ht_size(result_ps)); */ for (NUM i = 0; i < ht_size(result_ps); i++) { - PTD *ptdp = grammar_ptd(gi->g, **((PT **) ht_keys(result_ps+i))); + PTD *ptdp = grammar_ptd(gi->g, **((PT **) ht_keys(result_ps)+i)); if (ptd_run(ptdp, b)) { - /* fleprintf("i = %ld\n", i); */ result = 1; goto success; } @@ -104,24 +134,27 @@ test_select(Environment *env, NUM b, NUM X, CCR_MOD(List *) tnts) goto success; break; default: - if (!(gi->nts+TOP->data.nt)) goto success; + if (!(*(gi->nts+(TOP->data.nt)))) goto success; break; } #undef TOP } - + /* fleprintf("hi %ld\n", X); */ if (ht_find(gi->sts+X, &b) != NULL) { result = 1; + +#ifdef DEBUG + fleprintf("followed by %ld\n", b); +#endif + goto success; } for (NUM i = 0; i < ht_size(gi->sps+X); i++) { - PTD *ptdp = grammar_ptd(gi->g, **((PT **) ht_keys(gi->sps+X))); - /* fleprintf("i = %ld\n", i); */ + PTD *ptdp = grammar_ptd(gi->g, **((PT **) ht_keys(gi->sps+X)+i)); if (ptd_run(ptdp, b)) { - /* fleprintf("i = %ld\n", i); */ result = 1; goto success; } @@ -154,9 +187,11 @@ rtn_internal(pair6 label) label.v, label.w }))) return; - /* fleprintf("added descriptor (%ld, %ld, %ld, %ld, %ld)\n", - * label.z, label.u, label.v, label.w, - * rtn_internal_num); */ +#ifdef DEBUG + fleprintf("added descriptor (%ld, %ld, %ld, %ld, %ld)\n", + label.z, label.u, label.v, label.w, + rtn_internal_num); +#endif if ((rtn_internal_env->error = bsr_add(rtn_internal_env->gi->g, @@ -175,9 +210,11 @@ rtn(Environment *env, NUM X, NUM k, NUM j) pair3 label = (pair3) { .x = X, .y = k, .z = j }; pair2 label2 = (pair2) { .x = X, .y = k }; - if (spa_belong(env->spap, label)) return; +#ifdef DEBUG + fleprintf("encounter %ld, %ld, %ld\n", X, k, j); +#endif - /* fleprintf0("new spa\n"); */ + if (spa_belong(env->spap, label)) return; if ((env->error = spa_insert(env->spap, label))) return; @@ -267,7 +304,12 @@ cnp_call(Environment *env, pair3 label, NUM i, NUM j) } NUM X = (NUM) xtnt->data.nt; - /* fleprintf("X = %ld, j = %ld\n", X, j); */ + +#ifdef DEBUG + fleprintf0("X = "); + eprint_name(list_nth(grammar_names(env->gi->g), X)); + eprintf(", j = %ld\n", j); +#endif pair2 node = (pair2) { .x = X, .y = j }; pair4 u = (pair4) @@ -279,11 +321,21 @@ cnp_call(Environment *env, pair3 label, NUM i, NUM j) }; if (!(crf_find_node(env->crfp, node))) { + +#ifdef DEBUG + fleprintf("adding node (%ld, %ld)\n", X, j); +#endif + if (crf_add_node(env->crfp, node)) { fleprintf0("fail to add node to crf\n"); goto cleanup; } +#ifdef DEBUG + fleprintf("adding edge to (%ld, %ld, %ld, %ld)\n", + u.x, u.y, u.z, u.u); +#endif + if (crf_add_edge(env->crfp, node, u)) { fleprintf0("fail to add edge to crf\n"); goto cleanup; @@ -292,11 +344,14 @@ cnp_call(Environment *env, pair3 label, NUM i, NUM j) /* errors will be stored in ENV, so we simply return */ nt_add(env, X, j); - /* fleprintf("X = %ld, j = %ld\n", X, j); */ - return; } +#ifdef DEBUG + fleprintf("adding edge to (%ld, %ld, %ld, %ld)\n", + u.x, u.y, u.z, u.u); +#endif + if (!(crf_find_edge(env->crfp, node, u))) { if (crf_add_edge(env->crfp, node, u)) { fleprintf0("fail to add edge to crf\n"); @@ -378,11 +433,13 @@ env_follow_p(CCR_MOD(Environment *) env, NUM X, NUM t) for (NUM i = 0; i < ht_size(env->gi->sps+X); i++) { PTD *ptdp = grammar_ptd(env->gi->g, - **((PT **) ht_keys(env->gi->sps+X))); + **((PT **) ht_keys(env->gi->sps+X)+i)); if (ptd_run(ptdp, t)) return 1; } - /* fleprintf("X = %ld, t = %ld\n", X, t); */ +#ifdef DEBUG + fleprintf("X = %ld, t = %ld\n", X, t); +#endif return 0; } @@ -679,6 +736,9 @@ cnp_parse(Grammar *g, str *string) if (env_follow_p(env, current_prodecor->x, *(num_string+current_grade))) { +#ifdef DEBUG + fleprintf0("returning from an empty rule\n"); +#endif rtn(env, current_prodecor->x, current_prodecor->u, current_grade); } @@ -693,6 +753,9 @@ cnp_parse(Grammar *g, str *string) if (current_prodecor->z == list_length(right)) { if (env_follow_p(env, current_prodecor->x, *(num_string+current_grade))) { +#ifdef DEBUG + fleprintf0("returning from the end\n"); +#endif rtn(env, current_prodecor->x, current_prodecor->u, current_grade); } @@ -744,7 +807,17 @@ cnp_parse(Grammar *g, str *string) ((TNT *) list_nth(right, current_prodecor->z-1))->type == PREDICATE) { #ifdef DEBUG - fleprintf0("found terminal\n"); + if (((TNT *) list_nth(right, current_prodecor->z-1))->type == + TERMINAL) + fleprintf("found terminal %ld\n", + ((TNT *) + list_nth + (right, current_prodecor->z-1))->data.t); + else + fleprintf("found predicate terminal %ld\n", + ((TNT *) + list_nth + (right, current_prodecor->z-1))->data.pt); #endif /* add to BSR set */ errorp = @@ -771,8 +844,12 @@ cnp_parse(Grammar *g, str *string) goto continue_label; } + #ifdef DEBUG fleprintf0("terminal not at the end\n"); + fleprintf("testing X = %ld, z = %ld, input = %ld\n", + current_prodecor->x, current_prodecor->z, + *(num_string+current_grade)); #endif /* else test select */ tnts = @@ -818,10 +895,12 @@ cnp_parse(Grammar *g, str *string) .z = current_prodecor->z }, current_prodecor->u, current_grade); - /* fleprintf("after call { %ld, %ld, %ld, %ld, %ld }\n", - * current_prodecor->x, current_prodecor->y, - * current_prodecor->z, current_prodecor->u, - * current_grade); */ +#ifdef DEBUG + fleprintf("after call { %ld, %ld, %ld, %ld, %ld }\n", + current_prodecor->x, current_prodecor->y, + current_prodecor->z, current_prodecor->u, + current_grade); +#endif continue_label: diff --git a/src/crf.c b/src/crf.c index 1c9fea9..5dba8bf 100644 --- a/src/crf.c +++ b/src/crf.c @@ -95,8 +95,10 @@ crf_add_edge(crf *crfp, pair2 source, pair4 label) label.u }; - /* fleprintf("adding (%ld, %ld, %ld, %ld, %ld, %ld)\n", - * p6.x, p6.y, p6.z, p6.u, p6.v, p6.w); */ +#ifdef DEBUG + fleprintf("adding (%ld, %ld, %ld, %ld, %ld, %ld)\n", + p6.x, p6.y, p6.z, p6.u, p6.v, p6.w); +#endif NUM *find_result = luple6_find(crfp->lup, p6); @@ -118,7 +120,9 @@ crf_add_edge(crf *crfp, pair2 source, pair4 label) void destroy_crf(crf *crfp) { + /* fleprintf0("hi\n"); */ destroy_luple6(crfp->lup); + /* fleprintf0("hi\n"); */ free(crfp); } diff --git a/src/dfa.c b/src/dfa.c index 2edda77..f3f62fb 100644 --- a/src/dfa.c +++ b/src/dfa.c @@ -717,8 +717,8 @@ run_dfa(const dfa * const restrict table, const NUM code) if (code >= (table->data.sp.ranges+i)->beg && code <= (table->data.sp.ranges+i)->end) { #ifdef DEBUG - fleprintf("code = %ld, beg = %ld, end = %ld\n", - code, + fleprintf("i = %d, code = %ld, beg = %ld, end = %ld\n", + i, code, (table->data.sp.ranges+i)->beg, (table->data.sp.ranges+i)->end); #endif @@ -727,17 +727,18 @@ run_dfa(const dfa * const restrict table, const NUM code) return 0; break; case DFA_TYPE_SPECIAL_NEG: - for (int i = 0; i < table->data.sp.len; i++) + for (int i = 0; i < table->data.sp.len; i++) { if (code >= (table->data.sp.ranges+i)->beg && code <= (table->data.sp.ranges+i)->end) { #ifdef DEBUG - fleprintf("code = %ld, beg = %ld, end = %ld\n", - code, + fleprintf("code = %ld, i = %d, beg = %ld, end = %ld\n", + code, i, (table->data.sp.ranges+i)->beg, (table->data.sp.ranges+i)->end); #endif return 0; } + } return 1; break; case DFA_TYPE_SPECIAL_BOTH: diff --git a/src/grammar.c b/src/grammar.c index 1ea52b0..55a1e07 100644 --- a/src/grammar.c +++ b/src/grammar.c @@ -63,6 +63,13 @@ new_ptd(str *user_name, str *raw_name, dfa *dfap) return result; } +P_ATTR +str * +ptd_user_name(PTD *p) +{ + return p->user_name; +} + void destroy_ptd(PTD *p, int flag) { @@ -91,14 +98,8 @@ destroy_ptd_no_free(void *e) destroy_ptd((PTD *)e, 0); } -/* REVIEW: Add some statistic counts to assist the hash tables. For - example, store the total number of terminals as an integer; then - the hash table can be hinted at initialization to contain that many - elements, which can reduce the number of time a hash table needs to - expand and re-insert all its keys, which then helps the - performance. But this is not the top priority thing to do, and - might be postponed until a proto-type of the parser generator is - usable already. */ +/* FIXME: Add a list of terminals, so that we don't need to use hash + tables. */ /* rule_grps and names should have the same length */ struct Grammar_s { @@ -160,20 +161,85 @@ destroy_rule_group_free_first(void *rule_grp) static void print_sep() { - printf(", "); + printf(",\n"); } static void -print_rule_group(void *rule_grp) +print_rule_group(Grammar *g, void *rule_grp) { Rule_group *rg = (Rule_group *) rule_grp; + char s[5]; + str *strp = (str *) new_utf8(s, 5); + for (int i = 0; i < list_length(rg->rights); i++) { - List *str = (List *) list_nth(rg->rights, i); - printf("Rule %lu => ", rg->left); - map_list_between(str, print_tnt, print_sep); + /* fleprintf("i = %d\n", i); */ + List *strls = (List *) list_nth(rg->rights, i); + /* printf("Rule "); */ + for (int j = 0; + (UNUM) j < ((cpa *)list_nth(g->names, rg->left))->size; + j++) { + + if (encode + (*(((cpa *)list_nth(g->names, rg->left))->array+j), + strp)) { + destroy_str(strp, 0); + fleprintf0("Fail to encode!\n"); + return; + } + + *(s+str_length(strp)) = 0; + printf("%s", s); + str_set_length(strp, 5); + } + printf(" := "); + + for (int j = 0; j < list_length(strls); j++) { + /* fleprintf("j = %d, len = %ld\n", j, list_length(strls)); */ + TNT *tntp = (TNT *) list_nth(strls, j); + PTD *ptdp = NULL; + switch (tntp->type) { + case TERMINAL: + printf("'"); + if (encode + (tntp->data.t, + strp)) { + destroy_str(strp, 0); + fleprintf0("Fail to encode!\n"); + return; + } + printf("%s'", s); + str_set_length(strp, 5); + break; + case NONTERMINAL: + for (int k = 0; + (UNUM) k < ((cpa *)list_nth(g->names, + tntp->data.nt))->size; + k++) { + if (encode + (*(((cpa *)list_nth(g->names, tntp->data.nt))->array+k), + strp)) { + destroy_str(strp, 0); + fleprintf0("Fail to encode!\n"); + return; + } + printf("%s", s); + str_set_length(strp, 5); + } + break; + default: + /* predicate */ + ptdp = (PTD *) list_nth(g->predicates, tntp->data.pt); + /* fleprintf("pt = %lu\n", tntp->data.pt); */ + printf("[%s]", get_data(ptdp->user_name)); + break; + } + if (j+1size; i++) { + int result = encode(*(array->array+i), string); + + if (result) { + fleprintf("%llu, fail to encode %ld\n", i, *(array->array+i)); + str_set_length(string, 5); + continue; + } + + carray = get_data(string); + *(carray+str_length(string)) = 0; + printf("%s", carray); str_set_length(string, 5); } @@ -411,8 +503,6 @@ print_name(void *element) destroy_str(string, 1); } -/* REVIEW: Print the names of non-terminals out, instead of printing - the numbers? */ void print_grammar(CC_MOD(Grammar *) g) { @@ -420,7 +510,7 @@ print_grammar(CC_MOD(Grammar *) g) printf("Non-terminals...\n"); map_list_between(g->names, print_name, print_sep); - printf("\n"); + printf("\n\n"); printf("Predicates...\n"); @@ -431,9 +521,11 @@ print_grammar(CC_MOD(Grammar *) g) get_data(ptdp->user_name), get_data(ptdp->raw_name)); } + printf("\n"); + printf("Rules...\n"); for (int i = 0; i < list_length(g->rule_grps); i++) { - print_rule_group(list_nth(g->rule_grps, i)); + print_rule_group((Grammar *) g, list_nth(g->rule_grps, i)); printf("\n"); } @@ -568,6 +660,7 @@ grammar_ptd(CCR_MOD(Grammar *) g, PT pt) return (PTD *) list_nth(g->predicates, pt); } +P_ATTR NUM grammar_left_len(CCR_MOD(Grammar *)g) { @@ -581,6 +674,13 @@ grammar_names(CCR_MOD(Grammar *)g) return g->names; } +P_ATTR +List * +grammar_preds(CCR_MOD(Grammar *)g) +{ + return g->predicates; +} + /* A transitive closure algorithm */ void epsilon_nts(CC_MOD(Grammar *) g, BOOL * const restrict nts) @@ -682,11 +782,13 @@ nt_first(CC_MOD(Grammar *) g, CCR_MOD(BOOL *) nts, BREAKOUT; } else { free(tempT); + BREAKOUT; } break; case PREDICATE: SAFE_MALLOC(NUM, tempPT, 1, return 1;); *tempPT = top->data.pt; + if (first && ht_find(predicate_hts+i, tempPT) == NULL) { changed = 1; @@ -694,6 +796,7 @@ nt_first(CC_MOD(Grammar *) g, CCR_MOD(BOOL *) nts, BREAKOUT; } else { free(tempPT); + BREAKOUT; } break; default: @@ -777,7 +880,6 @@ tnt_first(CC_MOD(ht *) terminal_hts, CC_MOD(ht *) predicate_hts, for (NUM i = 0; i < tnt_len; i++) { top = (TNT *) list_nth(tnts, i); - switch (top->type) { case TERMINAL: if (ht_find(result_terminals, &(top->data.t)) == NULL) { @@ -797,6 +899,9 @@ tnt_first(CC_MOD(ht *) terminal_hts, CC_MOD(ht *) predicate_hts, break; default: current = top->data.nt; + /* if (tnt_len == 2 && current == 1) { + * fleprintf0("generating for empty\n"); + * } */ if (current >= (NT) len || current < 0) { fleprintf("Wrong non-terminal: %ld>%ld\n", current, len); @@ -949,6 +1054,13 @@ nt_follow(CC_MOD(Grammar *) g, CCR_MOD(BOOL *) nts, for (NUM ell = 0; ell < ht_len;) { SAFE_MALLOC(NUM, tempN, 1, return 1;); *tempN = **(keys+ell++); + /* if (top->data.nt == 17 || + * top->data.nt == 14 || + * top->data.nt == 13) { + * fleprintf("add pred %ld to NT %ld\n", *tempN, + * top->data.nt); + * eprintf("i = %ld, k = %ld, ell = %ld\n", i, k, ell); + * } */ if (ht_find(result_predicates+top->data.nt, tempN) == NULL) { changed = 1; diff --git a/src/grammar.h b/src/grammar.h index 89a66ba..bf418e0 100644 --- a/src/grammar.h +++ b/src/grammar.h @@ -75,6 +75,8 @@ typedef struct PT_DATA_s PTD; /* On error return NULL */ PTD *new_ptd(str *user_name, str *raw_name, dfa *dfap); +P_ATTR str *ptd_user_name(PTD *p); + /* FLAG is used to destroy the strings contained within */ void destroy_ptd(PTD *p, int flag); @@ -134,6 +136,8 @@ find_in_cpa_list(CCR_MOD(NUM *) string, NUM size, /* assume element is a cpa pointer */ void print_name(void *element); +void eprint_name(void *element); + void print_tnt(void *element); void print_rule(void *r); @@ -167,9 +171,10 @@ void destroy_rule_no_free(void *rule); void destroy_cpa_and_free_all(void *element); void destroy_grammar(void *grammar, int flag); -NUM grammar_left_len(CCR_MOD(Grammar *)g); +P_ATTR NUM grammar_left_len(CCR_MOD(Grammar *)g); -List *grammar_names(CCR_MOD(Grammar *)g); +P_ATTR List *grammar_names(CCR_MOD(Grammar *)g); +P_ATTR List *grammar_preds(CCR_MOD(Grammar *)g); /* look up a rule */ Rule_group *grammar_rule(CCR_MOD(Grammar *) g, NT nt); diff --git a/src/test/check_reader.c b/src/test/check_reader.c index a4e184f..45025ff 100644 --- a/src/test/check_reader.c +++ b/src/test/check_reader.c @@ -1,18 +1,517 @@ +#include #include #include +#include +#include -#include "../util.h" -#include "../list.h" -#include "../grammar.h" -#include "../reader.h" +#include "../cnp.h" + +#define TITO struct timespec tic, toc + +#define TIC do { \ + clock_gettime(CLOCK_MONOTONIC_RAW, &tic); \ + } while (0) + +#define TOC do { \ + clock_gettime(CLOCK_MONOTONIC_RAW, &toc); \ + printf("\nTotal time = %f seconds\n", \ + (toc.tv_nsec - tic.tv_nsec) / \ + 1000000000.0 + \ + toc.tv_sec - tic.tv_sec); \ + } while (0) + +#define READ_INTO_CPA(N, U, L, I, VA, VI, CP) do { \ + U = new_utf8(N, L); \ + I = get_info((str *)U, 0); \ + VI = 0; \ + for (NUM index = 0; \ + I.value >= 0 && index < str_length((str*) U); \ + index += I.step, VI++) { \ + I = get_info((str*)U, index); \ + } \ + SAFE_MALLOC(NUM, VA, VI, return 1;); \ + I = get_info((str *)U, 0); \ + VI = 0; \ + for (NUM index = 0; \ + I.value >= 0 && index < str_length((str *) U); \ + index += I.step, VI++) { \ + I = get_info((str *)U, index); \ + *(VA+VI) = I.value; \ + } \ + SAFE_MALLOC(cpa, CP, 1, return 1;); \ + CP->array = VA; \ + CP->size = VI; \ + if (add_to_list(names, CP)) { \ + fleprintf0("Fail to add to names\n"); \ + return 1; \ + } \ + destroy_str((str *)U, 1); \ + } while (0) + +#define READ_TNT_STRING(LEFT, FORMAT, LEN, ...) do { \ + tnt_string = new_tnt_string(FORMAT, LEN, __VA_ARGS__); \ + if (!tnt_string) { \ + fleprintf("left = %d, f = %s, l = %d, " \ + "cannot create tnt string\n", \ + LEFT, FORMAT, LEN); \ + map_list(rules, destroy_rule_and_free_all); \ + destroy_list(rules, 0); \ + map_list(names, destroy_cpa_and_free_all); \ + destroy_list(names, 0); \ + return 1; \ + } \ + rule = new_rule(LEFT, tnt_string); \ + add_to_list(rules, rule); \ + } while (0) + +#define ADD_EMPTY_RULE(N) do { \ + rule = new_rule(N, new_list()); \ + add_to_list(rules, rule); \ + } while (0) int -main(U_ATTR int argc, U_ATTR char **argv) +main(int UNUSED argc, char UNUSED **argv) { - /* return 77; */ + List *tnt_string = NULL; + Rule *rule = NULL; + List *rules = new_list(); + List *names = new_list(); + List *preds = new_list(); + + char *user_name = NULL; + char *raw_name = NULL; + + str *user_name_s = NULL, *raw_name_s = NULL; + + char *name = NULL; + utf8* uname = NULL; + + int name_len = 0; + + str_info info = EMPTY_STR_INFO; + + NUM *varray = NULL; + NUM vindex = 0; + cpa *cpap = NULL; + + SAFE_MALLOC(char, name, 3, return 1;); + + *name = 'B'; + *(name+1) = 'N'; + *(name+2) = 'F'; + + READ_INTO_CPA(name, uname, 3, info, varray, vindex, cpap); + + SAFE_MALLOC(char, name, 6, return 1;); + + *name = 's'; + *(name+1) = 'p'; + *(name+2) = 'a'; + *(name+3) = 'c'; + *(name+4) = 'e'; + *(name+5) = 's'; + + READ_INTO_CPA(name, uname, 6, info, varray, vindex, cpap); + + SAFE_MALLOC(char, name, 15, return 1;); + + *name = 'o'; + *(name+1) = 'p'; + *(name+2) = 't'; + *(name+3) = 'i'; + *(name+4) = 'o'; + *(name+5) = 'n'; + *(name+6) = 'a'; + *(name+7) = 'l'; + *(name+8) = '_'; + *(name+9) = 's'; + *(name+10) = 'p'; + *(name+11) = 'a'; + *(name+12) = 'c'; + *(name+13) = 'e'; + *(name+14) = 's'; + + READ_INTO_CPA(name, uname, 15, info, varray, vindex, cpap); + + SAFE_MALLOC(char, name, 5, return 1;); + + *name = 'e'; + *(name+1) = 'm'; + *(name+2) = 'p'; + *(name+3) = 't'; + *(name+4) = 'y'; + + READ_INTO_CPA(name, uname, 5, info, varray, vindex, cpap); + + SAFE_MALLOC(char, name, 11, return 1;); + + memcpy(name, "notnewlines", 11); + + READ_INTO_CPA(name, uname, 11, info, varray, vindex, cpap); + + SAFE_MALLOC(char, name, 17, return 1;); + + memcpy(name, "predicate_section", 17); + + READ_INTO_CPA(name, uname, 17, info, varray, vindex, cpap); + + SAFE_MALLOC(char, name, 9, return 1;); + + memcpy(name, "predicate", 9); + + READ_INTO_CPA(name, uname, 9, info, varray, vindex, cpap); + + name_len = 3; + SAFE_MALLOC(char, name, name_len, return 1;); + + memcpy(name, "ids", name_len); + + READ_INTO_CPA(name, uname, name_len, info, varray, vindex, cpap); + + name_len = 5; + SAFE_MALLOC(char, name, name_len, return 1;); + + memcpy(name, "class", name_len); + + READ_INTO_CPA(name, uname, name_len, info, varray, vindex, cpap); + + name_len = 14; + SAFE_MALLOC(char, name, name_len, return 1;); + + memcpy(name, "positive_class", name_len); + + READ_INTO_CPA(name, uname, name_len, info, varray, vindex, cpap); + + name_len = 22; + SAFE_MALLOC(char, name, name_len, return 1;); + + memcpy(name, "positive_specification", name_len); + + READ_INTO_CPA(name, uname, name_len, info, varray, vindex, cpap); + + name_len = 18; + SAFE_MALLOC(char, name, name_len, return 1;); + + memcpy(name, "class_single_chars", name_len); + + READ_INTO_CPA(name, uname, name_len, info, varray, vindex, cpap); + + name_len = 17; + SAFE_MALLOC(char, name, name_len, return 1;); + + memcpy(name, "class_range_chars", name_len); + + READ_INTO_CPA(name, uname, name_len, info, varray, vindex, cpap); + + name_len = 13; + SAFE_MALLOC(char, name, name_len, return 1;); + + memcpy(name, "rules_section", name_len); + + READ_INTO_CPA(name, uname, name_len, info, varray, vindex, cpap); + + name_len = 4; + SAFE_MALLOC(char, name, name_len, return 1;); + + memcpy(name, "rule", name_len); + + READ_INTO_CPA(name, uname, name_len, info, varray, vindex, cpap); + + name_len = 9; + SAFE_MALLOC(char, name, name_len, return 1;); + + memcpy(name, "rule_name", name_len); + + READ_INTO_CPA(name, uname, name_len, info, varray, vindex, cpap); + + name_len = 25; + SAFE_MALLOC(char, name, name_len, return 1;); + + memcpy(name, "spaces-or-escaped-newline", name_len); + + READ_INTO_CPA(name, uname, name_len, info, varray, vindex, cpap); + + name_len = 8; + SAFE_MALLOC(char, name, name_len, return 1;); + + memcpy(name, "rule_rhs", name_len); + + READ_INTO_CPA(name, uname, name_len, info, varray, vindex, cpap); + + name_len = 19; + SAFE_MALLOC(char, name, name_len, return 1;); + + memcpy(name, "double_string_chars", name_len); + + READ_INTO_CPA(name, uname, name_len, info, varray, vindex, cpap); + + name_len = 19; + SAFE_MALLOC(char, name, name_len, return 1;); + + memcpy(name, "single_string_chars", name_len); + + READ_INTO_CPA(name, uname, name_len, info, varray, vindex, cpap); + + READ_TNT_STRING(0, "tnnn", 4, (T) '#', (NT) 4, (NT) 3, (NT) 0); + READ_TNT_STRING(0, "ntttnn", 6, (NT) 5, + (T) '-', (T) '-', (T) 0xa, (NT) 3, (NT) 13); + READ_TNT_STRING(0, "n", 1, (NT) 13); + ADD_EMPTY_RULE(0); + + READ_TNT_STRING(1, "pn", 2, (PT) 0, (NT) 1); + READ_TNT_STRING(1, "p", 1, (PT) 0); + + READ_TNT_STRING(2, "pn", 2, (PT) 0, (NT) 2); + ADD_EMPTY_RULE(2); + + READ_TNT_STRING(3, "pn", 2, (PT) 0, (NT) 3); + READ_TNT_STRING(3, "tn", 2, (T) 0xa, (NT) 3); + READ_TNT_STRING(3, "tn", 2, (T) 0xd, (NT) 3); + READ_TNT_STRING(3, "ttnn", 4, (T) 0xa, (T) 0x23, + (NT) 4, (NT) 3); + ADD_EMPTY_RULE(3); + + READ_TNT_STRING(4, "pn", 2, (PT) 3, (NT) 4); + ADD_EMPTY_RULE(4); + + READ_TNT_STRING(5, "nntn", 4, (NT) 6, (NT) 3, (T) 0xa, (NT) 5); + ADD_EMPTY_RULE(5); + + READ_TNT_STRING(6, "tnttnn", 6, (T) '[', (NT) 7, + (T) ']', (T) ':', (NT) 2, (NT) 8); + + READ_TNT_STRING(7, "pn", 2, (PT) 1, (NT) 7); + READ_TNT_STRING(7, "p", 1, (PT) 1); + + READ_TNT_STRING(8, "n", 1, (NT) 9); + READ_TNT_STRING(8, "tn", 2, (T) '^', (NT) 9); + + READ_TNT_STRING(9, "nn", 2, (NT) 10, (NT) 9); + ADD_EMPTY_RULE(9); + + READ_TNT_STRING(10, "n", 1, (NT) 11); + READ_TNT_STRING(10, "ntn", 3, (NT) 12, (T) '-', (NT) 12); + + READ_TNT_STRING(11, "p", 1, (PT) 5); + READ_TNT_STRING(11, "tp", 2, (T) 0x5c, (PT) 6); + + READ_TNT_STRING(12, "p", 1, (PT) 4); + READ_TNT_STRING(12, "tp", 2, (T) 0x5c, (PT) 6); + + READ_TNT_STRING(13, "nntn", 4, (NT) 14, (NT) 3, (T) 0xa, (NT) 13); + ADD_EMPTY_RULE(13); + + READ_TNT_STRING(14, "nntnn", 5, + (NT) 15, (NT) 2, (T) ':', + (NT) 2, (NT) 17); + + READ_TNT_STRING(15, "pn", 2, (PT) 2, (NT) 15); + ADD_EMPTY_RULE(15); + + READ_TNT_STRING(16, "n", 1, (NT) 2); + READ_TNT_STRING(16, "tt", 2, (T) 0x5c, (T) 0xa); + + READ_TNT_STRING(17, "nnn", 3, (NT) 7, (NT) 16, (NT) 17); + READ_TNT_STRING(17, "tntnn", 5, + (T) '[', (NT) 7, (T) ']', (NT) 16, (NT) 17); + READ_TNT_STRING(17, "tntnn", 5, + (T) 0x22, (NT) 18, (T) 0x22, (NT) 16, (NT) 17); + READ_TNT_STRING(17, "tntnn", 5, + (T) 0x27, (NT) 19, (T) 0x27, (NT) 16, (NT) 17); + ADD_EMPTY_RULE(17); + + READ_TNT_STRING(18, "p", 1, (PT) 7); + READ_TNT_STRING(18, "tp", 2, (T) '\\', (PT) 6); + READ_TNT_STRING(18, "pn", 2, (PT) 7, (NT) 18); + READ_TNT_STRING(18, "tpn", 3, (T) '\\', (PT) 6, (NT) 18); + + READ_TNT_STRING(19, "p", 1, (PT) 8); + READ_TNT_STRING(19, "tp", 2, (T) '\\', (PT) 6); + READ_TNT_STRING(19, "pn", 2, (PT) 8, (NT) 19); + READ_TNT_STRING(19, "tpn", 3, (T) '\\', (PT) 6, (NT) 19); + + SAFE_MALLOC(char, user_name, 6, return 1;); + memcpy(user_name, "space", 6); + user_name_s = (str *) new_utf8(user_name, 6); + + SAFE_MALLOC(char, raw_name, 7, return 1;); + memcpy(raw_name, "%x20\\t", 7); + raw_name_s = (str *) new_utf8(raw_name, 7); + + if (add_to_list(preds, + new_ptd(user_name_s, raw_name_s, + dfa_from_ranges + (2, (NUM[]) { ' ', ' ', 9, 9 })))) { + fleprintf0("Fail to add a predicate\n"); + return 1; + } + + SAFE_MALLOC(char, user_name, 3, return 1;); + memcpy(user_name, "id", 3); + user_name_s = (str *) new_utf8(user_name, 3); + + SAFE_MALLOC(char, raw_name, 12, return 1;); + memcpy(raw_name, "a-zA-Z-_+*@", 12); + raw_name_s = (str *) new_utf8(raw_name, 12); + + if (add_to_list(preds, + new_ptd(user_name_s, raw_name_s, + dfa_from_ranges + (6, (NUM[]) { + 'a', 'z', 'A', 'Z', + '-', '-', '_', '_', + '*', '+', '@', '@' + })))) { + fleprintf0("Fail to add a predicate\n"); + return 1; + } + + SAFE_MALLOC(char, user_name, 15, return 1;); + memcpy(user_name, "rule_name_char", 15); + user_name_s = (str *) new_utf8(user_name, 15); + + SAFE_MALLOC(char, raw_name, 12, return 1;); + memcpy(raw_name, "^[]:%x20\\n#", 12); + raw_name_s = (str *) new_utf8(raw_name, 12); + + if (add_to_list(preds, + new_ptd(user_name_s, raw_name_s, + dfa_from_ranges_neg + (6, (NUM[]) { + '[', '[', ']', ']', + ':', ':', ' ', ' ', + 0xa, 0xa, 0x23, 0x23 + })))) { + fleprintf0("Fail to add a predicate\n"); + return 1; + } + + SAFE_MALLOC(char, user_name, 11, return 1;); + memcpy(user_name, "notnewline", 11); + user_name_s = (str *) new_utf8(user_name, 11); + + SAFE_MALLOC(char, raw_name, 6, return 1;); + memcpy(raw_name, "^\\n\\r", 6); + raw_name_s = (str *) new_utf8(raw_name, 6); + + if (add_to_list(preds, + new_ptd(user_name_s, raw_name_s, + dfa_from_ranges_neg + (2, (NUM[]) { + '\n', '\n', '\r', '\r' + })))) { + fleprintf0("Fail to add a predicate\n"); + return 1; + } + + SAFE_MALLOC(char, user_name, 17, return 1;); + memcpy(user_name, "class_range_char", 17); + user_name_s = (str *) new_utf8(user_name, 17); + + SAFE_MALLOC(char, raw_name, 10, return 1;); + memcpy(raw_name, "^\\n\\r\\^\\\\", 10); + raw_name_s = (str *) new_utf8(raw_name, 10); + + if (add_to_list(preds, + new_ptd(user_name_s, raw_name_s, + dfa_from_ranges_neg + (4, (NUM[]) { + '\n', '\n', '\r', '\r', + '^', '^', '\\', '\\' + })))) { + fleprintf0("Fail to add a predicate\n"); + return 1; + } + + SAFE_MALLOC(char, user_name, 18, return 1;); + memcpy(user_name, "class_single_char", 18); + user_name_s = (str *) new_utf8(user_name, 18); + + SAFE_MALLOC(char, raw_name, 11, return 1;); + memcpy(raw_name, "^\\n\\r\\^\\\\-", 11); + raw_name_s = (str *) new_utf8(raw_name, 11); + + if (add_to_list(preds, + new_ptd(user_name_s, raw_name_s, + dfa_from_ranges_neg + (5, (NUM[]) { + '\n', '\n', '\r', '\r', + '^', '^', '\\', '\\', + '-', '-' + })))) { + fleprintf0("Fail to add a predicate\n"); + return 1; + } + + SAFE_MALLOC(char, user_name, 4, return 1;); + memcpy(user_name, "any", 4); + user_name_s = (str *) new_utf8(user_name, 4); + + SAFE_MALLOC(char, raw_name, 2, return 2;); + memcpy(raw_name, " ", 2); + raw_name_s = (str *) new_utf8(raw_name, 2); + + if (add_to_list(preds, + new_ptd(user_name_s, raw_name_s, + dfa_from_ranges + (1, (NUM[]) { + 0, 0x10ffff + })))) { + fleprintf0("Fail to add a predicate\n"); + return 1; + } + + SAFE_MALLOC(char, user_name, 19, return 1;); + memcpy(user_name, "double_string_char", 19); + user_name_s = (str *) new_utf8(user_name, 19); + + SAFE_MALLOC(char, raw_name, 5, return 1;); + memcpy(raw_name, "^\"\\n", 5); + raw_name_s = (str *) new_utf8(raw_name, 5); + + if (add_to_list(preds, + new_ptd(user_name_s, raw_name_s, + dfa_from_ranges_neg + (2, (NUM[]) { + 0x22, 0x22, 0xa, 0xa + })))) { + fleprintf0("Fail to add a predicate\n"); + return 1; + } + + SAFE_MALLOC(char, user_name, 19, return 1;); + memcpy(user_name, "single_string_char", 19); + user_name_s = (str *) new_utf8(user_name, 19); + + SAFE_MALLOC(char, raw_name, 5, return 1;); + memcpy(raw_name, "^'\\n", 5); + raw_name_s = (str *) new_utf8(raw_name, 5); + + if (add_to_list(preds, + new_ptd(user_name_s, raw_name_s, + dfa_from_ranges_neg + (2, (NUM[]) { + 0x27, 0x27, 0xa, 0xa + })))) { + fleprintf0("Fail to add a predicate\n"); + return 1; + } + + Grammar *g = new_grammar(); + + build_grammar(g, rules, names, preds); + + print_grammar(g); + + /* utf8 *string = new_utf8("# comment\n\n[P]: a-z\n\n--\n\nS : AB\n" + * "# another comment\nA: \"S\"\nB : [P]\n", + * 65); */ + + char *file_name = "bnf.bnf"; + char *buffer = NULL; + + SAFE_MALLOC(char, buffer, 1<<9, return 1;); - char *file_name = "brainfuck.bnf"; - char *buffer = MYALLOC(char, 512); NUM buffer_size = 0; if (read_entire_file(file_name, &buffer, &buffer_size)) { @@ -21,17 +520,80 @@ main(U_ATTR int argc, U_ATTR char **argv) return 1; } - utf8 *s = new_utf8(buffer, buffer_size); + /* The size includes the trailing null byte, so we shall exclude + it. */ + buffer_size--; + + str *string = (str *) new_utf8(buffer, buffer_size); + + printf("\nPrinting the input...\n%s\n", get_data(string)); + + printf("Input size = %ld", buffer_size); + + TITO; + + TIC; - Grammar *g = read_grammar_from_bnf((str *) s); + Environment *env = cnp_parse(g, string); - if (g) { - print_grammar(g); - destroy_grammar(g, 2); - destroy_str((str *)s, 1); + TOC; - return 0; + if (env) { + if (!(env_error_p(env))) { + BOOL result = bsr_lookup + (env_bsrp(env), 0, 0, str_length((str *) string)); + + if (result) { + printf("\nSuccessfully parsed the input!\n"); + } else { + printf("\nThe input does not parse!\n"); + } + + printf("\nAll BSRs follow:\n\n"); + if (argc == 1) + bsr_print(env_bsrp(env), env_grammar(env), 1); + } else { + printf("There are errors!\n"); + } + + destroy_env(env); } - return 1; + destroy_grammar(g, 1); + + destroy_list(rules, 1); + + destroy_str(string, 1); + + return 0; } + + +/* archives */ + +/* char *file_name = "brainfuck.bnf"; + * char *buffer = NULL; + * + * SAFE_MALLOC(char, buffer, 1<<9, return 1;); + * + * NUM buffer_size = 0; + * + * if (read_entire_file(file_name, &buffer, &buffer_size)) { + * fleprintf("Cannot read file %s", file_name); + * free(buffer); + * return 1; + * } + * + * utf8 *s = new_utf8(buffer, buffer_size); + * + * Grammar *g = read_grammar_from_bnf((str *) s); + * + * if (g) { + * print_grammar(g); + * destroy_grammar(g, 2); + * destroy_str((str *)s, 1); + * + * return 0; + * } + * + * return 1; */ diff --git a/src/tuple.c b/src/tuple.c index 92f2e6a..190aa19 100644 --- a/src/tuple.c +++ b/src/tuple.c @@ -185,7 +185,9 @@ LONSTRUCT(6); static void destroy_tuple1(tuple1 tup, NUM * UNUSED len) { + /* fleprintf0("hi\n"); */ if (!(tup.initialized)) return; + /* fleprintf0("hi\n"); */ free(tup.array); } @@ -196,8 +198,11 @@ void destroy_tuple4(tuple4 tup, NUM *len) { if (!(tup.initialized)) return; - for (NUM i4 = 0; i4 < *len; i4++) + /* fleprintf("len = %ld\n", *len); */ + for (NUM i4 = 0; i4 < *len; i4++) { + /* fleprintf("i4 = %ld\n", i4); */ destroy_tuple3(*(tup.array+i4), len+1); + } free(tup.array); } @@ -296,7 +301,7 @@ add_to_tuple_6_pt_2(tuple6 *tup, NUM *len, pair2 label) if (!(((tup->array+label.x)->array+label.y)->initialized)) { SAFE_CALLOC(tuple3, ((tup->array+label.x)->array+label.y)->array, - *(len+1), goto cleanup;); + *(len+2), goto cleanup;); ((tup->array+label.x)->array+label.y)->initialized = 1; } @@ -610,6 +615,7 @@ luple5_free_1(luple5 *lup, NUM label) if (!((tuple->array+label)->initialized)) return; destroy_tuple4(*(tuple->array+label), lup->lengths+1); + /* fleprintf("label = %ld\n", label); */ (tuple->array+label)->initialized = 0; } -- cgit v1.2.3-18-g5258