From 0e4f4228de9d8f1a621371dcb61148f313ede991 Mon Sep 17 00:00:00 2001 From: IlushaShurupov Date: Sat, 12 Aug 2023 09:09:46 +0300 Subject: [PATCH] Checking for non productive rules and loops in cfg --- Parser/private/CfGrammar.cpp | 13 +++++++++++++ Parser/private/Parser.cpp | 1 + Parser/public/CfGrammar.hpp | 26 ++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/Parser/private/CfGrammar.cpp b/Parser/private/CfGrammar.cpp index b2e4b6f..cd925ad 100644 --- a/Parser/private/CfGrammar.cpp +++ b/Parser/private/CfGrammar.cpp @@ -145,5 +145,18 @@ bool CfGrammar::compile() { rules.removeNode(rules.find(*rule.data())); } } + + for (auto nonTerminal : mNonTerminals) { + if (!nonTerminal->val.isProductive()) { + printf("Non-terminal '%s' is not productive\n", nonTerminal->val.rules.first()->data->id.read()); + return false; + } + } + + Map processed; + if (mNonTerminals.get(startTerminal).isLooped(processed, startTerminal)) { + printf("Note that grammar is looped.\n"); + } + return true; } \ No newline at end of file diff --git a/Parser/private/Parser.cpp b/Parser/private/Parser.cpp index 3f8ad9e..61d09bb 100644 --- a/Parser/private/Parser.cpp +++ b/Parser/private/Parser.cpp @@ -1,3 +1,4 @@ +#include "NewPlacement.hpp" #include "Parser.hpp" #include "Tokenizer.hpp" diff --git a/Parser/public/CfGrammar.hpp b/Parser/public/CfGrammar.hpp index e33db89..f61d9f9 100644 --- a/Parser/public/CfGrammar.hpp +++ b/Parser/public/CfGrammar.hpp @@ -24,6 +24,13 @@ namespace tp { bool operator==(const Rule& in) const { return (id == in.id) && (args == in.args); } + + [[nodiscard]] bool isProductive() const { + for (auto arg : args) { + if (arg->id == id) return false; + } + return true; + } }; struct Sentence { @@ -42,9 +49,28 @@ namespace tp { private: struct NonTerminal { + List rules; Map references; Map referencing; + + [[nodiscard]] bool isProductive() const { + for (auto rule : rules) { + if (rule->isProductive()) return true; + } + return false; + } + + [[nodiscard]] bool isLooped(Map& processed, const String& id) const { + for (auto ref : referencing) { + if (processed.presents(ref->key)) return true; + } + processed.put(id, {}); + for (auto ref : referencing) { + if (ref->val->isLooped(processed, ref->key)) return true; + } + return false; + } }; struct Terminal {};