diff options
Diffstat (limited to 'bnf.cpp')
-rw-r--r-- | bnf.cpp | 53 |
1 files changed, 53 insertions, 0 deletions
@@ -68,6 +68,59 @@ BNF SubBNF(const BNF& bnf, const std::string& top) return result; } +namespace { + + bool isHeadRecursive(const std::vector<std::string>& list, const std::string& symbol) { + if (list.size() > 0 && list[0] == symbol) + return true; + return false; + } + + bool isHeadRecursive(const std::vector<std::vector<std::string>>& lists, const std::string& symbol) { + for (const auto& list: lists) { + if (isHeadRecursive(list, symbol)) + return true; + } + return false; + } + +} // anonymous namespace + +// Change head recursion to tail recursion +BNF removeHeadRecursion(const BNF& bnf) +{ + std::unordered_map<std::string, std::vector<std::vector<std::string>>> result; + + for (const auto& [from, to]: bnf) { + if (isHeadRecursive(to, from)) { // modify rule by adding additional one + std::string from_ext = from + "-ext"; + if (bnf.find(from_ext) != bnf.end()) + throw std::runtime_error("ICE: Symbol "s + from_ext + " already exists in original BNF"); + + std::vector<std::vector<std::string>> to_new; + std::vector<std::vector<std::string>> to_ext{{}}; // starts with empty list as first element + for (const auto& list: to) { + if (isHeadRecursive(list, from)) { + std::vector<std::string> list_new{list.begin() + 1, list.end()}; + list_new.push_back(from_ext); + to_ext.push_back(list_new); + } else { + std::vector<std::string> list_new{list.begin(), list.end()}; + list_new.push_back(from_ext); + to_new.push_back(list_new); + } + } + + result[from] = to_new; + result[from_ext] = to_ext; + } else { // just add + result[from] = to; + } + } + + return result; +} + bool isTerminal(const BNF& bnf, const std::string& symbol) { return bnf.find(symbol) == bnf.end(); |