From 493ec163ec9952eb7c489846bfef9c55368ff2c7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20Av=C3=A9?= <email@thomasave.be>
Date: Fri, 30 Dec 2016 17:38:42 +0100
Subject: [PATCH] First work on driver

---
 include/Parsodus/driver.h | 64 +++++++++++++++++++++++++++++++++++++++
 src/CMakeLists.txt        | 10 +++---
 src/driver.cpp            | 43 +++++++++++++++++++++++++-
 src/inputparser.cpp       |  3 +-
 src/main.cpp              | 11 +++++--
 tests/CMakeLists.txt      |  2 +-
 6 files changed, 123 insertions(+), 10 deletions(-)
 create mode 100644 include/Parsodus/driver.h

diff --git a/include/Parsodus/driver.h b/include/Parsodus/driver.h
new file mode 100644
index 0000000..a22a8d7
--- /dev/null
+++ b/include/Parsodus/driver.h
@@ -0,0 +1,64 @@
+#pragma once
+#ifndef PARSODUS_DRIVER_H
+#define PARSODUS_DRIVER_H
+
+#include <memory>
+#include <string>
+
+#include "Parsodus/backendmanager.h"
+
+namespace pds {
+    
+    /**
+     * The main driver for Parsodus
+     */
+    class Driver {
+        public:
+            /**
+             * Constructor
+             *
+             * @param backends The backendmanager, prepared with all needed supported backends
+             * @param inputfile An istream which should be read to be used as token rules specifications
+             * @param outputdir A string representing the directory where generated files should be places
+             * @param language The language to generate output for (backends is queried for this language)
+             * @param lexername The name to give to the generated lexer that is used by the parser, this gets cleaned to only contains alphanumeric chars or underscore and start with a non-digit (AKA a valid identifier)
+             * @param parsername The name to give to the generated parser, this gets cleaned to only contains alphanumeric chars or underscore and start with a non-digit (AKA a valid identifier)
+             */
+            Driver(std::unique_ptr<BackendManager> backends, std::istream& inputfile, std::string outputdir, std::string language, std::string lexername, std::string parsername);
+
+            /**
+             * Destructor
+             */
+            ~Driver();
+
+            /**
+             * Run this driver, all the preparation should happen when calling the constructor
+             *
+             * @return The status code this would return if it were a main function
+             */
+            int run();
+
+        private:
+            std::unique_ptr<BackendManager> m_backends;
+            std::istream& m_inputfile;
+            std::string m_outputdir;
+            std::string m_language;
+            std::string m_lexername;
+            std::string m_parsername;
+    };
+    
+    /**
+     * Used to throw errors when the driver could generate a valid lexer name or find the backend for a language
+     */
+
+    class DriverException: public std::exception {
+    public:
+        DriverException(std::string what);
+        virtual const char* what() const throw();
+
+    private:
+        std::string m_what;
+    };
+}
+
+#endif //PARSODUS_DRIVER_H
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8ac1da0..227e518 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -25,13 +25,15 @@ add_library(Parsodus-tables
     lrtables/SLR1Itemset.cpp
     )
 
-add_library(Parsodus-backends
-    backends/cpp.cpp
-    )
+# add_library(Parsodus-backends
+#     )
 
 add_library(pds
+    backend.cpp
     driver.cpp
+    template.cpp
     inputparser.cpp
+    backendmanager.cpp
     "${CMAKE_CURRENT_BINARY_DIR}/ParsodusLexer.cpp"
     )
 
