CFG compiler ini

This commit is contained in:
IlyaShurupov 2024-02-08 09:54:24 +03:00 committed by Ilya Shurupov
parent 70b6bf4d77
commit b883f0029c
5 changed files with 154 additions and 46 deletions

View file

@ -29,24 +29,6 @@ bool ContextFreeGrammar::Rule::isProductive() const {
return true; return true;
} }
bool ContextFreeGrammar::NonTerminal::isProductive() const {
for (auto rule : rules) {
if (rule->isProductive()) return true;
}
return false;
}
bool ContextFreeGrammar::NonTerminal::isLooped(Map<String, ualni>& 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;
}
void ContextFreeGrammar::addRule(const Rule& rule) { mRules.append(rule); } void ContextFreeGrammar::addRule(const Rule& rule) { mRules.append(rule); }
void ContextFreeGrammar::addRule(const String& id, const InitialierList<Arg>& args) { addRule(Rule(id, args)); } void ContextFreeGrammar::addRule(const String& id, const InitialierList<Arg>& args) { addRule(Rule(id, args)); }

View file

@ -7,27 +7,149 @@
namespace tp { namespace tp {
class ContextFreeCompiler { class ContextFreeCompiler {
typedef ContextFreeGrammar Grammar;
public: typedef ualni SymbolID;
// Terminals or non terminals
struct Alphabet { struct Symbol {
String mId; String mId;
bool mIsTerminal = false; bool mIsTerminal = false;
}; };
struct Item { struct Item {
Grammar::Rule mRule; const ContextFreeGrammar::Rule* mRule = nullptr;
ualni mAdvanceIdx = 0; ualni mAdvanceIdx = 0;
}; };
typedef FiniteStateAutomation<Alphabet, Item> NFA; struct NonTerminal {
typedef typename NFA::State State; Buffer<ContextFreeGrammar::Rule*> rules;
Map<String, NonTerminal*> references;
Map<String, NonTerminal*> referencing;
public: public:
void compile(const Grammar& in, NFA& out) { nfa = &out; } [[nodiscard]] bool isProductive() const {
for (auto rule : rules) {
if (rule->isProductive()) return true;
}
return false;
}
[[nodiscard]] bool isLooped(Map<String, ualni>& 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;
}
};
public:
bool compile(const ContextFreeGrammar& grammar, FiniteStateAutomation<SymbolID, Item>& automata) {
if (!init(grammar)) return false;
return true;
}
private: private:
NFA* nfa = nullptr; bool init(const ContextFreeGrammar& grammar) {
if (!grammar.getRules()->size()) {
return false;
}
for (auto rule : *grammar.getRules()) {
if (!rule->getArgs()->size()) {
return false;
}
}
findNonTerminals(grammar);
for (auto nonTerminal : mNonTerminals) {
for (auto rule : nonTerminal->val.rules) {
for (auto arg : *rule->getArgs()) {
if (arg->isTerminal() || arg->isEpsilon()) continue;
if (!mNonTerminals.presents(arg->getId())) {
printf("Referenced non-terminal '%s' is not defined\n", arg->getId().read());
return false;
}
}
}
}
findAllReferences(grammar);
for (auto nonTerminal : mNonTerminals) {
if (!nonTerminal->val.references.size() && nonTerminal->key != grammar.getStartTerminal()) {
printf("Non-terminal '%s' is defined but not used\n", nonTerminal->key.read());
return false;
}
}
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<String, ualni> processed;
if (mNonTerminals.get(grammar.getStartTerminal()).isLooped(processed, grammar.getStartTerminal())) {
printf("Note that grammar is looped.\n");
return false;
}
initSymbols(grammar);
}
void findNonTerminals(const ContextFreeGrammar& grammar) {
for (auto rule : *grammar.getRules()) {
if (!mNonTerminals.presents(rule->getId())) {
mNonTerminals.put(rule->getId(), {});
}
auto nonTerminal = &mNonTerminals.get(rule->getId());
nonTerminal->rules.append(&rule.data());
}
}
void findAllReferences(const ContextFreeGrammar& grammar) {
for (auto nonTerminal : mNonTerminals) {
for (auto rule : nonTerminal->val.rules) {
for (auto arg : *rule->getArgs()) {
if (arg->isTerminal() || arg->isEpsilon()) continue;
NonTerminal* reference = &mNonTerminals.get(arg->getId());
nonTerminal->val.referencing.put(arg->getId(), reference);
reference->references.put(nonTerminal->key, &nonTerminal->val);
}
}
}
}
void initSymbols(const ContextFreeGrammar& grammar) {
for (auto nonTerminal : mNonTerminals) {
mSymbols.append({ nonTerminal->key, false });
mSymbolLookup.put(nonTerminal->key, SymbolID(mSymbols.size() - 1));
for (auto rule : nonTerminal->val.rules) {
for (auto arg : *rule->getArgs()) {
if (arg->isEpsilon() || arg->isTerminal()) continue;
if (mTerminals.presents(arg->getId())) continue;
mTerminals.put(arg->getId(), {});
mSymbols.append({ nonTerminal->key, true });
mSymbolLookup.put(nonTerminal->key, SymbolID(mSymbols.size() - 1));
}
}
}
}
private:
Map<String, NonTerminal> mNonTerminals;
Map<String, bool> mTerminals;
Buffer<Symbol> mSymbols;
Map<String, SymbolID> mSymbolLookup;
}; };
} }

View file

@ -20,6 +20,8 @@ namespace tp {
public: public:
bool operator==(const Arg& in) const; bool operator==(const Arg& in) const;
[[nodiscard]] const String& getId() const; [[nodiscard]] const String& getId() const;
[[nodiscard]] bool isTerminal() const { return mIsTerminal; }
[[nodiscard]] bool isEpsilon() const { return mIsEpsilon; }
private: private:
String mId; String mId;
@ -35,24 +37,14 @@ namespace tp {
public: public:
bool operator==(const Rule& in) const; bool operator==(const Rule& in) const;
[[nodiscard]] bool isProductive() const; [[nodiscard]] bool isProductive() const;
[[nodiscard]] const String& getId() const { return mId; }
[[nodiscard]] const Buffer<Arg>* getArgs() const { return &mArgs; }
private: private:
String mId; String mId;
Buffer<Arg> mArgs; Buffer<Arg> mArgs;
}; };
private:
// cache data
struct NonTerminal {
Buffer<Rule*> rules;
Map<String, NonTerminal*> references;
Map<String, NonTerminal*> referencing;
public:
[[nodiscard]] bool isProductive() const;
[[nodiscard]] bool isLooped(Map<String, ualni>& processed, const String& id) const;
};
public: public:
ContextFreeGrammar() = default; ContextFreeGrammar() = default;
@ -60,9 +52,11 @@ namespace tp {
void addRule(const Rule& rule); void addRule(const Rule& rule);
void addRule(const String& id, const InitialierList<Arg>& args); void addRule(const String& id, const InitialierList<Arg>& args);
void setStart(const String& startRule); void setStart(const String& startRule);
[[nodiscard]] const Buffer<Rule>* getRules() const { return &mRules; }
[[nodiscard]] bool isValid() const { return false; }
[[nodiscard]] const String& getStartTerminal() const { return mStartTerminal; }
private: public:
Map<String, NonTerminal> mNonTerminals;
Buffer<Rule> mRules; Buffer<Rule> mRules;
String mStartTerminal; String mStartTerminal;
bool mIsLooped = false; bool mIsLooped = false;

View file

@ -21,16 +21,20 @@ namespace tp {
// ContextFreeGrammar; // ContextFreeGrammar;
// ContextFreeCompiler; // ContextFreeCompiler;
typedef FiniteStateAutomation<ContextFreeCompiler::Alphabet, ContextFreeCompiler::Item> ContextFreeGraph; typedef FiniteStateAutomation<ContextFreeCompiler::SymbolID, ContextFreeCompiler::Item> ContextFreeGraph;
typedef ContextFreeAutomata<ContextFreeCompiler::Alphabet, ContextFreeCompiler::Item> ContextFreeAutomata; typedef ContextFreeAutomata<ContextFreeCompiler::SymbolID, ContextFreeCompiler::Item> ContextFreeAutomata;
public: public:
Parser() = default; Parser() = default;
public: public:
void compileTables(const ContextFreeGrammar& cfGrammar, const RegularGrammar& reGrammar) { bool compileTables(const ContextFreeGrammar& cfGrammar, const RegularGrammar& reGrammar) {
// Compile Regular Grammar // Compile Regular Grammar
{ {
if (!reGrammar.isValid()) {
return false;
}
RegularGraph graph; RegularGraph graph;
RegularCompiler compiler; RegularCompiler compiler;
compiler.compile(graph, reGrammar); compiler.compile(graph, reGrammar);
@ -40,12 +44,18 @@ namespace tp {
// compile context free grammar // compile context free grammar
{ {
if (!cfGrammar.isValid()) {
return false;
}
ContextFreeGraph graph; ContextFreeGraph graph;
ContextFreeCompiler compiler; ContextFreeCompiler compiler;
compiler.compile(cfGrammar, graph); compiler.compile(cfGrammar, graph);
graph.makeDeterministic(); graph.makeDeterministic();
mContextFreeAutomata.construct(graph); mContextFreeAutomata.construct(graph);
} }
return true;
} }
void parse(const tAlphabetType* sentence, ualni sentenceLength, AST& out) {} void parse(const tAlphabetType* sentence, ualni sentenceLength, AST& out) {}

View file

@ -55,7 +55,7 @@ namespace tp {
} }
private: private:
Parser<tAlphabetType, UGTokens> mUnifiedGrammarParser; Parser<tAlphabetType, UGTokens, 0, 127> mUnifiedGrammarParser;
Parser<tAlphabetType, UGTokens> mUserParser; Parser<tAlphabetType, UGTokens, 0, 127> mUserParser;
}; };
} }