From 3f21513ac5a245b284c9b7d0c5697e03949b833b Mon Sep 17 00:00:00 2001
From: Robin Jadoul <robin.jadoul@gmail.com>
Date: Sun, 24 Apr 2016 15:42:29 +0200
Subject: [PATCH] First work

---
 include/Lexesis/automata.h | 46 ++++++++++++++++++
 include/Lexesis/re.h       | 90 +++++++++++++++++++++++++++++++++++
 src/automata.cpp           | 97 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 233 insertions(+)
 create mode 100644 include/Lexesis/automata.h
 create mode 100644 include/Lexesis/re.h
 create mode 100644 src/automata.cpp

diff --git a/include/Lexesis/automata.h b/include/Lexesis/automata.h
new file mode 100644
index 0000000..de8bd5d
--- /dev/null
+++ b/include/Lexesis/automata.h
@@ -0,0 +1,46 @@
+#pragma once
+#ifndef AUTOMATA_H
+#define AUTOMATA_H
+
+#include <map>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace lxs {
+    typedef unsigned long long State;
+    typedef unsigned long long Priority;
+
+    struct Automaton {
+        State numStates;
+        std::set<State> accepting;
+        std::map<State, Priority> priority;
+        std::map<State, std::string> acceptingToken;
+        State starting;
+    };
+
+    struct DFA : public Automaton {
+        std::map<State, std::map<char, State> > delta;
+    };
+
+    struct NFA : public Automaton {
+        std::map<State, std::map<char, std::set<State> > > delta;
+        virtual std::set<State> eClose(State);
+    };
+
+    struct ENFA : public NFA {
+        std::map<State, std::set<State> > epsilonTransitions;
+        virtual std::set<State> eClose(State);
+    };
+
+    std::string toDot(const DFA& d);
+    std::string toDot(const NFA& n);
+    std::string toDot(const ENFA& e);
+
+    ENFA merge(const std::vector<ENFA>& enfas);
+    DFA mssc(const NFA& e);
+    DFA minimize(const DFA& d);
+} //namespace lxs
+
+#endif //AUTOMATA_H
diff --git a/include/Lexesis/re.h b/include/Lexesis/re.h
new file mode 100644
index 0000000..9671a30
--- /dev/null
+++ b/include/Lexesis/re.h
@@ -0,0 +1,90 @@
+#pragma once
+#ifndef RE_H
+#define RE_H
+
+#include "Lexesis/automata.h"
+
+#include <stdexcept>
+
+namespace lxs {
+    class RE
+    {
+        public:
+            virtual ~RE() {}
+            virtual int toENFA(ENFA& enfa, int attach) = 0;
+            virtual std::string toRe() = 0;
+    };
+
+    class EmptyRE : public RE
+    {
+        public:
+            EmptyRE() {}
+            ~EmptyRE() {}
+            virtual int toENFA(ENFA& enfa, int attach);
+            virtual std::string toRe();
+    };
+
+    class EpsilonRE : public RE
+    {
+        public:
+            EpsilonRE() {}
+            ~EpsilonRE() {}
+            virtual int toENFA(ENFA& enfa, int attach);
+            virtual std::string toRe();
+    };
+
+    class SingleRE : public RE
+    {
+        public:
+            SingleRE(char c) : c(c) {}
+            ~SingleRE() {}
+            virtual int toENFA(ENFA& enfa, int attach);
+            virtual std::string toRe();
+
+            char c;
+    };
+
+    class ConcatRE : public RE
+    {
+        public:
+            ConcatRE(RE* e, RE* f) : e(e), f(f) {}
+            ~ConcatRE() {delete e; delete f;}
+            virtual int toENFA(ENFA& enfa, int attach);
+            virtual std::string toRe();
+
+            RE* e, *f;
+    };
+
+    class StarRE : public RE
+    {
+        public:
+            StarRE(RE* e) : e(e) {}
+            ~StarRE() {delete e;}
+            virtual int toENFA(ENFA& enfa, int attach);
+            virtual std::string toRe();
+
+            RE* e;
+    };
+
+    class PlusRE : public RE
+    {
+        public:
+            PlusRE(RE* e, RE* f) : e(e), f(f) {}
+            ~PlusRE() {delete e; delete f;}
+            virtual int toENFA(ENFA& enfa, int attach);
+            virtual std::string toRe();
+
+            RE* e, *f;
+    };
+
+    RE* parseRE(std::string& input);
+
+    class SyntaxError : public std::runtime_error
+    {
+        public:
+            SyntaxError(const char* w) : std::runtime_error(w) {}
+    };
+
+} //namespace lxs
+
+#endif //RE_H
diff --git a/src/automata.cpp b/src/automata.cpp
new file mode 100644
index 0000000..e79d684
--- /dev/null
+++ b/src/automata.cpp
@@ -0,0 +1,97 @@
+#include "automata.h"
+
+#include <cctype>
+#include <algorithm>
+#include <stdexcept>
+#include <string>
+
+namespace lxs {
+    std::string toDot(const DFA& d)
+    {
+        std::string s = "digraph {\nrankdir=LR\nin [shape=point style=invis]";
+
+        for (State state = 0; state < d.numStates; state++)
+        {
+            s += std::to_string(state) + " [label=\"" + std::to_string(state) + "\"";
+            if (state == d.starting)
+                s += " color=yellow";
+            if (d.accepting.count(state) > 0)
+                s += " color=green shape=doublecircle";
+            s += "]\n";
+        }
+
+        for (const auto& tmp : d.delta)
+        {
+            const auto& from = tmp.first;
+            for (const auto& trans : tmp.second)
+            {
+                s += std::to_string(from) + " -> " + std::to_string(trans.second) + " [label=\"" + trans.first + "\"]\n";
+            }
+        }
+
+        s += "in -> " + std::to_string(d.starting) + "\n}\n";
+        return s;
+    }
+
+    std::string toDot(const NFA& n)
+    {
+        std::string s = "digraph {\nrankdir=LR\nin [shape=point style=invis]\n";
+
+        for (State state = 0; state < n.numStates; state++)
+        {
+            s += std::to_string(state) + " [label=\"" + std::to_string(state) + "\"";
+            if (state == n.starting)
+                s += " color=yellow";
+            if (n.accepting.count(state) > 0)
+                s += " color=green shape=doublecircle";
+            s += "]\n";
+        }
+
+        for (const auto& tmp : n.delta)
+        {
+            const auto& from = tmp.first;
+            for (const auto& trans : tmp.second)
+            {
+                for (const auto& to : trans.second)
+                    s += std::to_string(from) + " -> " + std::to_string(to) + " [label=\"" + trans.first + "\"]\n";
+            }
+        }
+
+        s += "in -> " + std::to_string(n.starting) + "\n}\n";
+        return s;
+    }
+
+    std::string toDot(const ENFA& e)
+    {
+        std::string s = "digraph {\nrankdir=LR\nin [shape=point style=invis]\n";
+
+        for (State state = 0; state < e.numStates; state++)
+        {
+            s += std::to_string(state) + " [label=\"" + std::to_string(state) + "\"";
+            if (state == e.starting)
+                s += " color=yellow";
+            if (e.accepting.count(state) > 0)
+                s += " color=green shape=doublecircle";
+            s += "]\n";
+        }
+
+        for (const auto& tmp : e.delta)
+        {
+            const auto& from = tmp.first;
+            for (const auto& trans : tmp.second)
+            {
+                for (const auto& to : trans.second)
+                    s += std::to_string(from) + " -> " + std::to_string(to) + " [label=\"" + trans.first + "\"]\n";
+            }
+        }
+
+        for (const auto& etrans : e.epsilonTransitions)
+        {
+            for (const auto& dest : etrans.second)
+                s += std::to_string(etrans.first) + " -> " + std::to_string(dest) + " [label=\"ε\"]\n";
+        }
+
+        s += "in -> " + std::to_string(e.starting) + "\n}\n";
+        return s;
+    }
+} //namespace lxs