// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Graph automata base class
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2003-2020 by Wilson Snyder. This program is free software; you
// can redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************

#ifndef _V3GRAPHDFA_H_
#define _V3GRAPHDFA_H_ 1
#include "config_build.h"
#include "verilatedos.h"

#include "V3Ast.h"  // for VNUser
#include "V3Global.h"
#include "V3Graph.h"

class DfaGraph;
class DfaVertex;
class DfaEdge;

//=============================================================================
// NFA/DFA Graphs
///     The NFA graph consists of:
///             DfaVertex(START)        The starting point
///             DfaVertex()             Interior states
///             DfaVertex(ACCEPT)       The completion point
///
/// Transitions include a list of all inputs (arbitrary user pointers),
/// 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.  (If we want the complement, we
/// call complement and the algorithm makes a REJECT state, then flips
/// accept and reject for you.)
///
/// Common transforms:
///
///     "*":    DfaVertex(START) --> [epsilon] -->DfaVertex(ACCEPT)
///
///     "L":    ...->[ON_L]-->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]-/
///
///     "L*":   ...->DfaVtx-->[epsilon]-->DfaVtx-->[ON_L]-->DfaVtx()->[epsilon]-->DfaVtx(ACCEPT)
///                        |                 ^\----[epsilon]<-------/           |
///                        \->[epsilon]-----------------------------------------/

class DfaGraph : public V3Graph {
public:
    // CONSTRUCTORS
    DfaGraph() {}
    virtual ~DfaGraph() {}
    // METHODS
    /// Find start node
    DfaVertex* findStart();
    /// Convert automata: NFA to DFA
    void nfaToDfa();
    /// Simplify a DFA automata
    void dfaReduce();
    /// Complement result (must already be dfa)
    void dfaComplement();
};

//=============================================================================
// Vertex

class DfaVertex : public V3GraphVertex {
    // Each DFA state is captured in this vertex.
    // Start and accepting are members, rather than the more intuitive
    // subclasses, as subclassing them would make it harder to inherit from here.
    bool m_start;  // Start state
    bool m_accepting;  // Accepting state?
public:
    // CONSTRUCTORS
    explicit DfaVertex(DfaGraph* graphp, bool start = false, bool accepting = false)
        : V3GraphVertex(graphp)
        , m_start(start)
        , m_accepting(accepting) {}
    using V3GraphVertex::clone;  // We are overriding, not overloading clone(V3Graph*)
    virtual DfaVertex* clone(DfaGraph* graphp) {
        return new DfaVertex(graphp, start(), accepting());
    }
    virtual ~DfaVertex() {}
    // ACCESSORS
    virtual string dotShape() const { return (accepting() ? "doublecircle" : ""); }
    virtual string dotColor() const { return start() ? "blue" : (color() ? "red" : "black"); }
    bool start() const { return m_start; }
    void start(bool flag) { m_start = flag; }
    bool accepting() const { return m_accepting; }
    void accepting(bool flag) { m_accepting = flag; }
};

//============================================================================
/// Abstract type indicating a specific "input" to the NFA
/// DFA assumes each .toInt() is unique
typedef VNUser DfaInput;

//============================================================================
// Edge types

class DfaEdge : public V3GraphEdge {
    DfaInput m_input;
    bool m_complement;  // Invert value when doing compare
public:
    static DfaInput EPSILON() { return VNUser::fromInt(0); }
    static DfaInput NA() { return VNUser::fromInt(1); }  // as in not-applicable
    // CONSTRUCTORS
    DfaEdge(DfaGraph* graphp, DfaVertex* fromp, DfaVertex* top, const DfaInput& input)
        : V3GraphEdge(graphp, fromp, top, 1)
        , 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"
                                 : complement() ? ("not " + cvtToStr(input().toInt()))
                                                : cvtToStr(input().toInt()));
    }
    virtual string dotStyle() const { return (na() || cutable()) ? "dashed" : ""; }
    bool epsilon() const { return input().toInt() == EPSILON().toInt(); }
    bool na() const { return input().toInt() == NA().toInt(); }
    bool complement() const { return m_complement; }
    void complement(bool value) { m_complement = value; }
    DfaInput input() const { return m_input; }
};

//============================================================================

#endif  // Guard
