diff --git a/src/runtime/c/pgf/parser.cxx b/src/runtime/c/pgf/parser.cxx index 09a1a8532..e15426abb 100644 --- a/src/runtime/c/pgf/parser.cxx +++ b/src/runtime/c/pgf/parser.cxx @@ -117,7 +117,8 @@ struct PgfLRTableMaker::Item { } void operator delete(void *p) { - free(p); + if (((Item *) p)->ref_cnt == 0) + free(p); } }; @@ -194,13 +195,11 @@ void PgfLRTableMaker::CCat::register_item(Item *item) { PgfLRTableMaker::CCat::~CCat() { for (Item *item : items) { item->ref_cnt--; - if (item->ref_cnt == 0) - delete item; + delete item; } for (Item *item : suspended) { item->ref_cnt--; - if (item->ref_cnt == 0) - delete item; + delete item; } for (Production *prod : prods) { delete prod; @@ -384,8 +383,8 @@ bool PgfLRTableMaker::CompareKey3::operator() (const Key3& k1, const Key3& k2) c struct PgfLRTableMaker::State { size_t id; - std::vector items; - std::vector completed; + std::vector items; // The seed items for this state + std::vector completed; // Completed items that will become reductions std::map ccats1; std::map ccats2; std::map tokens; @@ -399,14 +398,12 @@ struct PgfLRTableMaker::State { ~State() { for (Item *item : items) { item->ref_cnt--; - if (item->ref_cnt == 0) - delete item; + delete item; } for (Item *item : completed) { item->ref_cnt--; - if (item->ref_cnt == 0) - delete item; + delete item; } } @@ -414,6 +411,12 @@ struct PgfLRTableMaker::State { items.push_back(item); item->ref_cnt++; push_heap(items.begin(), items.end(), compare_item); } + + Item *pop_item() { + Item *item = items.back(); items.pop_back(); + item->ref_cnt--; + return item; + } }; PgfLRTableMaker::PgfLRTableMaker(ref abstr, ref concr) @@ -709,38 +712,62 @@ void PgfLRTableMaker::symbol(State *state, Fold fold, Item *item, PgfSymbol sym) item->ccat->register_item(item); } else { auto symkp = ref::untagged(sym); + Item *new_item1 = NULL; + Item *new_item2 = NULL; for (size_t i = 0; i < symkp->alts.len; i++) { - Item *new_item = new (item) Item; new_item->sym_idx++; ref form = symkp->alts.data[i].form; if (form->syms.len == 0) { - process(state, fold, new_item); + if (!new_item1) { + new_item1 = new (item) Item; + new_item1->sym_idx++; + } + process(state, fold, new_item1); } else { auto &next_state = state->tokens[Key3(form,0)]; if (next_state == NULL) { next_state = new State; } - new_item->stk_size++; - next_state->push_item(new_item); + if (!new_item2) { + new_item2 = new (item) Item; + new_item2->sym_idx++; + new_item2->stk_size++; + } + next_state->push_item(new_item2); } } - Item *new_item = new (item) Item; new_item->sym_idx++; ref form = symkp->default_form; if (form->syms.len == 0) { - process(state, fold, new_item); + if (!new_item1) { + new_item1 = new (item) Item; + new_item1->sym_idx++; + } + process(state, fold, new_item1); } else { auto &next_state = state->tokens[Key3(form,0)]; if (next_state == NULL) { next_state = new State; } - new_item->stk_size++; - next_state->push_item(new_item); + if (!new_item2) { + new_item2 = new (item) Item; + new_item2->sym_idx++; + new_item2->stk_size++; + } + next_state->push_item(new_item2); } + + // If the items are not owned by anyone, we must delete them + if (new_item1 != NULL) + delete new_item1; + if (new_item2 != NULL) + delete new_item2; } } case PgfSymbolBIND::tag: { - if (fold != PROBE) - { + if (fold == PROBE) { + item->ccat->productive = true; + item->ccat->register_item(item); + } else { if (state->bind_state == NULL) { state->bind_state = new State; } @@ -753,33 +780,35 @@ void PgfLRTableMaker::symbol(State *state, Fold fold, Item *item, PgfSymbol sym) } case PgfSymbolSOFTBIND::tag: case PgfSymbolSOFTSPACE::tag: { - if (fold != PROBE) - { + if (fold == PROBE) { + item->ccat->productive = true; + item->ccat->register_item(item); + } else { // SOFT_BIND && SOFT_SPACE also allow a space - item = new (item) Item(); - item->sym_idx++; - process(state,fold,item); + Item *new_item = new (item) Item(); + new_item->sym_idx++; + process(state,fold,new_item); + delete new_item; - // Now we handle the case where there is no space + // Now we handle the case where there is no space. if (state->bind_state == NULL) { state->bind_state = new State; } - item = new (item) Item(); - item->stk_size++; - state->bind_state->push_item(item); + new_item = new (item) Item(); + new_item->stk_size++; + state->bind_state->push_item(new_item); + delete new_item; } break; } case PgfSymbolCAPIT::tag: case PgfSymbolALLCAPIT::tag: { // We just ignore CAPIT && ALLCAPIT during parsing - item->sym_idx++; + item = new (item) Item(); item->sym_idx++; process(state,fold,item); + delete item; break; } - default: - if (item->ref_cnt == 0) - delete item; } } @@ -828,6 +857,8 @@ void PgfLRTableMaker::predict(State *state, Fold fold, Item *item, T cat, predict(state, fold, new_item, cat, index); + delete new_item; + size_t i = n_terms; while (i > 0) { i--; @@ -846,9 +877,6 @@ void PgfLRTableMaker::predict(State *state, Fold fold, Item *item, T cat, break; } } - - if (item->ref_cnt == 0) - delete item; } void PgfLRTableMaker::predict(State *state, Fold fold, Item *item, ref cat, size_t lin_idx) @@ -871,6 +899,7 @@ void PgfLRTableMaker::predict(State *state, Fold fold, Item *item, ref } else if (fold == PROBE && ccat->prods.size() > 0) { Item *new_item = new(item,ccat) Item; process(state,fold,new_item); + delete new_item; } if (fold == PROBE) { @@ -896,6 +925,7 @@ void PgfLRTableMaker::predict(State *state, Fold fold, Item *item, ref if (fold == INIT && ccat->prods.size() > 0) { Item *new_item = new (item, ccat) Item; process(state, fold, new_item); + delete new_item; } } } @@ -916,6 +946,7 @@ void PgfLRTableMaker::predict(State *state, Fold fold, Item *item, CCat *ccat, s Production *prod = ccat->prods[i]; Item *item = new(new_ccat, prod, lin_idx) Item; process(NULL, PROBE, item); + delete item; } } @@ -926,13 +957,13 @@ void PgfLRTableMaker::predict(State *state, Fold fold, Item *item, CCat *ccat, s } } else { if (new_ccat->productive) { - auto &new_state = state->ccats2[Key2(new_ccat,lin_idx)]; - if (new_state == NULL) { - new_state = new State; + auto &next_state = state->ccats2[Key2(new_ccat,lin_idx)]; + if (next_state == NULL) { + next_state = new State; } - new_state->push_item(new(item,lin_idx) Item); + next_state->push_item(new(item,lin_idx) Item); - if (new_state->items.size() == 1) { + if (next_state->items.size() == 1) { for (size_t i = 0; i < new_ccat->items.size(); i++) { process(state, REPEAT, new_ccat->items[i]); } @@ -941,6 +972,7 @@ void PgfLRTableMaker::predict(State *state, Fold fold, Item *item, CCat *ccat, s if (fold == INIT && new_ccat->prods.size() > 0) { Item *new_item = new (item, new_ccat) Item; process(state, fold, new_item); + delete new_item; } } } @@ -958,6 +990,7 @@ void PgfLRTableMaker::predict(ref absfun, CCat *ccat) size_t seq_idx = n_fields * i + ccat->lin_idx; Item *item = new(ccat, lin, seq_idx) Item; process(NULL, PROBE, item); + delete item; } } } @@ -984,12 +1017,10 @@ void PgfLRTableMaker::complete(State *state, Fold fold, Item *item) if (susp != NULL) { Item *new_item = new (susp, item->ccat) Item; process(state, PROBE, new_item); + delete new_item; } } } - - if (item->ref_cnt == 0) - delete item; } else { state->completed.push_back(item); item->ref_cnt++; @@ -1045,7 +1076,7 @@ ref PgfLRTableMaker::make() #endif while (!state->items.empty()) { - Item *item = state->items.back(); state->items.pop_back(); + Item *item = state->pop_item(); #if defined(DEBUG_AUTOMATON) && !defined(DEBUG_STATE_CREATION) // The order in which we process the items should not matter, @@ -1055,9 +1086,8 @@ ref PgfLRTableMaker::make() #endif process(state, INIT, item); - item->ref_cnt--; - if (item->ref_cnt == 0) - delete item; + + delete item; } for (auto &i : state->ccats1) {