Add graph dfa complementing; not used yet.
git-svn-id: file://localhost/svn/verilator/trunk/verilator@1005 77ca24e4-aefa-0310-84f0-b9a241c72d87
This commit is contained in:
parent
ede37bb9d8
commit
6dca9b4ba4
|
@ -480,3 +480,97 @@ public:
|
||||||
void DfaGraph::dfaReduce() {
|
void DfaGraph::dfaReduce() {
|
||||||
DfaGraphReduce (this, &V3GraphEdge::followAlwaysTrue);
|
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<DfaGraph*>(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<DfaVertex*>(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<DfaVertex*>(vertexp)) {
|
||||||
|
//UINFO(0, "FIX on vertex "<<vvertexp->name()<<endl);
|
||||||
|
if (!vvertexp->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<DfaEdge*>(edgep);
|
||||||
|
DfaVertex* tovertexp = static_cast<DfaVertex*>(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);
|
||||||
|
}
|
||||||
|
|
|
@ -43,7 +43,9 @@ class DfaEdge;
|
||||||
/// or epsilon, represented as a empty list of inputs.
|
/// or epsilon, represented as a empty list of inputs.
|
||||||
///
|
///
|
||||||
/// We're only looking for matches, so the only accepting states are
|
/// 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:
|
/// Common transforms:
|
||||||
///
|
///
|
||||||
|
@ -51,8 +53,8 @@ class DfaEdge;
|
||||||
///
|
///
|
||||||
/// "L": ...->[ON_L]-->DfaVtx-->[epsilon]-->DfaVtx(ACCEPT)
|
/// "L": ...->[ON_L]-->DfaVtx-->[epsilon]-->DfaVtx(ACCEPT)
|
||||||
///
|
///
|
||||||
/// "LR": ...->[ON_L]-->DfaVtx-->[epsilon]-->DfaVtx()
|
/// "LR": ...->[ON_L]-->DfaVtx-->[epsilon]-->DfaVtx(ACCEPT)
|
||||||
/// ->[ON_R]-->DfaVtx-->[epsilon]-->DfaVtx(ACCEPT)
|
/// ->[ON_R]-->DfaVtx-->[epsilon]-/
|
||||||
///
|
///
|
||||||
/// "L|R": ...->DfaVtx-->[epsilon]-->DfaVtx-->[ON_L]-->DfaVtx()->[epsilon]-->DfaVtx(ACCEPT)
|
/// "L|R": ...->DfaVtx-->[epsilon]-->DfaVtx-->[ON_L]-->DfaVtx()->[epsilon]-->DfaVtx(ACCEPT)
|
||||||
/// \->[epsilon]-->DfaVtx-->[ON_R]-->DfaVtx()->[epsilon]-/
|
/// \->[epsilon]-->DfaVtx-->[ON_R]-->DfaVtx()->[epsilon]-/
|
||||||
|
@ -76,6 +78,9 @@ public:
|
||||||
|
|
||||||
/// Simplify a DFA automata
|
/// Simplify a DFA automata
|
||||||
void dfaReduce();
|
void dfaReduce();
|
||||||
|
|
||||||
|
/// Complement result (must already be dfa)
|
||||||
|
void dfaComplement();
|
||||||
};
|
};
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
@ -113,20 +118,33 @@ typedef AstNUser* DfaInput;
|
||||||
|
|
||||||
class DfaEdge : public V3GraphEdge {
|
class DfaEdge : public V3GraphEdge {
|
||||||
DfaInput m_input;
|
DfaInput m_input;
|
||||||
|
bool m_complement; // Invert value when doing compare
|
||||||
public:
|
public:
|
||||||
static DfaInput EPSILON() { return NULL; }
|
static DfaInput EPSILON() { return NULL; }
|
||||||
static DfaInput NA() { return AstNUser::fromInt(1); } // as in not-applicable
|
static DfaInput NA() { return AstNUser::fromInt(1); } // as in not-applicable
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
DfaEdge(DfaGraph* graphp, DfaVertex* fromp, DfaVertex* top, DfaInput input)
|
DfaEdge(DfaGraph* graphp, DfaVertex* fromp, DfaVertex* top, DfaInput input)
|
||||||
: V3GraphEdge(graphp, fromp, top, 1)
|
: 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() {}
|
virtual ~DfaEdge() {}
|
||||||
// METHODS
|
// METHODS
|
||||||
virtual string dotColor() const { return na()?"yellow":epsilon()?"green":"black"; }
|
virtual string dotColor() const {
|
||||||
virtual string dotLabel() const { return na()?"":epsilon()?"e":cvtToStr((void*)(input())); }
|
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":""; }
|
virtual string dotStyle() const { return (na()||cutable())?"dashed":""; }
|
||||||
bool epsilon() const { return input()==EPSILON(); }
|
bool epsilon() const { return input()==EPSILON(); }
|
||||||
bool na() const { return input()==NA(); }
|
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; }
|
DfaInput input() const { return m_input; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -309,6 +309,12 @@ public:
|
||||||
gp->nfaToDfa();
|
gp->nfaToDfa();
|
||||||
dump();
|
dump();
|
||||||
gp->dfaReduce();
|
gp->dfaReduce();
|
||||||
|
dump();
|
||||||
|
|
||||||
|
gp->dfaComplement();
|
||||||
|
dump();
|
||||||
|
gp->dfaReduce();
|
||||||
|
dump();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue