Sfoglia il codice sorgente

worked on the semantic analyzer

Nicolas Winkler 7 anni fa
parent
commit
3326654911
10 ha cambiato i file con 171 aggiunte e 90 eliminazioni
  1. 2 2
      src/Ast.cpp
  2. 21 16
      src/Ast.h
  3. 14 14
      src/AstVisitor.cpp
  4. 15 14
      src/AstVisitor.h
  5. 80 25
      src/Semantic.cpp
  6. 15 2
      src/Semantic.h
  7. 8 1
      src/Util.h
  8. 14 14
      src/Visitor.h
  9. 1 1
      src/main.cpp
  10. 1 1
      src/makefile

+ 2 - 2
src/Ast.cpp

@@ -11,9 +11,9 @@ AstObject::~AstObject(void)
 
 
 #define ACCEPT_DEFINITION(ClassName) \
-std::unique_ptr<qlow::sem::SemanticObject> ClassName::accept(AstVisitor& v) \
+std::unique_ptr<qlow::sem::SemanticObject> ClassName::accept(AstVisitor& v, const sem::SymbolTable<sem::Class>& c) \
 { \
-    v.visit(*this); \
+    v.visit(*this, c); \
 }
 
 ACCEPT_DEFINITION(Class)

+ 21 - 16
src/Ast.h

@@ -26,6 +26,7 @@
 #include <vector>
 #include <memory>
 #include <utility>
+#include <map>
 
 #include "Visitor.h"
 
@@ -67,12 +68,16 @@ namespace qlow
     namespace sem
     {
         struct SemanticObject;
+        struct Class;
+        
+        template<typename T>
+        using SymbolTable = std::map<std::string, std::unique_ptr<T>>;
     }
 }
 
 
 struct qlow::ast::AstObject :
-    public Visitable<std::unique_ptr<sem::SemanticObject>, AstVisitor>
+    public Visitable<std::unique_ptr<sem::SemanticObject>, const sem::SymbolTable<sem::Class>, AstVisitor>
 {
     virtual ~AstObject(void);
 };
@@ -84,11 +89,11 @@ struct qlow::ast::Class : public AstObject
     List<FeatureDeclaration> features;
     
     inline Class(const std::string& name, List<FeatureDeclaration>& features) :
-        name(name), features(std::move(features))
+        name{ name }, features(std::move(features))
     {
     }
 
-    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v);
+    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v, const sem::SymbolTable<sem::Class>&) override;
 };
 
 
@@ -102,7 +107,7 @@ struct qlow::ast::FeatureDeclaration : public AstObject
     {
     }
 
-    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v);
+    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v, const sem::SymbolTable<sem::Class>&);
 };
 
 
@@ -113,7 +118,7 @@ struct qlow::ast::FieldDeclaration : public FeatureDeclaration
     {
     }
 
-    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v);
+    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v, const sem::SymbolTable<sem::Class>&);
 };
 
 
@@ -138,7 +143,7 @@ struct qlow::ast::MethodDefinition : public FeatureDeclaration
     {
     }
 
-    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v);
+    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v, const sem::SymbolTable<sem::Class>&);
 };
 
 
@@ -151,7 +156,7 @@ struct qlow::ast::VariableDeclaration  : public AstObject
     {
     }
 
-    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v);
+    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v, const sem::SymbolTable<sem::Class>&);
 };
 
 
@@ -163,7 +168,7 @@ struct qlow::ast::ArgumentDeclaration :
     {
     }
 
-    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v);
+    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v, const sem::SymbolTable<sem::Class>&);
 };
 
 
@@ -176,7 +181,7 @@ struct qlow::ast::DoEndBlock : public AstObject
     {
     }
 
-    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v);
+    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v, const sem::SymbolTable<sem::Class>&);
 };
 
 
@@ -184,13 +189,13 @@ struct qlow::ast::Statement : public virtual AstObject
 {
     virtual ~Statement(void);
 
-    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v);
+    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v, const sem::SymbolTable<sem::Class>&);
 };
 
 
 struct qlow::ast::Expression : public virtual AstObject
 {
-    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v);
+    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v, const sem::SymbolTable<sem::Class>&);
 };
 
 
@@ -212,7 +217,7 @@ struct qlow::ast::FeatureCall : public Expression, public Statement
     {
     }
 
-    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v);
+    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v, const sem::SymbolTable<sem::Class>&);
 };
 
 
@@ -226,7 +231,7 @@ struct qlow::ast::AssignmentStatement : public Statement
     {
     }
 
-    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v);
+    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v, const sem::SymbolTable<sem::Class>&);
 };
 
 
@@ -239,7 +244,7 @@ struct qlow::ast::NewVariableStatement : public Statement
     {
     } 
 
