Selaa lähdekoodia

add better error reporting

Nicolas Winkler 6 vuotta sitten
vanhempi
commit
78e0fea436
8 muutettua tiedostoa jossa 210 lisäystä ja 28 poistoa
  1. 1 12
      src/Ast.h
  2. 44 2
      src/Driver.cpp
  3. 53 0
      src/ErrorReporting.cpp
  4. 58 0
      src/ErrorReporting.h
  5. 3 0
      src/Logging.h
  6. 2 0
      src/lexer.l
  7. 2 0
      src/main.cpp
  8. 47 14
      src/parser.y

+ 1 - 12
src/Ast.h

@@ -30,6 +30,7 @@
 
 #include "Visitor.h"
 #include "Util.h"
+#include "ErrorReporting.h"
 
 namespace qlow
 {
@@ -82,18 +83,6 @@ namespace qlow
 }
 
 
-/*!
- * \brief bison-compatible location struct
- */
-struct qlow::CodePosition
-{
-    const char* filename = "";
-    int first_line;
-    int last_line;
-    int first_column;
-    int last_column;
-};
-
 
 struct qlow::ast::AstObject :
     public Visitable<std::unique_ptr<sem::SemanticObject>, sem::Scope&, StructureVisitor>

+ 44 - 2
src/Driver.cpp

@@ -11,6 +11,7 @@
 extern std::unique_ptr<std::vector<std::unique_ptr<qlow::ast::Class>>> parsedClasses;
 extern FILE* qlow_parser_in;
 extern int qlow_parser_parse(void);
+extern const char* qlow_parser_filename;
 
 using namespace qlow;
 
@@ -63,10 +64,19 @@ int Driver::run(void)
     std::vector<std::unique_ptr<qlow::ast::Class>> classes;
     for (auto& filename : options.infiles) {
         std::FILE* file = std::fopen(filename.c_str(), "r");
+        ::qlow_parser_filename = filename.c_str();
         
         try {
-            classes = parseFile(file);
-        } catch (const char* errMsg) {
+            auto newClasses = parseFile(file);
+            classes.insert(classes.end(),
+                           std::make_move_iterator(newClasses.begin()),
+                           std::make_move_iterator(newClasses.end()));
+        }
+        catch (const CompileError& ce) {
+            ce.print(logger);
+            return 1;
+        }
+        catch (const char* errMsg) {
             logger.logError(errMsg);
             return 1;
         }
@@ -75,6 +85,38 @@ int Driver::run(void)
             std::fclose(file);
     }
     
+    
+    std::unique_ptr<qlow::sem::GlobalScope> semClasses =
+        qlow::sem::createFromAst(*parsedClasses.get());
+
+    for (auto& [a, b] : semClasses->classes) {
+        logger.debug() << a << ": " << b->toString() << std::endl;
+    }
+
+    auto main = semClasses->classes.find("Main");
+    qlow::sem::Class* mainClass = nullptr;
+    if (main == semClasses->classes.end()) {
+        throw "No Main class found!";
+    }
+    else {
+        mainClass = main->second.get();
+    }
+    auto mainmain = mainClass->methods.find("main");
+    qlow::sem::Method* mainMethod = nullptr;
+    if (mainmain == mainClass->methods.end()) {
+        //throw "No main method found inside Main class!";
+    }
+    else {
+        mainMethod = mainmain->second.get();
+    }
+    
+    logger.debug() << "starting code generation!" << std::endl;
+
+    auto mod = qlow::gen::generateModule(semClasses->classes);
+    qlow::gen::generateObjectFile("obj.o", std::move(mod));
+    
+    logger.debug() << "object exported!" << std::endl;
+    
     return 0;
 }
 

+ 53 - 0
src/ErrorReporting.cpp

@@ -0,0 +1,53 @@
+#include "ErrorReporting.h"
+
+#include <fstream>
+
+using qlow::CompileError;
+using qlow::SyntaxError;
+
+
+CompileError::~CompileError(void)
+{
+}
+
+
+void CompileError::underlineError(Logger& logger) const
+{
+    // TODO implement for multiline errors
+    if (where.first_line != where.last_line)
+        throw "TODO";
+    std::ifstream file(where.filename);
+    
+    if (!file)
+        return;
+    
+    size_t lineNr = 1;
+    while (lineNr < where.first_line) {
+        if (file.get() == '\n') {
+            lineNr++;
+        }
+    }
+    std::string line;
+    std::getline(file, line);
+    logger.err() << line << std::endl;
+    for (size_t i = 0; i < where.first_column; i++) {
+        logger.err() << ' ';
+    }
+    logger.foreground(Logger::Color::RED, true);
+    for (size_t i = where.first_column; i < where.last_column; i++) {
+        logger.err() << '^';
+    }
+    logger.removeFormatting();
+    logger.err() << std::endl;
+}
+
+
+
+
+void SyntaxError::print(Logger& logger) const
+{
+    logger.logError("Syntax error", where);
+    underlineError(logger);
+}
+
+

+ 58 - 0
src/ErrorReporting.h

@@ -0,0 +1,58 @@
+#ifndef QLOW_ERROR_REPORTING
+#define QLOW_ERROR_REPORTING
+
+#include "Logging.h"
+
+
+namespace qlow
+{
+    struct CodePosition;
+    
+    class CompileError;
+    
+    class SyntaxError;
+}
+
+
+/*!
+ * \brief bison-compatible location struct
+ */
+struct qlow::CodePosition
+{
+    const char* filename = "";
+    int first_line;
+    int last_line;
+    int first_column;
+    int last_column;
+};
+
+
+class qlow::CompileError
+{
+protected:
+    CodePosition where;
+public:
+    inline CompileError(const CodePosition& where) :
+        where{ where }
+    {
+    }
+    
+    virtual ~CompileError(void);
+    virtual void print(Logger& logger) const = 0;
+    
+    void underlineError(Logger& logger) const;
+};
+
+
+class qlow::SyntaxError : public CompileError
+{
+public:
+    inline SyntaxError(const CodePosition& where) :
+        CompileError{ where }
+    {
+    }
+    
+    virtual void print(Logger&) const override;
+};
+
+#endif // QLOW_ERROR_REPORTING