@@ -42,7 +44,7 @@ add_executable(Parsodus
 target_link_libraries(Parsodus
     Parsodus-util
     Parsodus-tables
-    Parsodus-backends
+    # Parsodus-backends
     pds
     mstch::mstch)
 
diff --git a/src/driver.cpp b/src/driver.cpp
index 2aeb2f1..8f5dcd3 100644
--- a/src/driver.cpp
+++ b/src/driver.cpp
@@ -1,2 +1,43 @@
-#include "Parsodus/grammar.h"
+#include "Parsodus/driver.h"
+#include "Parsodus/inputparser.h"
+#include "Parsodus/config.h"
+
+#include <fstream>
+
+namespace {
+    /**
+     * Filter only valid identifier chars: alphanumeric, and not starting with a digit
+     */
+    std::string clean(std::string in) {
+        std::string s;
+        for (char c : in) {
+            if ((s.length() && std::isalnum(c)) || std::isalpha(c) || c == '_')
+                s += c;
+        }
+        return s;
+    }
+}
+
+
+namespace pds {
+    
+    Driver::Driver(std::unique_ptr<BackendManager> backends, std::istream& inputfile, std::string outputdir, std::string language, std::string lexername, std::string parsername):
+        m_backends(std::move(backends)), m_inputfile(inputfile), m_outputdir(outputdir), m_language(language), m_lexername(clean(lexername)), m_parsername(clean(parsername)) {
+        }
+
+    Driver::~Driver(){}
+    int Driver::run() { 
+        if (!m_lexername.length()) throw DriverException("no valid lexer name possible"); 
+        if (!m_parsername.length()) throw DriverException("no valid parser name possible"); 
+        Config config = InputParser::parseInput(m_inputfile);       
+        Backend* back = m_backends->findBackend(m_language, config.parserType);
+        if (!back) throw DriverException("Could not find a valid backend for language " + m_language + " and the given type of parser");
+		back->generateParser([this](std::string filename) -> std::unique_ptr<std::ostream> {
+				return std::unique_ptr<std::ostream>(new std::ofstream(m_outputdir + "/" + filename));
+				},
+				m_lexername, config);  
+
+        return 0; 
+    }
+}
 
diff --git a/src/inputparser.cpp b/src/inputparser.cpp
index 434110e..eaa5a07 100644
--- a/src/inputparser.cpp
+++ b/src/inputparser.cpp
@@ -1,5 +1,6 @@
 #include "ParsodusLexer.h"
 #include "Parsodus/inputparser.h"
+#include "Parsodus/util/parserType.h"
 
 namespace pds {
 
@@ -32,7 +33,7 @@ namespace pds {
                         lexColon(lex, token);
                         if(token.type == ParsodusLexer::PARSERTYPE) {
                             if(token.content == "lalr(1)") {
-                                config.parserType = Config::ParserType::LALR_1;
+                                config.parserType = util::ParserType::LALR_1;
                             } else
                                 throw InputParserException("Unkown parser type");
                         } else {
diff --git a/src/main.cpp b/src/main.cpp
index 46c1c55..b91c3b6 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -2,9 +2,11 @@
 #include <fstream>
 #include "optparse.h"
 #include "Parsodus/inputparser.h"
-
+#include "Parsodus/backendmanager.h"
 #include "Parsodus/lrtables/generator.h"
 #include "Parsodus/lrtables/SLR1Itemset.h"
+#include "Parsodus/backends/cppLR.h"
+#include "Parsodus/util/parserType.h"
 
 int main(int argc, char** argv) {
 
@@ -30,8 +32,11 @@ int main(int argc, char** argv) {
 
     auto config = pds::InputParser::parseInput(infile);
    
-
-
+    pds::BackendManager b;
+    b.registerLR<pds::backends::CppLRBackend>();
+    pds::Backend* back = b.findBackend("c++", pds::util::ParserType::LR_0);
+    std::cout << back->getName() << std::endl;
+    
     // Reporting what the inputparser found, to be removed...
     std::cout << "Start: " << config.grammar.start << std::endl;
     for(auto a: config.grammar.terminals)
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 5baf0bb..2a82d3d 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -3,7 +3,7 @@ add_executable(Parsodus-test
     )
 target_link_libraries(Parsodus-test
     #Parsodus-tables
-    Parsodus-backends
+    # Parsodus-backends
     pds
     mstch::mstch
     ${GTEST_BOTH_LIBRARIES}