-    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v);
+    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v, const sem::SymbolTable<sem::Class>&);
 };
 
 
@@ -275,7 +280,7 @@ struct qlow::ast::UnaryOperation : public Operation
     {
     }
 
-    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v);
+    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v, const sem::SymbolTable<sem::Class>&);
 };
 
 
@@ -290,7 +295,7 @@ struct qlow::ast::BinaryOperation : public Operation
     {
     }
 
-    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v);
+    std::unique_ptr<sem::SemanticObject> accept(AstVisitor& v, const sem::SymbolTable<sem::Class>&);
 };
 
 

+ 14 - 14
src/AstVisitor.cpp

@@ -3,7 +3,7 @@
 
 using namespace qlow;
 
-std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::Class& ast)
+std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::Class& ast, const sem::SymbolTable<sem::Class>& classes)
 {
     auto c = std::make_unique<sem::Class> ();
     c->name = ast.name;
@@ -12,13 +12,13 @@ std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::Class& ast)
 }
 
 
-std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::FeatureDeclaration& ast)
+std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::FeatureDeclaration& ast, const sem::SymbolTable<sem::Class>& classes)
 {
     // not needed, because 
 }
 
 
-std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::FieldDeclaration& ast)
+std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::FieldDeclaration& ast, const sem::SymbolTable<sem::Class>& classes)
 {
     auto f = std::make_unique<sem::Field>();
     f->name = ast.name;
@@ -26,7 +26,7 @@ std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::FieldDeclaration& as
 }
 
 
-std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::MethodDefinition& ast)
+std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::MethodDefinition& ast, const sem::SymbolTable<sem::Class>& classes)
 {
     auto m = std::make_unique<sem::Method>();
     m->name = ast.name;
@@ -34,53 +34,53 @@ std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::MethodDefinition& as
 }
 
 
-std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::VariableDeclaration& ast)
+std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::VariableDeclaration& ast, const sem::SymbolTable<sem::Class>& classes)
 {
     
 }
 
 
-std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::ArgumentDeclaration& ast)
+std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::ArgumentDeclaration& ast, const sem::SymbolTable<sem::Class>& classes)
 {
 }
 
 
-std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::DoEndBlock& ast)
+std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::DoEndBlock& ast, const sem::SymbolTable<sem::Class>& classes)
 {
 }
 
 
-std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::Statement& ast)
+std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::Statement& ast, const sem::SymbolTable<sem::Class>& classes)
 {
 }
 
 
-std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::Expression& ast)
+std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::Expression& ast, const sem::SymbolTable<sem::Class>& classes)
 {
 }
 
 
-std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::FeatureCall& ast)
+std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::FeatureCall& ast, const sem::SymbolTable<sem::Class>& classes)
 {
 }
 
 
-std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::AssignmentStatement& ast)
+std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::AssignmentStatement& ast, const sem::SymbolTable<sem::Class>& classes)
 {
 }
 
 
-std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::NewVariableStatement& ast)
+std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::NewVariableStatement& ast, const sem::SymbolTable<sem::Class>& classes)
 {
 }
 
 
-std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::UnaryOperation& ast)
+std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::UnaryOperation& ast, const sem::SymbolTable<sem::Class>& classes)
 {
 }
 
 
-std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::BinaryOperation& ast)
+std::unique_ptr<sem::SemanticObject> AstVisitor::visit(ast::BinaryOperation& ast, const sem::SymbolTable<sem::Class>& classes)
 {
 }
 

+ 15 - 14
src/AstVisitor.h

@@ -53,6 +53,7 @@ namespace qlow
 class qlow::AstVisitor :
     public Visitor<
         std::unique_ptr<sem::SemanticObject>,
+        const sem::SymbolTable<sem::Class>&,
 
         ast::Class,
         ast::FeatureDeclaration,
@@ -73,20 +74,20 @@ class qlow::AstVisitor :
 public:
     using ReturnType = std::unique_ptr<sem::SemanticObject>;
 