+ 3 - 0
src/Logging.h

@@ -38,6 +38,7 @@ protected:
         inline int overflow(int c) override { return c; }
     };
     
+public:
     enum Color {
         BLACK = 0,
         RED,
@@ -48,6 +49,7 @@ protected:
         CYAN,
         WHITE
     };
+private:
 
     std::ostream& target;
     NullStream nullStream;
@@ -60,6 +62,7 @@ protected:
 
     static Logger instance;
 
+public:
     void foreground(Color color, bool bright);
     void background(Color color, bool bright);
     void bold(void);

+ 2 - 0
src/lexer.l

@@ -37,6 +37,7 @@ int commentDepth;
 
 size_t offset;
 extern QLOW_PARSER_LTYPE qlow_parser_lloc;
+extern const char* qlow_parser_filename;
 
 #define YY_USER_ACTION                          \
   do {                                          \
@@ -45,6 +46,7 @@ extern QLOW_PARSER_LTYPE qlow_parser_lloc;
     offset += yyleng;                           \
     qlow_parser_lloc.last_line = yylineno;      \
     qlow_parser_lloc.last_column = offset;      \
+    qlow_parser_lloc.filename = qlow_parser_filename; \
   } while(0);
 
 %}

+ 2 - 0
src/main.cpp

@@ -30,6 +30,8 @@ int main(int argc, char** argv)
     qlow::Driver driver(argc, argv);
     driver.run();
     
+    return 0;
+    
     {
     const char* filename = argv[optind];
     

+ 47 - 14
src/parser.y

@@ -27,6 +27,7 @@
 #include <iostream>
 #include <cstdio>
 #include "Ast.h"
+#include "ErrorReporting.h"
 
 using namespace qlow::ast;
 
@@ -34,25 +35,54 @@ extern int qlow_parser_lex();
 
 void yy_pop_state(void);
 
-int qlow_parser_error(const char*)
+int qlow_parser_error(const char* msg)
 {
-    throw "syntax error";
+    //throw msg;
+    //printf("error happened: %s\n", msg);
 }
 
-#define QLOW_PARSER_LTYPE_IS_DECLARED
-typedef qlow::CodePosition QLOW_PARSER_LTYPE;
-
 
 using ClassList = std::vector<std::unique_ptr<qlow::ast::Class>>;
 std::unique_ptr<ClassList> parsedClasses;
+const char* qlow_parser_filename = "";
+
+# define YYLLOC_DEFAULT(Cur, Rhs, N)                      \
+do                                                        \
+  if (N)                                                  \
+    {                                                     \
+      (Cur).first_line   = YYRHSLOC(Rhs, 1).first_line;   \
+      (Cur).first_column = YYRHSLOC(Rhs, 1).first_column; \
+      (Cur).last_line    = YYRHSLOC(Rhs, N).last_line;    \
+      (Cur).last_column  = YYRHSLOC(Rhs, N).last_column;  \
+      (Cur).filename     = YYRHSLOC(Rhs, 1).filename;     \
+    }                                                     \
+  else                                                    \
+    {                                                     \
+      (Cur).first_line   = (Cur).last_line   =            \
+        YYRHSLOC(Rhs, 0).last_line;                       \
+      (Cur).first_column = (Cur).last_column =            \
+        YYRHSLOC(Rhs, 0).last_column;                     \
+    }                                                     \
+while (0)
 
 %}
 
 
 %define api.prefix {qlow_parser_}
+%define parse.error verbose
+// %define parse.lac full
 
 %locations
-%code requires { #include "Ast.h" }
+%code requires {
+#include "Ast.h"
+typedef qlow::CodePosition QLOW_PARSER_LTYPE;
+#define QLOW_PARSER_LTYPE_IS_DECLARED
+}
+
+%initial-action
+{
+  @$.filename = qlow_parser_filename;
+};
 
 //%define api.location.type {qlow::CodePosition}
 
@@ -232,8 +262,8 @@ ifElseBlock:
     |
     IF expression DO statements ELSE statements END {
         $$ = new IfElseBlock(std::unique_ptr<Expression>($2),
-                             std::make_unique<DoEndBlock>(std::move(*$4), @$),
-                             std::make_unique<DoEndBlock>(std::move(*$6), @$), @$);
+                             std::make_unique<DoEndBlock>(std::move(*$4), @4),
+                             std::make_unique<DoEndBlock>(std::move(*$6), @6), @$);
         $2 = nullptr;
         delete $4;
         delete $6;
@@ -247,12 +277,9 @@ statements:
     |
     statements statement {
         $$ = $1;
-        $$->push_back(std::unique_ptr<Statement>($2));
-    }
-    |
-    statements error {
-        //$$<statements> = $1;
-        printf("ERROR\n");
+        // statements can be null on errors
+        if ($1 != nullptr)
+            $$->push_back(std::unique_ptr<Statement>($2));
     };
 
 /*!
@@ -286,6 +313,12 @@ statement:
     ifElseBlock statementEnd {
         $$ = $1;
     }
+    |
+    error statementEnd {
+        $$ = nullptr;
+        //printf("error happened here (%s): %d\n", qlow_parser_filename, @1.first_line);
+        throw qlow::SyntaxError(@1);
+    }
     ;
     
 statementEnd: