void ItemSetBuilder::build_successors(const ItemSet& set) { // reset for (auto& item : set.m_closure) item.complete = false; for (auto& item : set.m_closure) { if (item.complete) continue; auto& production = m_grammar.get_production(item.production_id()); auto dot = item.dot(); // skip item whose dot is at right end if (dot >= production.rhs_count()) { item.complete = true; continue; } auto& symbol = production[dot + 1]; // symbol after dot // for each item which has 'symbol' after its dot for (auto& item2 : set.m_closure) { if (item2.complete) continue; auto& production2 = m_grammar.get_production(item2.production_id()); auto dot2 = item2.dot(); if (dot2 >= production2.rhs_count()) { // 'item2' has no successor item2.complete = true; continue; } auto& symbol2 = production2[dot2 + 1]; // symbol after dot if (symbol == symbol2) { // each item becomes complete after contibuting a successor item2.complete = true; auto& add = m_curr_item_set.add_kernel(production2, dot2 + 1); add.lookaheads().resize(m_grammar.symbol_count()); // add backward propagation link auto& new_node = new_link(); new_node->next = add.backward_plink(); add.backward_plink() = new_node; new_node->item = &item2; } } // build set from new kernels auto& new_set = build_item_set(); if (symbol.type() == SymbolType::NONTERMINAL) { auto& act = set.add_action(symbol, ActionType::GOTO, new_set.id()); } else { auto& act = set.add_action(symbol, ActionType::SHIFT, new_set.id()); assert(act.type != ActionType::SSCONFLICT); } } }