diff --git a/Lua/lbp.c b/Lua/lbp.c index 51ba9d2..37d3bb3 100644 --- a/Lua/lbp.c +++ b/Lua/lbp.c @@ -112,41 +112,6 @@ static void push_match(lua_State *L, match_t *m, const char *start) lua_setfield(L, -2, "after"); } -static void recursively_free_pat(pat_t *pat) -{ - // Do a depth-first traversal, freeing everyting along the way: - if (!pat) return; - switch (pat->type) { - case BP_DEFINITION: - recursively_free_pat(pat->args.def.def); - recursively_free_pat(pat->args.def.pat); - break; - case BP_REPEAT: - recursively_free_pat(pat->args.repetitions.sep); - recursively_free_pat(pat->args.repetitions.repeat_pat); - break; - case BP_CHAIN: case BP_UPTO: case BP_UPTO_STRICT: - case BP_OTHERWISE: case BP_NOT_MATCH: case BP_MATCH: - recursively_free_pat(pat->args.multiple.first); - recursively_free_pat(pat->args.multiple.second); - break; - case BP_REPLACE: - recursively_free_pat(pat->args.replace.pat); - break; - case BP_CAPTURE: - recursively_free_pat(pat->args.capture.capture_pat); - break; - case BP_NOT: case BP_AFTER: case BP_BEFORE: - recursively_free_pat(pat->args.pat); - break; - case BP_LEFTRECURSION: - recursively_free_pat(pat->args.leftrec.fallback); - break; - default: break; - } - free_pat(pat); -} - static int Lmatch(lua_State *L) { if (lua_isstring(L, 1)) { @@ -226,7 +191,7 @@ static int Lreplace(lua_State *L) lua_pushinteger(L, replacements); fclose(out); - free_pat(maybe_replacement.value.pat); + delete_pat(&maybe_replacement.value.pat, false); return 2; } @@ -281,8 +246,7 @@ static int Lpat_tostring(lua_State *L) static int Lpat_gc(lua_State *L) { pat_t *pat = lua_touserdata(L, 1); - if (pat) - recursively_free_pat(pat); + if (pat) delete_pat(&pat, true); return 0; } diff --git a/bp.c b/bp.c index f9d1512..73b0469 100644 --- a/bp.c +++ b/bp.c @@ -682,7 +682,7 @@ int main(int argc, char *argv[]) // tracking down memory leaks. free_all_matches(); defs = free_defs(defs, NULL); - free_pat(NULL); + free_all_pats(); while (loaded_files) { file_t *next = loaded_files->next; destroy_file(&loaded_files); diff --git a/match.c b/match.c index 874f60a..5ae9f0f 100644 --- a/match.c +++ b/match.c @@ -531,10 +531,8 @@ static match_t *match(match_ctx_t *ctx, const char *str, pat_t *pat) ctx2.defs = with_def(ctx->defs, m1->pat->args.capture.namelen, m1->pat->args.capture.name, backref); ++m1->refcount; { m2 = match(&ctx2, m1->end, pat->args.multiple.second); - if (!m2) { // No need to keep the backref in memory if it didn't match - free_pat(backref); - backref = NULL; - } + if (!m2) // No need to keep the backref in memory if it didn't match + delete_pat(&backref, false); free_defs(ctx2.defs, ctx->defs); } --m1->refcount; } else { diff --git a/pattern.c b/pattern.c index eef1413..9865c0f 100644 --- a/pattern.c +++ b/pattern.c @@ -52,6 +52,7 @@ static pat_t *new_pat(enum pattype_e type, const char *start, const char *end, s static size_t next_pat_id = 1; pat_t *pat = new(pat_t); *pat = (pat_t){ + .home = &allocated_pats, .next = allocated_pats, .type = type, .start = start, @@ -60,6 +61,7 @@ static pat_t *new_pat(enum pattype_e type, const char *start, const char *end, s .max_matchlen = maxlen, .id = next_pat_id++, }; + if (allocated_pats) allocated_pats->home = &pat->next; allocated_pats = pat; return pat; } @@ -635,24 +637,54 @@ maybe_pat_t bp_pattern(const char *str, const char *end) return (maybe_pat_t){.success = false, .value.error.start = str, .value.error.end = end, .value.error.msg = "Failed to parse this pattern"}; } -void free_pat(pat_t *target) +void free_all_pats(void) { - if (target) { - for (pat_t **rem = &allocated_pats; *rem; rem = &(*rem)->next) { - if ((*rem) == target) { - pat_t *tmp = *rem; - *rem = (*rem)->next; - delete(&tmp); - break; - } - } - } else { - while (allocated_pats) { - pat_t *tofree = allocated_pats; - allocated_pats = tofree->next; - delete(&tofree); - } + while (allocated_pats) { + pat_t *tofree = allocated_pats; + allocated_pats = tofree->next; + delete(&tofree); } } +void delete_pat(pat_t **at_pat, bool recursive) +{ + pat_t *pat = *at_pat; + if (!pat) return; + + if (recursive) { + switch (pat->type) { + case BP_DEFINITION: + delete_pat(&pat->args.def.def, true); + delete_pat(&pat->args.def.pat, true); + break; + case BP_REPEAT: + delete_pat(&pat->args.repetitions.sep, true); + delete_pat(&pat->args.repetitions.repeat_pat, true); + break; + case BP_CHAIN: case BP_UPTO: case BP_UPTO_STRICT: + case BP_OTHERWISE: case BP_NOT_MATCH: case BP_MATCH: + delete_pat(&pat->args.multiple.first, true); + delete_pat(&pat->args.multiple.second, true); + break; + case BP_REPLACE: + delete_pat(&pat->args.replace.pat, true); + break; + case BP_CAPTURE: + delete_pat(&pat->args.capture.capture_pat, true); + break; + case BP_NOT: case BP_AFTER: case BP_BEFORE: + delete_pat(&pat->args.pat, true); + break; + case BP_LEFTRECURSION: + delete_pat(&pat->args.leftrec.fallback, true); + break; + default: break; + } + } + + if (pat->home) *(pat->home) = pat->next; + if (pat->next) pat->next->home = pat->home; + delete(at_pat); +} + // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/pattern.h b/pattern.h index ef08441..3a78f13 100644 --- a/pattern.h +++ b/pattern.h @@ -42,7 +42,7 @@ enum pattype_e { // A struct reperesenting a BP virtual machine operation // typedef struct pat_s { - struct pat_s *next; + struct pat_s *next, **home; enum pattype_e type; const char *start, *end; // The bounds of the match length (used for backtracking) @@ -115,8 +115,9 @@ pat_t *chain_together(pat_t *first, pat_t *second); pat_t *either_pat(pat_t *first, pat_t *second); __attribute__((nonnull)) maybe_pat_t bp_pattern(const char *str, const char *end); - -void free_pat(pat_t *pat); +void free_all_pats(void); +__attribute__((nonnull)) +void delete_pat(pat_t **at_pat, bool recursive); #endif