From 6dca9b4ba48b93c5710c9e9a61b53e3f02cde737 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 23 Mar 2008 13:56:06 +0000 Subject: [PATCH] Add graph dfa complementing; not used yet. git-svn-id: file://localhost/svn/verilator/trunk/verilator@1005 77ca24e4-aefa-0310-84f0-b9a241c72d87 --- src/V3GraphDfa.cpp | 94 +++++++++++++++++++++++++++++++++++++++++++++ src/V3GraphDfa.h | 30 ++++++++++++--- src/V3GraphTest.cpp | 6 +++ 3 files changed, 124 insertions(+), 6 deletions(-) diff --git a/src/V3GraphDfa.cpp b/src/V3GraphDfa.cpp index cc747ca47..09edef791 100644 --- a/src/V3GraphDfa.cpp +++ b/src/V3GraphDfa.cpp @@ -480,3 +480,97 @@ public: void DfaGraph::dfaReduce() { DfaGraphReduce (this, &V3GraphEdge::followAlwaysTrue); } + +//###################################################################### +//###################################################################### +// Algorithms - complement a DFA +// +// The traditional algorithm is to make a rejecting state, add edges to +// reject from all missing values, then swap accept and reject. Rather +// than swap at the end, it's faster if we swap up front, then do the edge +// changes. +// +// 1. Since we didn't log rejecting states, make a temp state (this will be +// the old accept, and new reject). +// +// 2. All vertexes except start/accept get edges to NEW accept for any +// non-existing case. Weedely we don't have a nice way of representing +// this so we just create a edge for each case and mark it "complemented." +// +// 3. Delete temp vertex (old accept/new reject) and related edges. +// The user's old accept is now the new accept. This is imporant as +// we want the virtual type of it to be intact. + +class DfaGraphComplement : GraphAlg { +private: + // MEMBERS + DfaVertex* m_tempNewerReject; + + // METHODS + int debug() { return 9; } + DfaGraph* graphp() { return static_cast(m_graphp); } + + void add_complement_edges() { + // Find accepting vertex + DfaVertex* acceptp = NULL; + for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { + if (DfaVertex* vvertexp = dynamic_cast(vertexp)) { + if (vvertexp->accepting()) { + acceptp = vvertexp; + break; + } + } + } + if (!acceptp) v3fatalSrc("No accepting vertex in DFA\n"); + + // Remap edges + for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { + if (DfaVertex* vvertexp = dynamic_cast(vertexp)) { + //UINFO(0, "FIX on vertex "<name()<accepting() && vvertexp != m_tempNewerReject) { + for (V3GraphEdge* nextp, *edgep = vertexp->outBeginp(); edgep; edgep=nextp) { + nextp = edgep->outNextp(); + if (!edgep->user()) { // Not processed + // Old edges to accept now go to new reject + DfaEdge* vedgep = static_cast(edgep); + DfaVertex* tovertexp = static_cast(edgep->top()); + if (tovertexp->accepting()) { + new DfaEdge(graphp(), vvertexp, m_tempNewerReject, vedgep); + edgep->unlinkDelete(); edgep=NULL; + } + + // NOT of all values goes to accept + // We make a edge for each value to OR, IE + // edge(complemented,a) edge(complemented,b) means !(a | b) + if (!tovertexp->accepting()) { // Note we must include edges moved above to reject + DfaEdge* newp = new DfaEdge (graphp(), vvertexp, acceptp, vedgep); + newp->complement(!newp->complement()); + newp->user(1); + } + } + } + } + } + } + } +public: + DfaGraphComplement(V3Graph* dfagraphp, V3EdgeFuncP edgeFuncp) + : GraphAlg(dfagraphp, edgeFuncp) { + if (debug()>=6) m_graphp->dumpDotFilePrefixed("comp_in"); + + // Vertex::m_user begin: 1 indicates new edge, no more processing + m_graphp->userClearEdges(); + + m_tempNewerReject = new DfaVertex(graphp()); + add_complement_edges(); + if (debug()>=6) m_graphp->dumpDotFilePrefixed("comp_preswap"); + + m_tempNewerReject->unlinkDelete(graphp()); m_tempNewerReject=NULL; + if (debug()>=6) m_graphp->dumpDotFilePrefixed("comp_out"); + } + ~DfaGraphComplement() {} +}; + +void DfaGraph::dfaComplement() { + DfaGraphComplement (this, &V3GraphEdge::followAlwaysTrue); +} diff --git a/src/V3GraphDfa.h b/src/V3GraphDfa.h index 9bb96a030..76b28367c 100644 --- a/src/V3GraphDfa.h +++ b/src/V3GraphDfa.h @@ -43,7 +43,9 @@ class DfaEdge; /// or epsilon, represented as a empty list of inputs. /// /// We're only looking for matches, so the only accepting states are -/// at the end of the transformations. +/// at the end of the transformations. (If we want the complement, we +/// call complement and the algorithm makes a REJECT state, then flips +/// accept and reject for you.) /// /// Common transforms: /// @@ -51,8 +53,8 @@ class DfaEdge; /// /// "L": ...->[ON_L]-->DfaVtx-->[epsilon]-->DfaVtx(ACCEPT) /// -/// "LR": ...->[ON_L]-->DfaVtx-->[epsilon]-->DfaVtx() -/// ->[ON_R]-->DfaVtx-->[epsilon]-->DfaVtx(ACCEPT) +/// "LR": ...->[ON_L]-->DfaVtx-->[epsilon]-->DfaVtx(ACCEPT) +/// ->[ON_R]-->DfaVtx-->[epsilon]-/ /// /// "L|R": ...->DfaVtx-->[epsilon]-->DfaVtx-->[ON_L]-->DfaVtx()->[epsilon]-->DfaVtx(ACCEPT) /// \->[epsilon]-->DfaVtx-->[ON_R]-->DfaVtx()->[epsilon]-/ @@ -76,6 +78,9 @@ public: /// Simplify a DFA automata void dfaReduce(); + + /// Complement result (must already be dfa) + void dfaComplement(); }; //============================================================================= @@ -113,20 +118,33 @@ typedef AstNUser* DfaInput; class DfaEdge : public V3GraphEdge { DfaInput m_input; + bool m_complement; // Invert value when doing compare public: static DfaInput EPSILON() { return NULL; } static DfaInput NA() { return AstNUser::fromInt(1); } // as in not-applicable // CONSTRUCTORS DfaEdge(DfaGraph* graphp, DfaVertex* fromp, DfaVertex* top, DfaInput input) : V3GraphEdge(graphp, fromp, top, 1) - , m_input(input) {} + , m_input(input), m_complement(false) {} + DfaEdge(DfaGraph* graphp, DfaVertex* fromp, DfaVertex* top, const DfaEdge* copyfrom) + : V3GraphEdge(graphp, fromp, top, copyfrom->weight()) + , m_input(copyfrom->input()), m_complement(copyfrom->complement()) {} virtual ~DfaEdge() {} // METHODS - virtual string dotColor() const { return na()?"yellow":epsilon()?"green":"black"; } - virtual string dotLabel() const { return na()?"":epsilon()?"e":cvtToStr((void*)(input())); } + virtual string dotColor() const { + return (na() ? "yellow" + : epsilon() ? "green" + : "black"); } + virtual string dotLabel() const { + return (na() ? "" + : epsilon() ? "e" + : complement() ? ("not "+cvtToStr((void*)(input()))) + : cvtToStr((void*)(input()))); } virtual string dotStyle() const { return (na()||cutable())?"dashed":""; } bool epsilon() const { return input()==EPSILON(); } bool na() const { return input()==NA(); } + bool complement() const { return m_complement; } + void complement(bool value) { m_complement=value; } DfaInput input() const { return m_input; } }; diff --git a/src/V3GraphTest.cpp b/src/V3GraphTest.cpp index 931a34dca..6b8f96620 100644 --- a/src/V3GraphTest.cpp +++ b/src/V3GraphTest.cpp @@ -309,6 +309,12 @@ public: gp->nfaToDfa(); dump(); gp->dfaReduce(); + dump(); + + gp->dfaComplement(); + dump(); + gp->dfaReduce(); + dump(); } };