From fb8202f385c657aeb1f036c30931c8058e8fbb0e Mon Sep 17 00:00:00 2001 From: IlyaShurupov Date: Mon, 5 Feb 2024 22:49:50 +0300 Subject: [PATCH] tmp --- Language/public/Automata.hpp | 376 +++++++++++++++++ Language/public/ContextFreeCompiler.hpp | 10 + Language/public/Parser.hpp | 2 +- Language/public/RegularAutomata.hpp | 386 +----------------- ...rammarCompiler.hpp => RegularCompiler.hpp} | 0 5 files changed, 388 insertions(+), 386 deletions(-) create mode 100644 Language/public/Automata.hpp create mode 100644 Language/public/ContextFreeCompiler.hpp rename Language/public/{GrammarCompiler.hpp => RegularCompiler.hpp} (100%) diff --git a/Language/public/Automata.hpp b/Language/public/Automata.hpp new file mode 100644 index 0000000..2ac7924 --- /dev/null +++ b/Language/public/Automata.hpp @@ -0,0 +1,376 @@ + +#pragma once + +#include "Utils.hpp" +#include "List.hpp" +#include "Map.hpp" + +namespace tp { + + // Non-Deterministic Finite-State Automata + template + class NFA { + static_assert(TypeTraits::isIntegral, "tAlphabetType must be enumerable."); + + public: + struct Vertex; + + struct Edge { + Vertex* mVertex = nullptr; + bool mConsumesSymbol = false; + Range mAcceptingRange; + bool mAcceptsAll = false; + bool mExclude = false; + + bool isTransition(const tAlphabetType& symbol) { + if (symbol == 0) return false; + if (!mConsumesSymbol || mAcceptsAll) return true; + bool const in_range = (symbol >= mAcceptingRange.mBegin && symbol <= mAcceptingRange.mEnd); + return in_range != mExclude; + } + }; + + struct Vertex { + List edges; + tStateType termination_state = tNoStateVal; + ualni debug_idx = 0; + ualni flag = 0; + }; + + public: + List mVertices; + Vertex* mStart = nullptr; + + public: + NFA() = default; + + Vertex* addVertex() { + auto node = mVertices.newNode(); + node->data.debug_idx = mVertices.length() + 1; + mVertices.pushBack(node); + return &node->data; + } + + void + addTransition(Vertex* from, Vertex* to, Range range, bool consumes, bool accepts_all, bool exclude) { + Edge edge; + edge.mVertex = to; + edge.mConsumesSymbol = consumes; + edge.mAcceptingRange = range; + edge.mExclude = exclude; + edge.mAcceptsAll = accepts_all; + from->edges.pushBack(edge); + } + + void setStartVertex(Vertex* start) { mStart = start; } + + [[nodiscard]] Vertex* getStartVertex() const { return mStart; } + + void setVertexState(Vertex* vertex, tStateType state) { vertex->termination_state = state; } + + [[nodiscard]] bool isValid() const { + if (!mStart) { + return false; + } + return true; + } + + Range getAlphabetRange() const { + tAlphabetType start = 0, end = 0; + Range all_range( + std::numeric_limits::min(), std::numeric_limits::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(start, end + 1); + } + + // vertices that are reachable from initial set with no input consumption (E-transitions) + // does not include initial set + void closure(const List& set, List& closure, ualni unique_call_id) { + List marked; + marked = set; + + while (marked.length()) { + auto first = marked.first()->data; + if (first->flag != unique_call_id) { + first->flag = unique_call_id; + closure.pushBack(first); + } + for (auto edge : first->edges) { + if (!edge.data().mConsumesSymbol && edge.data().mVertex->flag != unique_call_id) { + marked.pushBack(edge.data().mVertex); + } + } + marked.popFront(); + } + } + + // vertices that are reachable from initial set with symbol transition + void move(const List& set, List& reachable, tAlphabetType symbol, ualni unique_call_id) { + for (auto vertex : set) { + for (auto edge : vertex->edges) { + if (!edge.data().mConsumesSymbol) continue; + bool transition = edge.data().isTransition(symbol); + if (transition && edge.data().mVertex->flag != unique_call_id) { + edge.data().mVertex->flag = unique_call_id; + reachable.pushBack(edge.data().mVertex); + } + } + } + } + }; + + // Deterministic Finite-State Automata + template + class DFA { + static_assert(TypeTraits::isIntegral, "tAlphabetType must be enumerable."); + + struct Vertex { + struct Edge { + Vertex* vertex = nullptr; + tAlphabetType transition_code = nullptr; + }; + + List edges; + tStateType termination_state = tNoStateVal; + bool marked = false; + }; + + List mVertices; + Vertex* mStart = nullptr; + const Vertex* mIter = nullptr; + Range mAlphabetRange; + bool mTrapState = false; + + typedef typename NFA::Vertex NState; + + public: + explicit DFA(NFA& nfa) { + if (!nfa.isValid()) { + return; + } + + mAlphabetRange = nfa.getAlphabetRange(); + + struct DStateKey { + const List* nStates; + bool operator==(const DStateKey& in) const { + if (nStates->length() != in.nStates->length()) { + return false; + } + // FIXME : make linear time + for (auto state : *nStates) { + bool found = false; + for (auto in_state : *in.nStates) { + if (state.data() == in_state.data()) { + found = true; + break; + } + } + + if (!found) { + return false; + } + } + + return true; + } + + static ualni dStateHashFunc(DStateKey key) { + alni out = 0; + for (auto state : *key.nStates) { + out += alni(state.data()); + } + return out; + }; + }; + + // all NFA states that are reachable from initial DFA State for specific symbol in alphabet + struct DState { + struct DTransition { + DState* state = nullptr; + tAlphabetType accepting_code; + }; + + List nStates; + List transitions; + + Vertex* dVertex = nullptr; // relevant DFA vertex + + ualni debug_idx = 0; + }; + + // includes closure of NFA start state by definition + auto start_state = new DState(); + nfa.closure({ nfa.getStartVertex() }, start_state->nStates, ualni(start_state)); + + Map dStates; + + dStates.put({ &start_state->nStates }, start_state); + + List working_set = { start_state }; + + // while there is items to work with + auto currentDState = working_set.first(); + while (currentDState) { + + // check all possible transitions for any symbol + for (auto symbol : mAlphabetRange) { + + List reachableNStates; + + nfa.move(currentDState->data->nStates, reachableNStates, symbol, ualni(currentDState + symbol)); + nfa.closure(reachableNStates, reachableNStates, ualni(currentDState + symbol)); + + if (!reachableNStates.length()) { + continue; + } + + DState* targetDState = nullptr; + + // check if set of all reachable NFA states already forms existing DFA state + auto idx = dStates.presents({ &reachableNStates }); + if (idx) { + targetDState = dStates.getSlotVal(idx); + } + + if (!targetDState) { + // register new DFA state + targetDState = new DState(); + + targetDState->debug_idx = dStates.size(); + + targetDState->nStates = reachableNStates; + + // append to working stack + working_set.pushBack(targetDState); + dStates.put({ &targetDState->nStates }, targetDState); + } + + // add transition to DFA state + currentDState->data->transitions.pushBack({ targetDState, symbol }); + } + + working_set.popFront(); + currentDState = working_set.first(); + } + + // create own vertices + for (auto node : dStates) { + tStateType state = tNoStateVal; + for (auto iter : node->val->nStates) { + if (iter->termination_state != tNoStateVal) { + state = iter->termination_state; + break; + } + } + node->val->dVertex = addVertex(state); + } + + // connect all vertices + for (auto node : dStates) { + for (auto edge : node->val->transitions) { + addTransition(node->val->dVertex, edge.data().state->dVertex, edge.data().accepting_code); + } + } + + // set the starting vertex + mStart = start_state->dVertex; + + // cleanup + for (auto node : dStates) { + delete node->val; + } + + collapseEquivalentVertices(); + mAlphabetRange = getAlphabetRange(); + } + + tStateType move(tAlphabetType symbol) { + if (mTrapState || !mIter) { + return tNoStateVal; + } + + for (auto edge : mIter->edges) { + if (edge.data().transition_code == symbol) { + mIter = edge.data().vertex; + return mIter->termination_state; + } + } + + mTrapState = true; + return tNoStateVal; + } + + void start() { + mIter = mStart; + mTrapState = false; + } + + [[nodiscard]] uhalni nVertices() const { return (uhalni) mVertices.length(); } + + [[nodiscard]] Range getRange() const { return mAlphabetRange; } + + public: + [[nodiscard]] Range getAlphabetRange() const { + Range out; + for (auto vertex : mVertices) { + vertex.data().marked = false; + } + + bool first = true; + getAlphabetRangeUtil(mStart, &out, first); + out.mEnd++; + return out; + } + + void getAlphabetRangeUtil(Vertex* vert, Range* out, bool& first) const { + vert->marked = true; + for (auto edge : vert->edges) { + auto const code = edge.data().transition_code; + + if (first) { + *out = { code, code }; + first = false; + } + + if (code < out->mBegin) { + out->mBegin = code; + } + if (code > out->mEnd) { + out->mEnd = code; + } + + if (!edge.data().vertex->marked) { + getAlphabetRangeUtil(edge.data().vertex, out, first); + } + } + } + + void collapseEquivalentVertices() { + // TODO + } + + Vertex* addVertex(tStateType state) { + auto node = mVertices.addNodeBack(); + node->data.termination_state = state; + return &node->data; + } + + void addTransition(Vertex* from, Vertex* to, tAlphabetType transition_symbol) { + from->edges.pushBack({ to, transition_symbol }); + } + }; +} diff --git a/Language/public/ContextFreeCompiler.hpp b/Language/public/ContextFreeCompiler.hpp new file mode 100644 index 0000000..c67e3e1 --- /dev/null +++ b/Language/public/ContextFreeCompiler.hpp @@ -0,0 +1,10 @@ + +#pragma once + +#include "Grammar.hpp" + +namespace tp { + + template + class RegularCompiler {}; +} diff --git a/Language/public/Parser.hpp b/Language/public/Parser.hpp index 81be880..24407fa 100644 --- a/Language/public/Parser.hpp +++ b/Language/public/Parser.hpp @@ -2,7 +2,7 @@ #pragma once #include "AST.hpp" -#include "GrammarCompiler.hpp" +#include "RegularCompiler.hpp" namespace tp { diff --git a/Language/public/RegularAutomata.hpp b/Language/public/RegularAutomata.hpp index 3199829..dea3c21 100644 --- a/Language/public/RegularAutomata.hpp +++ b/Language/public/RegularAutomata.hpp @@ -2,8 +2,7 @@ #pragma once #include "Strings.hpp" -#include "List.hpp" -#include "Map.hpp" +#include "Automata.hpp" #include "Buffer2D.hpp" namespace tp { @@ -11,389 +10,6 @@ namespace tp { template class TransitionMatrix; - template - class DFA; - - // Non-Deterministic Finite-State Automata - template - class NFA { - static_assert(TypeTraits::isIntegral, "tAlphabetType must be enumerable."); - - public: - struct Vertex; - - private: - struct Edge { - Vertex* mVertex = nullptr; - bool mConsumesSymbol = false; - Range mAcceptingRange; - bool mAcceptsAll = false; - bool mExclude = false; - - bool isTransition(const tAlphabetType& symbol) { - if (symbol == 0) return false; - if (!mConsumesSymbol || mAcceptsAll) return true; - bool const in_range = (symbol >= mAcceptingRange.mBegin && symbol <= mAcceptingRange.mEnd); - return in_range != mExclude; - } - }; - - public: - struct Vertex { - List edges; - tStateType termination_state = tNoStateVal; -#ifdef ENV_BUILD_DEBUG - ualni debug_idx = 0; -#endif - ualni flag = 0; - }; - - private: - friend DFA; - - List mVertices; - Vertex* mStart = nullptr; - - public: - NFA() = default; - - Vertex* addVertex() { - auto node = mVertices.newNode(); -#ifdef ENV_BUILD_DEBUG - node->data.debug_idx = mVertices.length() + 1; -#endif - mVertices.pushBack(node); - return &node->data; - } - - void - addTransition(Vertex* from, Vertex* to, Range range, bool consumes, bool accepts_all, bool exclude) { - Edge edge; - edge.mVertex = to; - edge.mConsumesSymbol = consumes; - edge.mAcceptingRange = range; - edge.mExclude = exclude; - edge.mAcceptsAll = accepts_all; - from->edges.pushBack(edge); - } - - void setStartVertex(Vertex* start) { mStart = start; } - - [[nodiscard]] Vertex* getStartVertex() const { return mStart; } - - void setVertexState(Vertex* vertex, tStateType state) { vertex->termination_state = state; } - - [[nodiscard]] bool isValid() const { - if (!mStart) { - return false; - } - return true; - } - - Range getAlphabetRange() const { - tAlphabetType start = 0, end = 0; - Range all_range( - std::numeric_limits::min(), std::numeric_limits::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(start, end + 1); - } - - // vertices that are reachable from initial set with no input consumption (E-transitions) - // does not include initial set - void closure(const List& set, List& closure, ualni unique_call_id) { - List marked; - marked = set; - - while (marked.length()) { - auto first = marked.first()->data; - if (first->flag != unique_call_id) { - first->flag = unique_call_id; - closure.pushBack(first); - } - for (auto edge : first->edges) { - if (!edge.data().mConsumesSymbol && edge.data().mVertex->flag != unique_call_id) { - marked.pushBack(edge.data().mVertex); - } - } - marked.popFront(); - } - } - - // vertices that are reachable from initial set with symbol transition - void move(const List& set, List& reachable, tAlphabetType symbol, ualni unique_call_id) { - for (auto vertex : set) { - for (auto edge : vertex->edges) { - if (!edge.data().mConsumesSymbol) continue; - bool transition = edge.data().isTransition(symbol); - if (transition && edge.data().mVertex->flag != unique_call_id) { - edge.data().mVertex->flag = unique_call_id; - reachable.pushBack(edge.data().mVertex); - } - } - } - } - }; - - // Deterministic Finite-State Automata - template - class DFA { - static_assert(TypeTraits::isIntegral, "tAlphabetType must be enumerable."); - friend TransitionMatrix; - - struct Vertex { - struct Edge { - Vertex* vertex = nullptr; - tAlphabetType transition_code = nullptr; - }; - - List edges; - tStateType termination_state = tNoStateVal; - bool marked = false; - }; - - List mVertices; - Vertex* mStart = nullptr; - const Vertex* mIter = nullptr; - Range mAlphabetRange; - bool mTrapState = false; - - typedef typename NFA::Vertex NState; - - public: - explicit DFA(NFA& nfa) { - if (!nfa.isValid()) { - return; - } - - mAlphabetRange = nfa.getAlphabetRange(); - - struct DStateKey { - const List* nStates; - bool operator==(const DStateKey& in) const { - if (nStates->length() != in.nStates->length()) { - return false; - } - // FIXME : make linear time - for (auto state : *nStates) { - bool found = false; - for (auto in_state : *in.nStates) { - if (state.data() == in_state.data()) { - found = true; - break; - } - } - - if (!found) { - return false; - } - } - - return true; - } - - static ualni dStateHashFunc(DStateKey key) { - alni out = 0; - for (auto state : *key.nStates) { - out += alni(state.data()); - } - return out; - }; - }; - - // all NFA states that are reachable from initial DFA State for specific symbol in alphabet - struct DState { - struct DTransition { - DState* state = nullptr; - tAlphabetType accepting_code; - }; - - List nStates; - List transitions; - - Vertex* dVertex = nullptr; // relevant DFA vertex - -#ifdef ENV_BUILD_DEBUG - ualni debug_idx = 0; -#endif - }; - - // includes closure of NFA start state by definition - auto start_state = new DState(); - nfa.closure({ nfa.getStartVertex() }, start_state->nStates, ualni(start_state)); - - Map dStates; - - dStates.put({ &start_state->nStates }, start_state); - - List working_set = { start_state }; - - // while there is items to work with - auto currentDState = working_set.first(); - while (currentDState) { - - // check all possible transitions for any symbol - for (auto symbol : mAlphabetRange) { - - List reachableNStates; - - nfa.move(currentDState->data->nStates, reachableNStates, symbol, ualni(currentDState + symbol)); - nfa.closure(reachableNStates, reachableNStates, ualni(currentDState + symbol)); - - if (!reachableNStates.length()) { - continue; - } - - DState* targetDState = nullptr; - - // check if set of all reachable NFA states already forms existing DFA state - auto idx = dStates.presents({ &reachableNStates }); - if (idx) { - targetDState = dStates.getSlotVal(idx); - } - - if (!targetDState) { - // register new DFA state - targetDState = new DState(); - -#ifdef ENV_BUILD_DEBUG - targetDState->debug_idx = dStates.size(); -#endif - - targetDState->nStates = reachableNStates; - - // append to working stack - working_set.pushBack(targetDState); - dStates.put({ &targetDState->nStates }, targetDState); - } - - // add transition to DFA state - currentDState->data->transitions.pushBack({ targetDState, symbol }); - } - - working_set.popFront(); - currentDState = working_set.first(); - } - - // create own vertices - for (auto node : dStates) { - tStateType state = tNoStateVal; - for (auto iter : node->val->nStates) { - if (iter->termination_state != tNoStateVal) { - state = iter->termination_state; - break; - } - } - node->val->dVertex = addVertex(state); - } - - // connect all vertices - for (auto node : dStates) { - for (auto edge : node->val->transitions) { - addTransition(node->val->dVertex, edge.data().state->dVertex, edge.data().accepting_code); - } - } - - // set the starting vertex - mStart = start_state->dVertex; - - // cleanup - for (auto node : dStates) { - delete node->val; - } - - collapseEquivalentVertices(); - mAlphabetRange = getAlphabetRange(); - } - - tStateType move(tAlphabetType symbol) { - if (mTrapState || !mIter) { - return tNoStateVal; - } - - for (auto edge : mIter->edges) { - if (edge.data().transition_code == symbol) { - mIter = edge.data().vertex; - return mIter->termination_state; - } - } - - mTrapState = true; - return tNoStateVal; - } - - void start() { - mIter = mStart; - mTrapState = false; - } - - [[nodiscard]] uhalni nVertices() const { return (uhalni) mVertices.length(); } - - [[nodiscard]] Range getRange() const { return mAlphabetRange; } - - private: - [[nodiscard]] Range getAlphabetRange() const { - Range out; - for (auto vertex : mVertices) { - vertex.data().marked = false; - } - - bool first = true; - getAlphabetRangeUtil(mStart, &out, first); - out.mEnd++; - return out; - } - - void getAlphabetRangeUtil(Vertex* vert, Range* out, bool& first) const { - vert->marked = true; - for (auto edge : vert->edges) { - auto const code = edge.data().transition_code; - - if (first) { - *out = { code, code }; - first = false; - } - - if (code < out->mBegin) { - out->mBegin = code; - } - if (code > out->mEnd) { - out->mEnd = code; - } - - if (!edge.data().vertex->marked) { - getAlphabetRangeUtil(edge.data().vertex, out, first); - } - } - } - - void collapseEquivalentVertices() { - // TODO - } - - Vertex* addVertex(tStateType state) { - auto node = mVertices.addNodeBack(); - node->data.termination_state = state; - return &node->data; - } - - void addTransition(Vertex* from, Vertex* to, tAlphabetType transition_symbol) { - from->edges.pushBack({ to, transition_symbol }); - } - }; - template class TransitionMatrix { diff --git a/Language/public/GrammarCompiler.hpp b/Language/public/RegularCompiler.hpp similarity index 100% rename from Language/public/GrammarCompiler.hpp rename to Language/public/RegularCompiler.hpp