diff --git a/boot/semantic.cc b/boot/semantic.cc
index 6735976..ae1157d 100644
--- a/boot/semantic.cc
+++ b/boot/semantic.cc
@@ -69,5 +69,66 @@ namespace boot
     {
         return this;
     }
+
+    void declaration_visitor::visit(program *program)
+    {
+        for (type_definition *const type : program->types)
+        {
+            this->unresolved.insert({ type->identifier, new alias_type() });
+        }
+        for (type_definition *const type : program->types)
+        {
+            type->accept(this);
+        }
+    }
+
+    void declaration_visitor::visit(type_definition *definition)
+    {
+        auto unresolved_declaration = this->unresolved.at(definition->identifier);
+
+        definition->body().accept(this);
+
+        if (this->current_type != nullptr)
+        {
+            unresolved_declaration->reference = this->current_type;
+        }
+        this->current_type = nullptr;
+    }
+
+    void declaration_visitor::visit(primitive_type_expression *type)
+    {
+        auto unresolved_alias = this->unresolved.find(type->name);
+
+        if (unresolved_alias != this->unresolved.end())
+        {
+            this->current_type = unresolved_alias->second;
+        }
+        else
+        {
+            this->current_type = new primitive_type(type->name);
+        }
+    }
+
+    void declaration_visitor::visit(array_type_expression *type)
+    {
+    }
+
+    void declaration_visitor::visit(pointer_type_expression *type)
+    {
+    }
+
+    void declaration_visitor::visit(record_type_expression *type)
+    {
+        this->current_type = new record_type();
+    }
+
+    void declaration_visitor::visit(union_type_expression *type)
+    {
+        this->current_type = new union_type();
+    }
+
+    void declaration_visitor::visit(procedure_type_expression *type)
+    {
+    }
 }
 }
diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc
index 3ee4f94..33af896 100644
--- a/gcc/elna-generic.cc
+++ b/gcc/elna-generic.cc
@@ -38,19 +38,7 @@ namespace elna
 {
 namespace gcc
 {
-    declaration_visitor::declaration_visitor(std::shared_ptr<symbol_table> symbol_table)
-        : symbols(symbol_table)
-    {
-        this->symbols->enter("Int", elna_int_type_node);
-        this->symbols->enter("Word", elna_word_type_node);
-        this->symbols->enter("Char", elna_char_type_node);
-        this->symbols->enter("Bool", elna_bool_type_node);
-        this->symbols->enter("Byte", elna_byte_type_node);
-        this->symbols->enter("Float", elna_float_type_node);
-        this->symbols->enter("String", elna_string_type_node);
-    }
-
-    tree declaration_visitor::get_inner_alias(const boot::alias_type& t)
+    static tree get_inner_alias(std::shared_ptr<symbol_table> symbol_table, const boot::alias_type& t)
     {
         if (t.reference == nullptr)
         {
@@ -58,11 +46,11 @@ namespace gcc
         }
         else if (auto reference = t.reference->is_primitive())
         {
-            return this->symbols->lookup(reference->identifier);
+            return symbol_table->lookup(reference->identifier);
         }
         else if (auto reference = t.reference->is_alias())
         {
-            return get_inner_alias(*reference);
+            return get_inner_alias(symbol_table, *reference);
         }
         else if (auto reference = t.reference->is_record())
         {
@@ -75,75 +63,16 @@ namespace gcc
         return NULL_TREE;
     }
 
-    boot::type *declaration_visitor::build_type(boot::type_expression *type_expression)
+    void do_semantic_analysis(std::shared_ptr<symbol_table> symbols, std::unique_ptr<boot::program>& ast)
     {
-        if (auto alias_node = type_expression->is_primitive())
-        {
-            return this->unresolved.at(alias_node->name);
-        }
-        else if (auto alias_node = type_expression->is_record())
-        {
-            return build_record(alias_node.get());
-        }
-        else if (auto alias_node = type_expression->is_union())
-        {
-            return build_union(alias_node.get());
-        }
-        return nullptr;
-    }
+        boot::declaration_visitor declaration_visitor;
 
-    boot::record_type *declaration_visitor::build_record(boot::record_type_expression *type_expression)
-    {
-        return new boot::record_type();
-    }
-
-    boot::union_type *declaration_visitor::build_union(boot::union_type_expression *type_expression)
-    {
-        return new boot::union_type();
-    }
-
-    void declaration_visitor::visit(boot::program *program)
-    {
-        for (boot::type_definition *const type : program->types)
+        declaration_visitor.visit(ast.get());
+        for (auto unresolved : declaration_visitor.unresolved)
         {
-            type->accept(this);
+            auto inner_alias = elna::gcc::get_inner_alias(symbols, *unresolved.second);
+            symbols->enter(unresolved.first, inner_alias);
         }
-        for (boot::type_definition *const type : program->types)
-        {
-            auto unresolved_declaration = this->unresolved.at(type->identifier);
-
-            if (auto alias_node = type->body().is_primitive())
-            {
-                auto unresolved_alias = this->unresolved.find(alias_node->name);
-
-                if (unresolved_alias != this->unresolved.end())
-                {
-                    unresolved_declaration->reference = unresolved_alias->second;
-                }
-                else
-                {
-                    unresolved_declaration->reference = new boot::primitive_type(alias_node->name);
-                }
-            }
-            else if (auto alias_node = type->body().is_record())
-            {
-                unresolved_declaration->reference = build_record(alias_node.get());
-            }
-            else if (auto alias_node = type->body().is_union())
-            {
-                unresolved_declaration->reference = build_union(alias_node.get());
-            }
-        }
-        for (auto unresolved : this->unresolved)
-        {
-            auto inner_alias = get_inner_alias(*unresolved.second);
-            this->symbols->enter(unresolved.first, inner_alias);
-        }
-    }
-
-    void declaration_visitor::visit(boot::type_definition *definition)
-    {
-        this->unresolved.insert({ definition->identifier, new boot::alias_type() });
     }
 
     generic_visitor::generic_visitor(std::shared_ptr<symbol_table> symbol_table)
diff --git a/gcc/elna1.cc b/gcc/elna1.cc
index 5713719..07d8a31 100644
--- a/gcc/elna1.cc
+++ b/gcc/elna1.cc
@@ -90,10 +90,17 @@ static void elna_parse_file(const char *filename)
     {
         std::shared_ptr<elna::gcc::symbol_table> symbol_table = std::make_shared<elna::gcc::symbol_table>();
 
-        elna::gcc::declaration_visitor declaration_visitor{ symbol_table };
+        symbol_table->enter("Int", elna_int_type_node);
+        symbol_table->enter("Word", elna_word_type_node);
+        symbol_table->enter("Char", elna_char_type_node);
+        symbol_table->enter("Bool", elna_bool_type_node);
+        symbol_table->enter("Byte", elna_byte_type_node);
+        symbol_table->enter("Float", elna_float_type_node);
+        symbol_table->enter("String", elna_string_type_node);
+
+        elna::gcc::do_semantic_analysis(symbol_table, driver.tree);
         elna::gcc::generic_visitor generic_visitor{ symbol_table };
 
-        declaration_visitor.visit(driver.tree.get());
         generic_visitor.visit(driver.tree.get());
     }
     linemap_add(line_table, LC_LEAVE, 0, NULL, 0);
diff --git a/include/elna/boot/semantic.h b/include/elna/boot/semantic.h
index de6030a..c88f802 100644
--- a/include/elna/boot/semantic.h
+++ b/include/elna/boot/semantic.h
@@ -17,6 +17,9 @@ along with GCC; see the file COPYING3.  If not see
 
 #include <string>
 #include <vector>
+#include <unordered_map>
+
+#include "elna/boot/ast.h"
 
 namespace elna
 {
@@ -71,5 +74,24 @@ namespace boot
 
         union_type *is_union() override;
     };
+
+    class declaration_visitor final : public empty_visitor
+    {
+        type *current_type{ nullptr };
+
+    public:
+        std::unordered_map<std::string, alias_type *> unresolved;
+
+        declaration_visitor() = default;
+
+        void visit(primitive_type_expression *type) override;
+        void visit(array_type_expression *type) override;
+        void visit(pointer_type_expression *type) override;
+        void visit(program *program) override;
+        void visit(type_definition *definition) override;
+        void visit(record_type_expression *type) override;
+        void visit(union_type_expression *type) override;
+        void visit(procedure_type_expression *type) override;
+    };
 }
 }
diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h
index 4f4c635..2dfb2d9 100644
--- a/include/elna/gcc/elna-generic.h
+++ b/include/elna/gcc/elna-generic.h
@@ -28,29 +28,13 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "tree-iterator.h"
 
-#include <unordered_map>
 #include <string>
 
 namespace elna
 {
 namespace gcc
 {
-    class declaration_visitor final : public boot::empty_visitor
-    {
-        std::shared_ptr<symbol_table> symbols;
-        std::unordered_map<std::string, boot::alias_type *> unresolved;
-
-        boot::type *build_type(boot::type_expression *type_expression);
-        boot::record_type *build_record(boot::record_type_expression *type_expression);
-        boot::union_type *build_union(boot::union_type_expression *type_expression);
-        tree get_inner_alias(const boot::alias_type& t);
-
-    public:
-        declaration_visitor(std::shared_ptr<symbol_table> symbol_table);
-
-        void visit(boot::program *program) override;
-        void visit(boot::type_definition *definition) override;
-    };
+    void do_semantic_analysis(std::shared_ptr<symbol_table> symbols, std::unique_ptr<boot::program>& ast);
 
     class generic_visitor final : public boot::empty_visitor
     {