-    ReturnType visit(ast::Class& ast) override;
-    ReturnType visit(ast::FeatureDeclaration& ast) override;
-    ReturnType visit(ast::FieldDeclaration& ast) override;
-    ReturnType visit(ast::MethodDefinition& ast) override;
-    ReturnType visit(ast::VariableDeclaration& ast) override;
-    ReturnType visit(ast::ArgumentDeclaration& ast) override;
-    ReturnType visit(ast::DoEndBlock& ast) override;
-    ReturnType visit(ast::Statement& ast) override;
-    ReturnType visit(ast::Expression& ast) override;
-    ReturnType visit(ast::FeatureCall& ast) override;
-    ReturnType visit(ast::AssignmentStatement& ast) override;
-    ReturnType visit(ast::NewVariableStatement& ast) override;
-    ReturnType visit(ast::UnaryOperation& ast) override;
-    ReturnType visit(ast::BinaryOperation& ast) override;
+    ReturnType visit(ast::Class& ast, const sem::SymbolTable<sem::Class>& classes) override;
+    ReturnType visit(ast::FeatureDeclaration& ast, const sem::SymbolTable<sem::Class>& classes) override;
+    ReturnType visit(ast::FieldDeclaration& ast, const sem::SymbolTable<sem::Class>& classes) override;
+    ReturnType visit(ast::MethodDefinition& ast, const sem::SymbolTable<sem::Class>& classes) override;
+    ReturnType visit(ast::VariableDeclaration& ast, const sem::SymbolTable<sem::Class>& classes) override;
+    ReturnType visit(ast::ArgumentDeclaration& ast, const sem::SymbolTable<sem::Class>& classes) override;
+    ReturnType visit(ast::DoEndBlock& ast, const sem::SymbolTable<sem::Class>& classes) override;
+    ReturnType visit(ast::Statement& ast, const sem::SymbolTable<sem::Class>& classes) override;
+    ReturnType visit(ast::Expression& ast, const sem::SymbolTable<sem::Class>& classes) override;
+    ReturnType visit(ast::FeatureCall& ast, const sem::SymbolTable<sem::Class>& classes) override;
+    ReturnType visit(ast::AssignmentStatement& ast, const sem::SymbolTable<sem::Class>& classes) override;
+    ReturnType visit(ast::NewVariableStatement& ast, const sem::SymbolTable<sem::Class>& classes) override;
+    ReturnType visit(ast::UnaryOperation& ast, const sem::SymbolTable<sem::Class>& classes) override;
+    ReturnType visit(ast::BinaryOperation& ast, const sem::SymbolTable<sem::Class>& classes) override;
 };
 
 

+ 80 - 25
src/Semantic.cpp

@@ -1,41 +1,72 @@
 #include "Semantic.h"
-
 #include "AstVisitor.h"
 
