Nicolas Winkler %!s(int64=6) %!d(string=hai) anos
pai
achega
edaf5d1243
Modificáronse 12 ficheiros con 145 adicións e 82 borrados
  1. 6 5
      src/AstVisitor.cpp
  2. 29 11
      src/Driver.cpp
  3. 4 3
      src/Driver.h
  4. 8 2
      src/ErrorReporting.cpp
  5. 30 0
      src/ErrorReporting.h
  6. 3 0
      src/Scope.cpp
  7. 1 0
      src/Scope.h
  8. 23 18
      src/Semantic.cpp
  9. 6 28
      src/Semantic.h
  10. 1 1
      src/lexer.l
  11. 2 2
      src/main.cpp
  12. 32 12
      src/parser.y

+ 6 - 5
src/AstVisitor.cpp

@@ -1,5 +1,6 @@
 #include "AstVisitor.h"
 #include "Ast.h"
+#include "ErrorReporting.h"
 
 #include <typeinfo>
 
@@ -33,7 +34,7 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::FieldDeclarati
         f->type = type.value();
     }
     else {
-        throw sem::SemanticException(sem::SemanticException::UNKNOWN_TYPE,
+        throw SemanticError(SemanticError::UNKNOWN_TYPE,
             ast.type,
             ast.pos
         );
@@ -46,7 +47,7 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::MethodDefiniti
 {
     auto returnType = scope.getType(ast.type);
     if (!returnType) {
-        throw sem::SemanticException(sem::SemanticException::UNKNOWN_TYPE,
+        throw SemanticError(SemanticError::UNKNOWN_TYPE,
             ast.type,
             ast.pos
         );
@@ -83,7 +84,7 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::VariableDeclar
         v->type = type.value();
     }
     else {
-        throw sem::SemanticException(sem::SemanticException::UNKNOWN_TYPE,
+        throw SemanticError(SemanticError::UNKNOWN_TYPE,
             ast.type,
             ast.pos
         );
@@ -109,7 +110,7 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::DoEndBlock& as
             auto type = body->scope.getType(nvs->type);
 
             if (!type)
-                throw sem::SemanticException(sem::SemanticException::UNKNOWN_TYPE, nvs->type, nvs->pos);
+                throw SemanticError(SemanticError::UNKNOWN_TYPE, nvs->type, nvs->pos);
 
             auto var = std::make_unique<sem::Variable>(type.value(), nvs->name);
             body->scope.putVariable(nvs->name, std::move(var));
@@ -186,7 +187,7 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::FeatureCall& a
         printf("var not found: %s\n", ast.name.c_str());
         printf("current scope: %s\n", scope.toString().c_str());
 #endif
-        throw sem::SemanticException(sem::SemanticException::FEATURE_NOT_FOUND, ast.name, ast.pos);
+        throw SemanticError(SemanticError::FEATURE_NOT_FOUND, ast.name, ast.pos);
     }
 }
 

+ 29 - 11
src/Driver.cpp

@@ -8,7 +8,7 @@
 
 #include <cstdio>
 
-extern std::unique_ptr<std::vector<std::unique_ptr<qlow::ast::Class>>> parsedClasses;
+extern std::unique_ptr<std::vector<std::unique_ptr<qlow::ast::AstObject>>> parsedClasses;
 extern FILE* qlow_parser_in;
 extern int qlow_parser_parse(void);
 extern const char* qlow_parser_filename;
@@ -61,16 +61,16 @@ int Driver::run(void)
     
     //logger.logError("driver not yet implemented", {options.emitAssembly ? "asm" : "noasm", 10, 11, 12, 13});
     
-    std::vector<std::unique_ptr<qlow::ast::Class>> classes;
+    std::vector<std::unique_ptr<qlow::ast::AstObject>> objects;
     for (auto& filename : options.infiles) {
         std::FILE* file = std::fopen(filename.c_str(), "r");
         ::qlow_parser_filename = filename.c_str();
         
         try {
-            auto newClasses = parseFile(file);
-            classes.insert(classes.end(),
-                           std::make_move_iterator(newClasses.begin()),
-                           std::make_move_iterator(newClasses.end()));
+            auto newObjects = parseFile(file);
+            objects.insert(objects.end(),
+                           std::make_move_iterator(newObjects.begin()),
+                           std::make_move_iterator(newObjects.end()));
         }
         catch (const CompileError& ce) {
             ce.print(logger);
@@ -86,8 +86,18 @@ int Driver::run(void)
     }
     
     
-    std::unique_ptr<qlow::sem::GlobalScope> semClasses =
-        qlow::sem::createFromAst(*parsedClasses.get());
+    std::unique_ptr<qlow::sem::GlobalScope> semClasses = nullptr;
+    try {
+        semClasses =
+            qlow::sem::createFromAst(objects);
+    }
+    catch(SemanticError& se) {
+        se.print(logger);
+        return 1;
+    }
+    catch(const char* err) {
+        logger.logError(err);
+    }
 
     for (auto& [a, b] : semClasses->classes) {
         logger.debug() << a << ": " << b->toString() << std::endl;
@@ -96,7 +106,8 @@ int Driver::run(void)
     auto main = semClasses->classes.find("Main");
     qlow::sem::Class* mainClass = nullptr;
     if (main == semClasses->classes.end()) {
-        throw "No Main class found!";
+        logger.logError("No Main class found");
+        return 1;
     }
     else {
         mainClass = main->second.get();
@@ -112,7 +123,14 @@ int Driver::run(void)
     
     logger.debug() << "starting code generation!" << std::endl;
 
-    auto mod = qlow::gen::generateModule(semClasses->classes);
+    std::unique_ptr<llvm::Module> mod = nullptr;
+    
+    try {
+        mod = qlow::gen::generateModule(semClasses->classes);
+    }
+    catch (const char* err) {
+        logger.logError(err);
+    }
     qlow::gen::generateObjectFile("obj.o", std::move(mod));
     
     logger.debug() << "object exported!" << std::endl;
@@ -121,7 +139,7 @@ int Driver::run(void)
 }
 
 
-std::vector<std::unique_ptr<qlow::ast::Class>> Driver::parseFile(FILE* file)
+std::vector<std::unique_ptr<qlow::ast::AstObject>> Driver::parseFile(FILE* file)
 {
     ::qlow_parser_in = file;
     if (!::qlow_parser_in)

+ 4 - 3
src/Driver.h

@@ -14,8 +14,9 @@ namespace qlow
     class Driver;
     
     
-    namespace ast {
-        struct Class;
+    namespace ast
+    {
+        struct AstObject;
     }
 }
 
@@ -42,7 +43,7 @@ public:
     
     /// \brief runs the parser over a given stream
     /// \warning Don't call concurrently. Not supported!
-    std::vector<std::unique_ptr<qlow::ast::Class>> parseFile(FILE* file);
+    std::vector<std::unique_ptr<qlow::ast::AstObject>> parseFile(FILE* file);
 };
 
 

+ 8 - 2
src/ErrorReporting.cpp

@@ -4,6 +4,7 @@
 
 using qlow::CompileError;
 using qlow::SyntaxError;
+using qlow::SemanticError;
 
 
 CompileError::~CompileError(void)
@@ -42,8 +43,6 @@ void CompileError::underlineError(Logger& logger) const
 }
 
 
-
-
 void SyntaxError::print(Logger& logger) const
 {
     logger.logError("Syntax error", where);
@@ -51,3 +50,10 @@ void SyntaxError::print(Logger& logger) const
 }
 
 
+void SemanticError::print(Logger& logger) const
+{
+    logger.logError(message, where);
+    underlineError(logger);
+}
+
+

+ 30 - 0
src/ErrorReporting.h

@@ -11,6 +11,7 @@ namespace qlow
     class CompileError;
     
     class SyntaxError;
+    class SemanticError;
 }
 
 
@@ -55,4 +56,33 @@ public:
     virtual void print(Logger&) const override;
 };
 
+
+class qlow::SemanticError : public CompileError
+{
+    std::string message;
+public:
+    enum ErrorCode
+    {
+        UNKNOWN_TYPE,
+        DUPLICATE_CLASS_DEFINITION,
+        DUPLICATE_FIELD_DECLARATION,
+        DUPLICATE_METHOD_DEFINITION,
+        
+        FEATURE_NOT_FOUND,
+    };
+    
+    
+    ErrorCode errorCode;
+public:
+    inline SemanticError(ErrorCode ec, const std::string& arg, const
+        qlow::CodePosition& where) :
+            CompileError{ where },
+            message{ arg },
+            errorCode{ ec }
+    {}
+
+    virtual void print(Logger&) const override;
+};
+
+
 #endif // QLOW_ERROR_REPORTING

+ 3 - 0
src/Scope.cpp

@@ -17,6 +17,9 @@ sem::Variable* sem::GlobalScope::getVariable(const std::string& name)
 
 sem::Method* sem::GlobalScope::getMethod(const std::string& name)
 {
+    if (const auto& f = functions.find(name); f != functions.end()) {
+        return f->second.get();
+    }
     return nullptr;
 }
 

+ 1 - 0
src/Scope.h

@@ -48,6 +48,7 @@ class qlow::sem::GlobalScope : public Scope
 {
 public:
     SymbolTable<Class> classes;
+    SymbolTable<Method> functions;
 public:
     virtual Variable* getVariable(const std::string& name);
     virtual Method* getMethod(const std::string& name);

+ 23 - 18
src/Semantic.cpp

@@ -1,4 +1,5 @@
 #include "Semantic.h"
+#include "Ast.h"
 #include "AstVisitor.h"
 
 #include "CodegenVisitor.h"
@@ -13,8 +14,10 @@ namespace sem
 {
 
 std::unique_ptr<GlobalScope>
-    createFromAst(const std::vector<std::unique_ptr<qlow::ast::Class>>& classes)
+    createFromAst(const std::vector<std::unique_ptr<qlow::ast::AstObject>>& objects)
 {
+    
+    Logger& logger = Logger::getInstance();
 
 #ifdef DEBUGGING
     printf("starting building semantic representation\n");
@@ -22,8 +25,13 @@ std::unique_ptr<GlobalScope>
 
     // create classes
     std::unique_ptr<sem::GlobalScope> globalScope = std::make_unique<sem::GlobalScope>();
-    for (auto& astClass : classes) {
-        globalScope->classes[astClass->name] = std::make_unique<sem::Class>(astClass.get(), *globalScope);
+    for (auto& astObject : objects) {
+        if (auto* cls = dynamic_cast<ast::Class*>(astObject.get()); cls) {
+            globalScope->classes[cls->name] = std::make_unique<sem::Class>(cls, *globalScope);
+        }
+        else if (auto* function = dynamic_cast<ast::MethodDefinition*>(astObject.get()); function) {
+            globalScope->functions[function->name] = std::make_unique<sem::Method>(function, *globalScope);
+        }
     }
 
 #ifdef DEBUGGING
@@ -38,14 +46,14 @@ std::unique_ptr<GlobalScope>
             
             if (auto* field = dynamic_cast<qlow::ast::FieldDeclaration*> (feature.get()); field) {
                 if (semClass->fields.find(field->name) != semClass->fields.end()) // throw, if field already exists
-                    throw SemanticException(SemanticException::DUPLICATE_FIELD_DECLARATION, field->name, field->pos);
+                    throw SemanticError(SemanticError::DUPLICATE_FIELD_DECLARATION, field->name, field->pos);
                 
                 // otherwise add to the fields list
                 semClass->fields[field->name] = unique_dynamic_cast<Field>(field->accept(av, semClass->scope));
             }
             else if (auto* method = dynamic_cast<qlow::ast::MethodDefinition*> (feature.get()); method) {
                 if (semClass->methods.find(method->name) != semClass->methods.end()) // throw, if method already exists
-                    throw SemanticException(SemanticException::DUPLICATE_METHOD_DEFINITION, method->name, method->pos);
+                    throw SemanticError(SemanticError::DUPLICATE_METHOD_DEFINITION, method->name, method->pos);
                 
                 // otherwise add to the methods list
                 semClass->methods[method->name] = unique_dynamic_cast<Method>(method->accept(av, semClass->scope));
@@ -57,6 +65,16 @@ std::unique_ptr<GlobalScope>
         }
     }
     
+    for (auto& [name, method] : globalScope->functions) {
+        auto returnType = globalScope->getType(method->astNode->type);
+        if (returnType) {
+            method->returnType = returnType.value();
+        }
+        else {
+            SemanticError se(SemanticError::UNKNOWN_TYPE, method->astNode->type, method->astNode->pos);
+        }
+    }
+    
 #ifdef DEBUGGING
     printf("created all methods and fields\n");
 #endif
@@ -195,19 +213,6 @@ std::string FeatureCallStatement::toString(void) const
 }
 
 
-std::string SemanticException::getMessage(void) const
-{
-    static std::map<ErrorCode, std::string> error = {
-        {UNKNOWN_TYPE, "unknown type"},
-        {FEATURE_NOT_FOUND, "method or variable not found"}
-    };
-    
-    std::string pos = std::to_string(where.first_line) + ":" +
-        std::to_string(where.first_column);
-    
-    return pos + ": " + error[errorCode] + ": " + message;
-}
-
 
 
 

+ 6 - 28
src/Semantic.h

@@ -17,7 +17,7 @@ namespace qlow
     namespace sem
     {
         std::unique_ptr<GlobalScope>
-            createFromAst(const std::vector<std::unique_ptr<qlow::ast::Class>>& classes);
+            createFromAst(const std::vector<std::unique_ptr<qlow::ast::AstObject>>& objects);
 
         struct SemanticObject;
         struct Class;
@@ -143,6 +143,11 @@ struct qlow::sem::Method : public SemanticObject
     inline Method(Scope& parentScope, const Type& returnType) :
         returnType{ returnType }, scope{ parentScope } {}
     
+    inline Method(ast::MethodDefinition* astNode, Scope& parentScope) :
+        astNode{ astNode }, scope{ parentScope }
+    {
+    }
+    
     virtual std::string toString(void) const override;
 };
 
@@ -280,33 +285,6 @@ struct qlow::sem::FeatureCallStatement : public Statement
 };
 
 
-class qlow::sem::SemanticException
-{
-    std::string message;
-    qlow::CodePosition where;
-public:
-    enum ErrorCode
-    {
-        UNKNOWN_TYPE,
-        DUPLICATE_CLASS_DEFINITION,
-        DUPLICATE_FIELD_DECLARATION,
-        DUPLICATE_METHOD_DEFINITION,
-        
-        FEATURE_NOT_FOUND,
-    };
-    
-    
-    ErrorCode errorCode;
-public:
-    inline SemanticException(ErrorCode ec, const std::string& arg, const
-        qlow::CodePosition& where) :
-        message{ arg }, where{ where }, errorCode{ ec }
-    {}
-
-    std::string getMessage(void) const;
-};
-
-
 
 
 

+ 1 - 1
src/lexer.l

@@ -118,6 +118,6 @@ extern const char* qlow_parser_filename;
 [0-9_]+                 SET_STRING; return INT_LITERAL;
 0x[0-9A-Fa-f]+          SET_STRING; return INT_LITERAL;
 [a-zA-Z_][a-zA-Z0-9_]*  SET_STRING; return IDENTIFIER;
-.                       printf("Unexpected symbol %s.\n", std::string(yytext, yyleng).c_str()); yyterminate();
+.                       SET_STRING; return UNEXPECTED_SYMBOL; // printf("Unexpected symbol %s.\n", std::string(yytext, yyleng).c_str()); yyterminate();
 
 %%

+ 2 - 2
src/main.cpp

@@ -31,7 +31,7 @@ int main(int argc, char** argv)
     driver.run();
     
     return 0;
-    
+    /*
     {
     const char* filename = argv[optind];
     
@@ -101,7 +101,7 @@ int main(int argc, char** argv)
 
     for (auto&& c : *parsedClasses) {
         delete c.release();
-    }
+    }*/
 }
 
 

+ 32 - 12
src/parser.y

@@ -41,9 +41,13 @@ int qlow_parser_error(const char* msg)
     //printf("error happened: %s\n", msg);
 }
 
+void reportError(const qlow::SyntaxError& se)
+{
+    qlow::Logger& logger = qlow::Logger::getInstance();
+    se.print(logger);
+}
 
-using ClassList = std::vector<std::unique_ptr<qlow::ast::Class>>;
-std::unique_ptr<ClassList> parsedClasses;
+std::unique_ptr<std::vector<std::unique_ptr<qlow::ast::AstObject>>> parsedClasses;
 const char* qlow_parser_filename = "";
 
 # define YYLLOC_DEFAULT(Cur, Rhs, N)                      \
@@ -87,7 +91,7 @@ typedef qlow::CodePosition QLOW_PARSER_LTYPE;
 //%define api.location.type {qlow::CodePosition}
 
 %union {
-    std::vector<std::unique_ptr<qlow::ast::Class>>* classes;
+    std::vector<std::unique_ptr<qlow::ast::AstObject>>* topLevel;
     qlow::ast::Class* classDefinition;
     qlow::ast::FeatureDeclaration* featureDeclaration;
     std::vector<std::unique_ptr<qlow::ast::FeatureDeclaration>>* featureList;
@@ -124,8 +128,9 @@ typedef qlow::CodePosition QLOW_PARSER_LTYPE;
 %token <token> NEW_LINE
 %token <token> SEMICOLON COLON COMMA DOT ASSIGN
 %token <token> ROUND_LEFT ROUND_RIGHT
+%token <string> UNEXPECTED_SYMBOL
 
-%type <classes> classes
+%type <topLevel> topLevel 
 %type <classDefinition> classDefinition
 %type <featureDeclaration> featureDeclaration fieldDeclaration methodDefinition
 %type <featureList> featureList
@@ -145,6 +150,11 @@ typedef qlow::CodePosition QLOW_PARSER_LTYPE;
 %type <unaryOperation> unaryOperation
 %type <binaryOperation> binaryOperation
 
+%destructor { } <token>
+%destructor { } <op>
+%destructor { } <topLevel> // don't delete everything ;)
+%destructor { if ($$) delete $$; } <*>
+
 %left ASTERISK SLASH
 %left PLUS MINUS
 %left EQUALS
@@ -152,19 +162,20 @@ typedef qlow::CodePosition QLOW_PARSER_LTYPE;
 %left AND
 %left OR XOR
 
-%start classes
+%start topLevel
 
 %%
 
 
 /* list of class definitions */
-classes:
+topLevel:
     /* empty */ {
-       parsedClasses = std::make_unique<ClassList>();
+       parsedClasses = std::make_unique<std::vector<std::unique_ptr<qlow::ast::AstObject>>>();
     }
     |
-    classes classDefinition {
-        parsedClasses->push_back(std::move(std::unique_ptr<Class>($2)));
+    topLevel classDefinition {
+        parsedClasses->push_back(std::move(std::unique_ptr<qlow::ast::Class>($2)));
+        $2 = nullptr;
     };
 
 
@@ -317,7 +328,9 @@ statement:
     error statementEnd {
         $$ = nullptr;
         //printf("error happened here (%s): %d\n", qlow_parser_filename, @1.first_line);
-        throw qlow::SyntaxError(@1);
+        //throw qlow::SyntaxError(@1);
+        reportError(qlow::SyntaxError(@1));
+        printf("unexpected token: %d\n", $<token>1);
     }
     ;
     
@@ -380,8 +393,15 @@ expression:
     INT_LITERAL {
         $$ = new IntConst(std::move(*$1), @$);
         delete $1;
-    };
-
+    };/*
+    |
+    error {
+        $$ = nullptr;
+        reportError(qlow::SyntaxError(@1));
+        //throw qlow::SyntaxError(@1);
+    }
+    ;
+*/
 
 operationExpression:
     binaryOperation {