This commit is contained in:
IlyaShurupov 2024-02-06 09:27:49 +03:00 committed by Ilya Shurupov
parent fb8202f385
commit 184f8dd1fe
6 changed files with 128 additions and 71 deletions

View file

@ -8,9 +8,8 @@
namespace tp { namespace tp {
// Non-Deterministic Finite-State Automata // Non-Deterministic Finite-State Automata
template <typename tAlphabetType, typename tStateType, tStateType tNoStateVal, tStateType tFailedStateVal> template <typename tAlphabetType, typename tStateType>
class NFA { class NFA {
static_assert(TypeTraits<tAlphabetType>::isIntegral, "tAlphabetType must be enumerable.");
public: public:
struct Vertex; struct Vertex;
@ -32,7 +31,8 @@ namespace tp {
struct Vertex { struct Vertex {
List<Edge> edges; List<Edge> edges;
tStateType termination_state = tNoStateVal; tStateType state{};
bool isTermination = false;
ualni debug_idx = 0; ualni debug_idx = 0;
ualni flag = 0; ualni flag = 0;
}; };
@ -40,12 +40,15 @@ namespace tp {
public: public:
List<Vertex> mVertices; List<Vertex> mVertices;
Vertex* mStart = nullptr; Vertex* mStart = nullptr;
Buffer<tAlphabetType> mAllSymbols;
public: public:
NFA() = default; NFA() = default;
Vertex* addVertex() { Vertex* addVertex(const tStateType& state, bool termination) {
auto node = mVertices.newNode(); auto node = mVertices.newNode();
node->data.isTermination = termination;
node->data.state = state;
node->data.debug_idx = mVertices.length() + 1; node->data.debug_idx = mVertices.length() + 1;
mVertices.pushBack(node); mVertices.pushBack(node);
return &node->data; return &node->data;
@ -66,7 +69,10 @@ namespace tp {
[[nodiscard]] Vertex* getStartVertex() const { return mStart; } [[nodiscard]] Vertex* getStartVertex() const { return mStart; }
void setVertexState(Vertex* vertex, tStateType state) { vertex->termination_state = state; } void setVertexState(Vertex* vertex, const tStateType& state, bool terminated) {
vertex->state = state;
vertex->isTermination = terminated;
}
[[nodiscard]] bool isValid() const { [[nodiscard]] bool isValid() const {
if (!mStart) { if (!mStart) {
@ -75,27 +81,6 @@ namespace tp {
return true; return true;
} }
Range<tAlphabetType> getAlphabetRange() const {
tAlphabetType start = 0, end = 0;
Range<tAlphabetType> all_range(
std::numeric_limits<tAlphabetType>::min(), std::numeric_limits<tAlphabetType>::max()
);
bool first = true;
for (auto vertex : mVertices) {
for (auto edge : vertex.data().edges) {
if (!edge.data().mConsumesSymbol) continue;
auto const& tran_range = edge.data().mAcceptingRange;
if (edge.data().mAcceptsAll || edge.data().mExclude) return all_range;
if (tran_range.mBegin < start || first) start = tran_range.mBegin;
if (tran_range.mEnd > end || first) end = tran_range.mEnd;
first = false;
}
}
return Range<tAlphabetType>(start, end + 1);
}
// vertices that are reachable from initial set with no input consumption (E-transitions) // vertices that are reachable from initial set with no input consumption (E-transitions)
// does not include initial set // does not include initial set
void closure(const List<Vertex*>& set, List<Vertex*>& closure, ualni unique_call_id) { void closure(const List<Vertex*>& set, List<Vertex*>& closure, ualni unique_call_id) {
@ -133,10 +118,9 @@ namespace tp {
}; };
// Deterministic Finite-State Automata // Deterministic Finite-State Automata
template <typename tAlphabetType, typename tStateType, tStateType tNoStateVal, tStateType tFailedStateVal> template <typename tAlphabetType, typename tStateType>
class DFA { class DFA {
static_assert(TypeTraits<tAlphabetType>::isIntegral, "tAlphabetType must be enumerable."); public:
struct Vertex { struct Vertex {
struct Edge { struct Edge {
Vertex* vertex = nullptr; Vertex* vertex = nullptr;
@ -144,25 +128,26 @@ namespace tp {
}; };
List<Edge> edges; List<Edge> edges;
tStateType termination_state = tNoStateVal; tStateType state{};
bool termination = false;
bool marked = false; bool marked = false;
}; };
List<Vertex> mVertices; List<Vertex> mVertices;
Vertex* mStart = nullptr; Vertex* mStart = nullptr;
const Vertex* mIter = nullptr; const Vertex* mIter = nullptr;
Range<tAlphabetType> mAlphabetRange; Buffer<tAlphabetType> mAlphabetRange;
bool mTrapState = false; bool mTrapState = false;
typedef typename NFA<tAlphabetType, tStateType, tNoStateVal, tFailedStateVal>::Vertex NState; typedef typename NFA<tAlphabetType, tStateType>::Vertex NState;
public: public:
explicit DFA(NFA<tAlphabetType, tStateType, tNoStateVal, tFailedStateVal>& nfa) { explicit DFA(NFA<tAlphabetType, tStateType>& nfa) {
if (!nfa.isValid()) { if (!nfa.isValid()) {
return; return;
} }
mAlphabetRange = nfa.getAlphabetRange(); mAlphabetRange = nfa.mAllSymbols;
struct DStateKey { struct DStateKey {
const List<NState*>* nStates; const List<NState*>* nStates;
@ -269,14 +254,19 @@ namespace tp {
// create own vertices // create own vertices
for (auto node : dStates) { for (auto node : dStates) {
tStateType state = tNoStateVal; const tStateType* state = nullptr;
ualni numFound = 0;
for (auto iter : node->val->nStates) { for (auto iter : node->val->nStates) {
if (iter->termination_state != tNoStateVal) { if (iter->isTermination) {
state = iter->termination_state; state = &iter->state;
break; break;
} }
} }
node->val->dVertex = addVertex(state); if (numFound != 1) {
printf("Error constructing dfa - invalid number of termination states in final node.");
exit(1);
}
node->val->dVertex = addVertex(*state);
} }
// connect all vertices // connect all vertices
@ -295,9 +285,9 @@ namespace tp {
} }
collapseEquivalentVertices(); collapseEquivalentVertices();
mAlphabetRange = getAlphabetRange();
} }
/*
tStateType move(tAlphabetType symbol) { tStateType move(tAlphabetType symbol) {
if (mTrapState || !mIter) { if (mTrapState || !mIter) {
return tNoStateVal; return tNoStateVal;
@ -318,10 +308,11 @@ namespace tp {
mIter = mStart; mIter = mStart;
mTrapState = false; mTrapState = false;
} }
*/
[[nodiscard]] uhalni nVertices() const { return (uhalni) mVertices.length(); } [[nodiscard]] uhalni nVertices() const { return (uhalni) mVertices.length(); }
[[nodiscard]] Range<tAlphabetType> getRange() const { return mAlphabetRange; } [[nodiscard]] const Buffer<tAlphabetType>& getRange() const { return mAlphabetRange; }
public: public:
[[nodiscard]] Range<tAlphabetType> getAlphabetRange() const { [[nodiscard]] Range<tAlphabetType> getAlphabetRange() const {
@ -363,9 +354,9 @@ namespace tp {
// TODO // TODO
} }
Vertex* addVertex(tStateType state) { Vertex* addVertex(const tStateType& state) {
auto node = mVertices.addNodeBack(); auto node = mVertices.addNodeBack();
node->data.termination_state = state; node->data.state = state;
return &node->data; return &node->data;
} }

View file

@ -1,10 +1,33 @@
#pragma once #pragma once
#include "Automata.hpp"
#include "Grammar.hpp" #include "Grammar.hpp"
namespace tp { namespace tp {
template <typename tAlphabetType, typename tStateType, tStateType tNoStateVal, tStateType tFailedStateVal> class ContextFreeCompiler {
class RegularCompiler {}; typedef ContextFreeGrammar Grammar;
public:
// Terminals or non terminals
struct Alphabet {
String mId;
bool mIsTerminal = false;
};
struct Item {
Grammar::Rule mRule;
ualni mAdvanceIdx;
};
typedef NFA<Alphabet, Item> NFA;
typedef typename NFA::Vertex State;
public:
void compile(const Grammar& in, NFA& out) { nfa = &out; }
private:
NFA* nfa = nullptr;
};
} }

View file

@ -3,6 +3,7 @@
#include "AST.hpp" #include "AST.hpp"
#include "RegularCompiler.hpp" #include "RegularCompiler.hpp"
#include "ContextFreeCompiler.hpp"
namespace tp { namespace tp {
@ -10,9 +11,13 @@ namespace tp {
class Parser { class Parser {
typedef TransitionMatrix<tAlphabetType, TokenType, TokenType::InTransition, TokenType::Failed> RegularTable; typedef TransitionMatrix<tAlphabetType, TokenType, TokenType::InTransition, TokenType::Failed> RegularTable;
typedef DFA<tAlphabetType, TokenType, TokenType::InTransition, TokenType::Failed> RegularGraph; typedef DFA<tAlphabetType, TokenType> RegularGraph;
typedef RegularCompiler<tAlphabetType, TokenType, TokenType::InTransition, TokenType::Failed> RegularCompiler; typedef RegularCompiler<tAlphabetType, TokenType, TokenType::InTransition, TokenType::Failed> RegularCompiler;
typedef NFA<tAlphabetType, TokenType, TokenType::InTransition, TokenType::Failed> RegularNonDetGraph; typedef NFA<tAlphabetType, TokenType> RegularNonDetGraph;
// ContextFreeCompiler::Alphabet PushDownTable;
typedef DFA<ContextFreeCompiler::Alphabet, ContextFreeCompiler::Item> ContextFreeDFA;
typedef ContextFreeCompiler::NFA ContextFreeNFA;
public: public:
Parser() = default; Parser() = default;
@ -28,6 +33,15 @@ namespace tp {
RegularGraph dfa(nfa); RegularGraph dfa(nfa);
mRegularTable.construct(dfa); mRegularTable.construct(dfa);
} }
// compile context free grammar
{
ContextFreeNFA nfa;
ContextFreeCompiler compiler;
compiler.compile(cfGrammar, nfa);
ContextFreeDFA dfa(nfa);
}
} }
void parse(const tAlphabetType* sentence, ualni sentenceLength, AST& out) {} void parse(const tAlphabetType* sentence, ualni sentenceLength, AST& out) {}

View file

@ -7,9 +7,6 @@
namespace tp { namespace tp {
template <typename tAlphabetType, typename tStateType, tStateType tNoStateVal, tStateType tFailedStateVal>
class TransitionMatrix;
template <typename tAlphabetType, typename tStateType, tStateType tNoStateVal, tStateType tFailedStateVal> template <typename tAlphabetType, typename tStateType, tStateType tNoStateVal, tStateType tFailedStateVal>
class TransitionMatrix { class TransitionMatrix {
@ -30,8 +27,8 @@ namespace tp {
auto getTransitions() const { return &mTransitions; } auto getTransitions() const { return &mTransitions; }
auto getStart() const { return mStart; } auto getStart() const { return mStart; }
void construct(const DFA<tAlphabetType, tStateType, tNoStateVal, tFailedStateVal>& dfa) { void construct(const DFA<tAlphabetType, tStateType>& dfa) {
mSymbolRange = dfa.getRange(); mSymbolRange = { dfa.getRange().first(), dfa.getRange().last() };
auto range_len = ualni(mSymbolRange.mEnd - mSymbolRange.mBegin); auto range_len = ualni(mSymbolRange.mEnd - mSymbolRange.mBegin);
auto sizeX = range_len ? range_len : 1; auto sizeX = range_len ? range_len : 1;
auto sizeY = (ualni) (dfa.nVertices() + 1); auto sizeY = (ualni) (dfa.nVertices() + 1);
@ -42,7 +39,7 @@ namespace tp {
ualni idx = 0; ualni idx = 0;
for (auto vertex : dfa.mVertices) { for (auto vertex : dfa.mVertices) {
auto state = vertex.data().termination_state; auto state = vertex.data().termination ? vertex.data().state : tNoStateVal;
mStates[idx] = state; mStates[idx] = state;
idx++; idx++;
} }

View file

@ -9,7 +9,7 @@ namespace tp {
template <typename tAlphabetType, typename tStateType, tStateType tNoStateVal, tStateType tFailedStateVal> template <typename tAlphabetType, typename tStateType, tStateType tNoStateVal, tStateType tFailedStateVal>
class RegularCompiler { class RegularCompiler {
typedef NFA<tAlphabetType, tStateType, tNoStateVal, tFailedStateVal> Graph; typedef NFA<tAlphabetType, tStateType> Graph;
typedef typename Graph::Vertex Vertex; typedef typename Graph::Vertex Vertex;
typedef RegularGrammar<tAlphabetType, tStateType> Grammar; typedef RegularGrammar<tAlphabetType, tStateType> Grammar;
@ -31,16 +31,17 @@ namespace tp {
CompileError mError; CompileError mError;
Node compile(Graph& graph, const tAlphabetType* regex, tStateType state) { void compile(Graph& graph, const tAlphabetType* regex, tStateType state) {
mGraph = &graph; mGraph = &graph;
return compileUtil(regex, state); compileUtil(regex, state);
setAlphabet();
} }
Node compile(Graph& aGraph, const Grammar& grammar) { void compile(Graph& aGraph, const Grammar& grammar) {
mGraph = &aGraph; mGraph = &aGraph;
auto left = mGraph->addVertex(); auto left = addVertex();
auto right = mGraph->addVertex(); auto right = addVertex();
halni idx = 0; halni idx = 0;
for (auto rule : grammar.mRules) { for (auto rule : grammar.mRules) {
@ -49,7 +50,7 @@ namespace tp {
if (!(node.left && node.right)) { if (!(node.left && node.right)) {
mError.mRuleIndex = idx; mError.mRuleIndex = idx;
return {}; return;
} }
transitionAny(left, node.left); transitionAny(left, node.left);
@ -60,7 +61,7 @@ namespace tp {
mGraph->setStartVertex(left); mGraph->setStartVertex(left);
return { left, right }; setAlphabet();
} }
private: private:
@ -68,15 +69,15 @@ namespace tp {
auto node = compileNode(astNode, nullptr, nullptr); auto node = compileNode(astNode, nullptr, nullptr);
mGraph->setVertexState(node.right, state); mGraph->setVertexState(node.right, state, true);
mGraph->setStartVertex(node.left); mGraph->setStartVertex(node.left);
return node; return node;
} }
Node compileVal(Grammar::ValueNode* val, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) { Node compileVal(Grammar::ValueNode* val, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) {
auto left = aLeft ? aLeft : mGraph->addVertex(); auto left = aLeft ? aLeft : addVertex();
auto right = aRight ? aRight : mGraph->addVertex(); auto right = aRight ? aRight : addVertex();
transitionVal(left, right, val->mVal); transitionVal(left, right, val->mVal);
return { left, right }; return { left, right };
} }
@ -90,15 +91,15 @@ namespace tp {
} }
Node compileAny(const Grammar::AnyNode*, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) { Node compileAny(const Grammar::AnyNode*, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) {
auto left = aLeft ? aLeft : mGraph->addVertex(); auto left = aLeft ? aLeft : addVertex();
auto right = aRight ? aRight : mGraph->addVertex(); auto right = aRight ? aRight : addVertex();
transitionAny(left, right, true); transitionAny(left, right, true);
return { left, right }; return { left, right };
} }
Node compileRepeat(const Grammar::RepetitionNode* repeat, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) { Node compileRepeat(const Grammar::RepetitionNode* repeat, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) {
if (repeat->mPlus) { if (repeat->mPlus) {
auto middle = mGraph->addVertex(); auto middle = addVertex();
auto left_node = compileNode(repeat->mNode, aLeft, middle); auto left_node = compileNode(repeat->mNode, aLeft, middle);
@ -122,8 +123,8 @@ namespace tp {
} }
Node compileClass(const Grammar::ClassNode* node, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) { Node compileClass(const Grammar::ClassNode* node, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) {
auto left = aLeft ? aLeft : mGraph->addVertex(); auto left = aLeft ? aLeft : addVertex();
auto right = aRight ? aRight : mGraph->addVertex(); auto right = aRight ? aRight : addVertex();
if (node->mRanges.size() == 1) { if (node->mRanges.size() == 1) {
auto const& range = node->mRanges.first(); auto const& range = node->mRanges.first();
@ -132,7 +133,7 @@ namespace tp {
} }
for (auto range : node->mRanges) { for (auto range : node->mRanges) {
auto middle = mGraph->addVertex(); auto middle = addVertex();
transitionRange(left, middle, { range.data().mBegin, range.data().mEnd }, node->mExclude); transitionRange(left, middle, { range.data().mBegin, range.data().mEnd }, node->mExclude);
transitionAny(middle, right); transitionAny(middle, right);
} }
@ -182,5 +183,36 @@ namespace tp {
void transitionRange(Vertex* from, Vertex* to, Range<tAlphabetType> range, bool exclude) { void transitionRange(Vertex* from, Vertex* to, Range<tAlphabetType> range, bool exclude) {
mGraph->addTransition(from, to, range, true, false, exclude); mGraph->addTransition(from, to, range, true, false, exclude);
} }
Vertex* addVertex() { return mGraph->addVertex(tNoStateVal, false); }
private:
Range<tAlphabetType> getAlphabetRange() const {
tAlphabetType start = 0, end = 0;
Range<tAlphabetType> all_range(
std::numeric_limits<tAlphabetType>::min(), std::numeric_limits<tAlphabetType>::max()
);
bool first = true;
for (auto vertex : mGraph->mVertices) {
for (auto edge : vertex.data().edges) {
if (!edge.data().mConsumesSymbol) continue;
auto const& tran_range = edge.data().mAcceptingRange;
if (edge.data().mAcceptsAll || edge.data().mExclude) return all_range;
if (tran_range.mBegin < start || first) start = tran_range.mBegin;
if (tran_range.mEnd > end || first) end = tran_range.mEnd;
first = false;
}
}
return Range<tAlphabetType>(start, end + 1);
}
void setAlphabet() {
auto range = getAlphabetRange();
for (auto iter : range) {
mGraph->mAllSymbols.append(iter);
}
}
}; };
} }

View file

@ -100,8 +100,8 @@ namespace tp {
inline const Iterator& operator*() { return *this; } inline const Iterator& operator*() { return *this; }
}; };
tType mBegin = 0; tType mBegin{};
tType mEnd = 0; tType mEnd{};
Range() = default; Range() = default;