void print_items(item_map &items) { for(item_map::iterator iter = items.begin(); iter != items.end(); ++iter) { item_ptr p = iter->second; cout << typeid(*p).name() << '\t' << p->id << "\t[val] " << p->value << " [in] "; if(p->input.empty()) cout << '\t'; for(item_list::iterator in = p->input.begin(); in != p->input.end(); ++in) { cout << (*in)->id << ' '; } cout << "\t[out] "; for(item_list::iterator out = p->output.begin(); out != p->output.end(); ++out) { cout << (*out)->id << ' '; } cout << endl; } }
/// \brief Updates the follow set cache using the content of a particular rule void grammar::fill_follow(const rule& rule, item_map<item_set>::type& dependencies) const { // Empty rules don't change the follow set for anything if (rule.items().size() == 0) return; // Iterate through the items in this rule for (size_t pos=0; pos<rule.items().size(); ++pos) { // Get the current item const item_container& thisItem = rule.items()[pos]; // Terminal items aren't processed by this call (we don't bother to generate follow sets for them) if (thisItem->type() == item::terminal) continue; // Retrieve the follow set for this item item_set_map::iterator followSet = m_CachedFollowSets.find(thisItem); if (followSet == m_CachedFollowSets.end()) { followSet = m_CachedFollowSets.insert(item_set_map::value_type(thisItem, item_set(this))).first; } // The follow set of this item is the combination of the first sets for all of the following items // If it's at the end, it also includes the follow set for the nonterminal for this rule size_t nextPos = pos+1; for (;nextPos < rule.items().size(); ++nextPos) { // Get this following item const item_container& followingItem = rule.items()[nextPos]; // Get the set FIRST(followingItem) const item_set& firstSet = first(followingItem); // Add to the follow set followSet->second.merge(firstSet); // Finished if the first set doesn't include the empty set if (!firstSet.contains(an_empty_item_c)) break; } // If we reach the end, then we need to include FOLLOW(rule.nonterminal) in the set for FOLLOW(thisItem) if (nextPos >= rule.items().size()) { item_set_map::iterator depend = dependencies.find(thisItem); if (depend == dependencies.end()) { depend = dependencies.insert(item_map<item_set>::type::value_type(thisItem, item_set(this))).first; } depend->second.insert(rule.nonterminal()); } // If this item is an EBNF rule, then we need to process each of its children const ebnf* ebnfItem = thisItem->cast_ebnf(); if (ebnfItem) { for (ebnf::rule_iterator subRule = ebnfItem->first_rule(); subRule != ebnfItem->last_rule(); ++subRule) { fill_follow(**subRule, dependencies); } } } }