コード例 #1
0
ファイル: grammar.cpp プロジェクト: Logicalshift/TameParse
/// \brief Computes the first set for the specified rule (or retrieves the cached version)
item_set grammar::first_for_rule(const rule& rule) const {
    // Return a set containing only the empty item if the rule is 0 items long
    if (rule.items().size() == 0) {
        return *m_EpsilonSet;
    }
    
    // Return the first set of the first item in the rule
    item_set result(this);
    for (size_t itemId = 0; itemId < rule.items().size(); ++itemId) {
        // Remove the epsilon item from the set
        result.erase(an_empty_item_c);

        // Add the items in the first set for this item
        result.merge(first(*rule.items()[itemId]));

        // If the result doesn't contain the empty item, then return it
        if (!result.contains(an_empty_item_c)) {
            return result;
        }
    }

    // The empty item is included
    result.insert(an_empty_item_c);
    return result;
}
コード例 #2
0
ファイル: grammar.cpp プロジェクト: Logicalshift/TameParse
/// \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);
            }
        }
    }
}