+#include "Util.h"
+
 using namespace qlow::sem;
 
 namespace qlow
 {
-    namespace sem
-    {
-        template<typename T, typename U>
-        std::unique_ptr<T> unique_dynamic_cast(std::unique_ptr<U>&& p)
-        {
-            return std::unique_ptr<T> (dynamic_cast<T*>(p.release()));
-        }
+namespace sem
+{
 
+/// i don't like this, but I lack better ideas at the moment.
+/// TODO: find better solution
+
+/*!
+* \brief tries to cast a unique_ptr and throws if it fails
+*/
+template<typename T, typename U>
+std::unique_ptr<T> unique_dynamic_cast(std::unique_ptr<U>&& p)
+{
+    U* released = p.release();
+    if (T* casted = dynamic_cast<T*>(released); casted)
+        return std::unique_ptr<T> (casted);
+    else {
+        delete released;
+        throw "invalid unique_dynamic_cast";
+    }
+}
 
-        SymbolTable<qlow::sem::Class>
-            createFromAst(std::vector<std::unique_ptr<qlow::ast::Class>>&
-                    classes)
-        {
-            AstVisitor av;
-
-            // create classes
-            SymbolTable<sem::Class> semClasses;
-            for (auto& astClass : classes) {
-                semClasses.insert(
-                    {
-                        astClass->name,
-                        std::make_unique<sem::Class>(astClass->name)
-                    }
-                );
+
+SymbolTable<qlow::sem::Class>
+    createFromAst(std::vector<std::unique_ptr<qlow::ast::Class>>& classes)
+{
+
+    // create classes
+    SymbolTable<sem::Class> semClasses;
+    for (auto& astClass : classes) {
+        semClasses.insert(
+            {
+                astClass->name,
+                std::make_unique<sem::Class>(astClass.get())
             }
+        );
+    }
 
-            return semClasses;
+    AstVisitor av;
+    
+    // create all methods and fields
+    for (auto& [name, semClass] : semClasses) {
+        for (auto& feature : semClass->astNode->features) {
+            if (auto* field = dynamic_cast<qlow::ast::FieldDeclaration*> (feature.get()); field) {
+                semClass->fields.insert({
+                    field->name,
+                    unique_dynamic_cast<Field>(av.visit(*field, semClasses))
+                });
+            }
+            if (auto* method = dynamic_cast<qlow::ast::MethodDefinition*> (feature.get()); method) {
+                semClass->methods.insert({
+                    method->name,
+                    unique_dynamic_cast<Method>(av.visit(*method, semClasses))
+                });
+            }
         }
-
     }
+    return semClasses;
+}
+
+}
 }
 
 
@@ -44,7 +75,31 @@ SemanticObject::~SemanticObject(void)
 }
 
 
+std::string SemanticObject::toString(void) const
+{
+    return "SemanticObject [" + util::toString(this) + "]";
+}
+
+
+std::string Class::toString(void) const
+{
+    std::string val = "Class[";
+    for (auto& field : fields)
+        val += field.second->toString() + ", ";
+    if (!fields.empty())
+        val = val.substr(0, val.length() - 2);
+    return val + "]";
+}
 
 
+std::string Field::toString(void) const
+{
+    return "Field[" + this->name + "]";
+}
 
 
+std::string Method::toString(void) const
+{
+    return "Method[" + this->name + "]";
+}
+

+ 15 - 2
src/Semantic.h

@@ -30,19 +30,28 @@ namespace qlow
 struct qlow::sem::SemanticObject
 {
     virtual ~SemanticObject(void);
+    
+    /**
+     * \brief converts the object to a readable string for debugging purposes. 
+     */
+    virtual std::string toString(void) const;
 };
 
 
 struct qlow::sem::Class : public SemanticObject
 {
+    qlow::ast::Class* astNode;
     std::string name;
     SymbolTable<Field> fields;
     SymbolTable<Method> methods;
 
-    inline Class(const std::string& name) :
-        name{ name }
+    Class(void) = default;
+    inline Class(qlow::ast::Class* astNode) :
+        astNode{ astNode }, name{ astNode->name }
     {
     }
+    
+    virtual std::string toString(void) const override;
 };
 
 
@@ -50,6 +59,8 @@ struct qlow::sem::Field : public SemanticObject
 {
     Class* type;
     std::string name;
+    
+    virtual std::string toString(void) const override;
 };
 
 
@@ -57,6 +68,8 @@ struct qlow::sem::Method : public SemanticObject
 {
     Class* returnType;
     std::string name;
+    
+    virtual std::string toString(void) const override;
 };
 
 

+ 8 - 1
src/Util.h

@@ -3,6 +3,7 @@
 
 #include <vector>
 #include <memory>
+#include <sstream>
 
 
 namespace qlow
@@ -11,6 +12,13 @@ namespace qlow
     {
         template<typename T>
         using OwningList = std::vector<std::unique_ptr<T>>;
+
+        inline std::string toString(const void* a)
+        {
+            std::ostringstream o;
+            o << a;
+            return o.str();
+        }
     }
 }
 
@@ -24,4 +32,3 @@ namespace qlow
 
 #endif // QLOW_UTIL_H
 
-

+ 14 - 14
src/Visitor.h

@@ -4,43 +4,43 @@
 
 namespace qlow
 {
-    template<typename R, typename... T>
+    template<typename R, typename A, typename... T>
     class Visitor;
 
-    template<typename R>
-    class Visitor<R>
+    template<typename R, typename A>
+    class Visitor<R, A>
     {
     public:
         using ReturnType = R;
     };
     
-    template<typename R, typename T>
-    class Visitor<R, T> :
-        public Visitor<R>
+    template<typename R, typename A, typename T>
+    class Visitor<R, A, T> :
+        public Visitor<R, A>
     {
     public:
         using ReturnType = R;
-        virtual R visit(T& arg) = 0;
+        virtual R visit(T& arg, A& arg2) = 0;
     };
 
 
-    template<typename R, typename T, typename... V>
-    class Visitor<R, T, V...> :
-        public Visitor<R, V...>
+    template<typename R, typename A, typename T, typename... V>
+    class Visitor<R, A, T, V...> :
+        public Visitor<R, A, V...>
     {
     public:
-        using Visitor<R, V...>::visit;
+        using Visitor<R, A, V...>::visit;
         using ReturnType = R;
-        virtual R visit(T& arg) = 0;
+        virtual R visit(T& arg, A& arg2) = 0;
     };
 
 
-    template<typename RT, typename V>
+    template<typename RT, typename A, typename V>
     class Visitable
     {
     public:
         virtual ~Visitable(void) {}
-        virtual RT accept(V& visitor) = 0;
+        virtual RT accept(V& visitor, A& arg2) = 0;
     };
 
 

+ 1 - 1
src/main.cpp

@@ -18,7 +18,7 @@ int main()
         qlow::sem::SymbolTable<qlow::sem::Class> semClasses = qlow::sem::createFromAst(*parsedClasses.get());
 
         for (auto& [a, b] : semClasses) {
-            std::cout << "ay: " << a << std::endl;
+            std::cout << a << ": " << b->toString() << std::endl;
         }
     }
     catch (const char* err)

+ 1 - 1
src/makefile

@@ -1,5 +1,5 @@
 CXX := g++
-CXXFLAGS := -Wall -Wextra -std=c++17
+CXXFLAGS := -std=c++17 # -Wall -Wextra 
 LINKFLAGS :=
 
 YACC := bison