Add a symbol table with type info

This commit is contained in:
Eugen Wissner 2025-03-09 00:53:13 +01:00
parent 868db6e0bf
commit f739194e06
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
9 changed files with 471 additions and 342 deletions

View File

@ -21,243 +21,18 @@ namespace elna
{
namespace boot
{
type::type()
: tag(type_tag::alias)
declaration_error::declaration_error(const std::string& identifier, const char *path, const struct position position)
: error(path, position), identifier(identifier)
{
}
type::type(std::shared_ptr<alias_type> alias)
: tag(type_tag::alias), alias(alias)
std::string declaration_error::what() const
{
return "Type '" + identifier + "' not declared";
}
type::type(std::shared_ptr<primitive_type> primitive)
: tag(type_tag::primitive), primitive(primitive)
{
}
type::type(std::shared_ptr<record_type> record)
: tag(type_tag::record), record(record)
{
}
type::type(std::shared_ptr<union_type> _union)
: tag(type_tag::_union), _union(_union)
{
}
type::type(std::shared_ptr<pointer_type> pointer)
: tag(type_tag::pointer), pointer(pointer)
{
}
type::type(std::shared_ptr<array_type> array)
: tag(type_tag::array), array(array)
{
}
void type::copy(const type& other)
{
switch (other.tag)
{
case type_tag::empty:
break;
case type_tag::alias:
new (&alias) std::weak_ptr<alias_type>(other.alias);
break;
case type_tag::primitive:
new (&primitive) std::weak_ptr<primitive_type>(other.primitive);
break;
case type_tag::record:
new (&record) std::shared_ptr<record_type>(other.record);
break;
case type_tag::_union:
new (&_union) std::shared_ptr<union_type>(other._union);
break;
case type_tag::pointer:
new (&pointer) std::shared_ptr<pointer_type>(other.pointer);
break;
case type_tag::array:
new (&array) std::shared_ptr<array_type>(other.array);
break;
}
}
type::type(const type& other)
: tag(other.tag)
{
copy(other);
}
void type::move(type&& other)
{
switch (other.tag)
{
case type_tag::empty:
break;
case type_tag::alias:
new (&alias) std::weak_ptr<alias_type>(std::move(other.alias));
break;
case type_tag::primitive:
new (&primitive) std::weak_ptr<primitive_type>(std::move(other.primitive));
break;
case type_tag::record:
new (&record) std::shared_ptr<record_type>(std::move(other.record));
break;
case type_tag::_union:
new (&_union) std::shared_ptr<union_type>(std::move(other._union));
break;
case type_tag::pointer:
new (&pointer) std::shared_ptr<pointer_type>(std::move(other.pointer));
break;
case type_tag::array:
new (&array) std::shared_ptr<array_type>(std::move(other.array));
break;
}
}
type& type::operator=(const type& other)
{
this->~type();
this->tag = other.tag;
copy(other);
return *this;
}
type::type(type&& other)
: tag(other.tag)
{
move(std::move(other));
}
type& type::operator=(type&& other)
{
this->~type();
this->tag = other.tag;
move(std::move(other));
return *this;
}
type::~type()
{
switch (tag)
{
case type_tag::empty:
break;
case type_tag::alias:
break;
case type_tag::primitive:
break;
case type_tag::record:
this->record.~shared_ptr<record_type>();
break;
case type_tag::_union:
this->_union.~shared_ptr<union_type>();
break;
case type_tag::pointer:
this->pointer.~shared_ptr<pointer_type>();
break;
case type_tag::array:
this->array.~shared_ptr<array_type>();
break;
}
}
template<>
std::shared_ptr<alias_type> type::get<alias_type>() const
{
if (tag == type_tag::alias)
{
return this->alias.lock();
}
else
{
return nullptr;
}
}
template<>
std::shared_ptr<primitive_type> type::get<primitive_type>() const
{
if (tag == type_tag::primitive)
{
return this->primitive.lock();
}
else
{
return nullptr;
}
}
template<>
std::shared_ptr<record_type> type::get<record_type>() const
{
if (tag == type_tag::record)
{
return this->record;
}
else
{
return nullptr;
}
}
template<>
std::shared_ptr<union_type> type::get<union_type>() const
{
if (tag == type_tag::_union)
{
return this->_union;
}
else
{
return nullptr;
}
}
template<>
std::shared_ptr<pointer_type> type::get<pointer_type>() const
{
if (tag == type_tag::pointer)
{
return this->pointer;
}
else
{
return nullptr;
}
}
template<>
std::shared_ptr<array_type> type::get<array_type>() const
{
if (tag == type_tag::array)
{
return this->array;
}
else
{
return nullptr;
}
}
bool type::empty() const
{
return tag == type_tag::empty;
}
pointer_type::pointer_type(type base)
: base(base)
{
}
array_type::array_type(type base, std::uint64_t size)
: base(base), size(size)
{
}
primitive_type::primitive_type(const std::string& identifier)
: identifier(identifier)
declaration_visitor::declaration_visitor(const char *path, std::shared_ptr<symbol_table> symbols)
: path(path), symbols(symbols)
{
}
@ -275,9 +50,8 @@ namespace boot
void declaration_visitor::visit(type_definition *definition)
{
auto unresolved_declaration = this->unresolved.at(definition->identifier);
definition->body().accept(this);
auto unresolved_declaration = this->unresolved.at(definition->identifier);
unresolved_declaration->reference = this->current_type;
}
@ -292,24 +66,36 @@ namespace boot
}
else
{
auto new_error = std::make_unique<declaration_error>(type_expression->name,
path, type_expression->position());
this->errors.emplace_back(std::move(new_error));
// TODO: Delete the next line.
this->current_type = type(std::make_shared<primitive_type>(type_expression->name));
}
}
void declaration_visitor::visit(array_type_expression *type_expression)
{
}
void declaration_visitor::visit(pointer_type_expression *type_expression)
{
type_expression->base().accept(this);
this->current_type = type(std::make_shared<pointer_type>(this->current_type));
}
void declaration_visitor::visit(array_type_expression *type_expression)
{
type_expression->base().accept(this);
this->current_type = type(std::make_shared<array_type>(this->current_type, type_expression->size));
}
void declaration_visitor::visit(record_type_expression *type_expression)
{
auto type_definition = std::make_shared<record_type>();
for (auto& field : type_expression->fields)
{
field.second->accept(this);
type_definition->fields.push_back({ field.first, type(this->current_type) });
}
this->current_type = type(type_definition);
}
@ -317,6 +103,12 @@ namespace boot
{
auto type_definition = std::make_shared<union_type>();
for (auto& field : type_expression->fields)
{
field.second->accept(this);
type_definition->fields.push_back({ field.first, type(this->current_type) });
}
this->current_type = type(type_definition);
}

300
boot/symbol.cc Normal file
View File

@ -0,0 +1,300 @@
/* Symbol definitions.
Copyright (C) 2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#pragma once
#include "elna/boot/symbol.h"
namespace elna
{
namespace boot
{
type::type()
: tag(type_tag::alias)
{
}
type::type(std::shared_ptr<alias_type> alias)
: tag(type_tag::alias), alias(alias)
{
}
type::type(std::shared_ptr<primitive_type> primitive)
: tag(type_tag::primitive), primitive(primitive)
{
}
type::type(std::shared_ptr<record_type> record)
: tag(type_tag::record), record(record)
{
}
type::type(std::shared_ptr<union_type> _union)
: tag(type_tag::_union), _union(_union)
{
}
type::type(std::shared_ptr<pointer_type> pointer)
: tag(type_tag::pointer), pointer(pointer)
{
}
type::type(std::shared_ptr<array_type> array)
: tag(type_tag::array), array(array)
{
}
void type::copy(const type& other)
{
switch (other.tag)
{
case type_tag::empty:
break;
case type_tag::alias:
new (&alias) std::weak_ptr<alias_type>(other.alias);
break;
case type_tag::primitive:
new (&primitive) std::weak_ptr<primitive_type>(other.primitive);
break;
case type_tag::record:
new (&record) std::shared_ptr<record_type>(other.record);
break;
case type_tag::_union:
new (&_union) std::shared_ptr<union_type>(other._union);
break;
case type_tag::pointer:
new (&pointer) std::shared_ptr<pointer_type>(other.pointer);
break;
case type_tag::array:
new (&array) std::shared_ptr<array_type>(other.array);
break;
}
}
type::type(const type& other)
: tag(other.tag)
{
copy(other);
}
void type::move(type&& other)
{
switch (other.tag)
{
case type_tag::empty:
break;
case type_tag::alias:
new (&alias) std::weak_ptr<alias_type>(std::move(other.alias));
break;
case type_tag::primitive:
new (&primitive) std::weak_ptr<primitive_type>(std::move(other.primitive));
break;
case type_tag::record:
new (&record) std::shared_ptr<record_type>(std::move(other.record));
break;
case type_tag::_union:
new (&_union) std::shared_ptr<union_type>(std::move(other._union));
break;
case type_tag::pointer:
new (&pointer) std::shared_ptr<pointer_type>(std::move(other.pointer));
break;
case type_tag::array:
new (&array) std::shared_ptr<array_type>(std::move(other.array));
break;
}
}
type& type::operator=(const type& other)
{
this->~type();
this->tag = other.tag;
copy(other);
return *this;
}
type::type(type&& other)
: tag(other.tag)
{
move(std::move(other));
}
type& type::operator=(type&& other)
{
this->~type();
this->tag = other.tag;
move(std::move(other));
return *this;
}
type::~type()
{
switch (tag)
{
case type_tag::empty:
break;
case type_tag::alias:
break;
case type_tag::primitive:
break;
case type_tag::record:
this->record.~shared_ptr<record_type>();
break;
case type_tag::_union:
this->_union.~shared_ptr<union_type>();
break;
case type_tag::pointer:
this->pointer.~shared_ptr<pointer_type>();
break;
case type_tag::array:
this->array.~shared_ptr<array_type>();
break;
}
}
template<>
std::shared_ptr<alias_type> type::get<alias_type>() const
{
if (tag == type_tag::alias)
{
return this->alias.lock();
}
else
{
return nullptr;
}
}
template<>
std::shared_ptr<primitive_type> type::get<primitive_type>() const
{
if (tag == type_tag::primitive)
{
return this->primitive.lock();
}
else
{
return nullptr;
}
}
template<>
std::shared_ptr<record_type> type::get<record_type>() const
{
if (tag == type_tag::record)
{
return this->record;
}
else
{
return nullptr;
}
}
template<>
std::shared_ptr<union_type> type::get<union_type>() const
{
if (tag == type_tag::_union)
{
return this->_union;
}
else
{
return nullptr;
}
}
template<>
std::shared_ptr<pointer_type> type::get<pointer_type>() const
{
if (tag == type_tag::pointer)
{
return this->pointer;
}
else
{
return nullptr;
}
}
template<>
std::shared_ptr<array_type> type::get<array_type>() const
{
if (tag == type_tag::array)
{
return this->array;
}
else
{
return nullptr;
}
}
bool type::empty() const
{
return tag == type_tag::empty;
}
pointer_type::pointer_type(type base)
: base(base)
{
}
array_type::array_type(type base, std::uint64_t size)
: base(base), size(size)
{
}
primitive_type::primitive_type(const std::string& identifier)
: identifier(identifier)
{
}
info::~info()
{
}
std::shared_ptr<type_info> info::is_type()
{
return nullptr;
}
type_info::type_info(const type symbol)
: symbol(symbol)
{
}
std::shared_ptr<type_info> type_info::is_type()
{
return std::static_pointer_cast<type_info>(shared_from_this());
}
std::shared_ptr<symbol_table> builtin_symbol_table()
{
auto result = std::make_shared<symbol_table>();
result->enter("Int", std::make_shared<type_info>(type(std::make_shared<primitive_type>("Int"))));
result->enter("Word", std::make_shared<type_info>(type(std::make_shared<primitive_type>("Word"))));
result->enter("Char", std::make_shared<type_info>(type(std::make_shared<primitive_type>("Char"))));
result->enter("Bool", std::make_shared<type_info>(type(std::make_shared<primitive_type>("Bool"))));
result->enter("Byte", std::make_shared<type_info>(type(std::make_shared<primitive_type>("Byte"))));
result->enter("Float", std::make_shared<type_info>(type(std::make_shared<primitive_type>("Float"))));
result->enter("String", std::make_shared<type_info>(type(std::make_shared<primitive_type>("String"))));
return result;
}
}
}

View File

@ -47,6 +47,7 @@ elna_OBJS = \
elna/lexer.o \
elna/parser.o \
elna/semantic.o \
elna/symbol.o \
elna/result.o \
$(END)

View File

@ -63,14 +63,16 @@ namespace gcc
return error_mark_node;
}
void do_semantic_analysis(std::shared_ptr<symbol_table> symbols, std::unique_ptr<boot::program>& ast)
void do_semantic_analysis(const char *path, std::unique_ptr<boot::program>& ast,
std::shared_ptr<symbol_table> symbols)
{
boot::declaration_visitor declaration_visitor;
auto info_table = boot::builtin_symbol_table();
boot::declaration_visitor declaration_visitor(path, info_table);
declaration_visitor.visit(ast.get());
for (auto unresolved : declaration_visitor.unresolved)
{
auto inner_alias = elna::gcc::get_inner_alias(symbols, boot::type(unresolved.second));
auto inner_alias = get_inner_alias(symbols, boot::type(unresolved.second));
symbols->enter(unresolved.first, inner_alias);
}
}

View File

@ -98,7 +98,7 @@ static void elna_parse_file(const char *filename)
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::do_semantic_analysis(filename, driver.tree, symbol_table);
elna::gcc::generic_visitor generic_visitor{ symbol_table };
generic_visitor.visit(driver.tree.get());

View File

@ -42,28 +42,22 @@ namespace boot
class error
{
protected:
/**
* Constructs an error.
*
* \param path Source file name.
* \param position Error position in the source text.
*/
error(const char *path, const struct position position);
public:
const struct position position;
const char *path;
virtual ~error() noexcept = default;
virtual ~error() = default;
/// Error text.
virtual std::string what() const = 0;
/// Error line in the source text.
std::size_t line() const noexcept;
std::size_t line() const;
/// Error column in the source text.
std::size_t column() const noexcept;
std::size_t column() const;
};
}
}

View File

@ -16,119 +16,38 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include <string>
#include <vector>
#include <unordered_map>
#include <memory>
#include "elna/boot/ast.h"
#include "elna/boot/result.h"
#include "elna/boot/symbol.h"
namespace elna
{
namespace boot
{
class alias_type;
class primitive_type;
class record_type;
class union_type;
class pointer_type;
class array_type;
class type
class declaration_error : public error
{
enum class type_tag
{
empty,
alias,
primitive,
record,
_union,
pointer,
array
};
type_tag tag{ type_tag::empty };
union
{
std::weak_ptr<alias_type> alias;
std::weak_ptr<primitive_type> primitive;
std::shared_ptr<record_type> record;
std::shared_ptr<union_type> _union;
std::shared_ptr<pointer_type> pointer;
std::shared_ptr<array_type> array;
};
void copy(const type& other);
void move(type&& other);
std::string identifier;
public:
type();
explicit type(std::shared_ptr<alias_type> alias);
explicit type(std::shared_ptr<primitive_type> primitive);
explicit type(std::shared_ptr<record_type> record);
explicit type(std::shared_ptr<union_type> _union);
explicit type(std::shared_ptr<pointer_type> pointer);
explicit type(std::shared_ptr<array_type> array);
declaration_error(const std::string& identifier, const char *path, const struct position position);
type(const type& other);
type& operator=(const type& other);
type(type&& other);
type& operator=(type&& other);
~type();
template<typename T>
std::shared_ptr<T> get() const;
bool empty() const;
};
struct alias_type
{
type reference;
};
struct pointer_type
{
const type base;
explicit pointer_type(type base);
};
struct array_type
{
const type base;
const std::uint64_t size;
array_type(type base, std::uint64_t size);
};
struct primitive_type
{
const std::string identifier;
explicit primitive_type(const std::string& identifier);
};
using type_field = typename std::pair<std::string, type>;
struct record_type
{
std::vector<type_field> fields;
};
struct union_type
{
std::vector<type_field> fields;
virtual std::string what() const override;
};
class declaration_visitor final : public empty_visitor
{
type current_type;
const char *path;
symbol_table symbols;
std::vector<std::unique_ptr<error>> errors;
public:
std::unordered_map<std::string, std::shared_ptr<alias_type>> unresolved;
declaration_visitor() = default;
explicit declaration_visitor(const char *path, std::shared_ptr<symbol_table> symbols);
void visit(primitive_type_expression *type_expression) override;
void visit(array_type_expression *type_expression) override;

View File

@ -21,11 +21,127 @@ along with GCC; see the file COPYING3. If not see
#include <unordered_map>
#include <string>
#include <memory>
#include <vector>
namespace elna
{
namespace boot
{
class alias_type;
class primitive_type;
class record_type;
class union_type;
class pointer_type;
class array_type;
class type
{
enum class type_tag
{
empty,
alias,
primitive,
record,
_union,
pointer,
array
};
type_tag tag{ type_tag::empty };
union
{
std::weak_ptr<alias_type> alias;
std::weak_ptr<primitive_type> primitive;
std::shared_ptr<record_type> record;
std::shared_ptr<union_type> _union;
std::shared_ptr<pointer_type> pointer;
std::shared_ptr<array_type> array;
};
void copy(const type& other);
void move(type&& other);
public:
type();
explicit type(std::shared_ptr<alias_type> alias);
explicit type(std::shared_ptr<primitive_type> primitive);
explicit type(std::shared_ptr<record_type> record);
explicit type(std::shared_ptr<union_type> _union);
explicit type(std::shared_ptr<pointer_type> pointer);
explicit type(std::shared_ptr<array_type> array);
type(const type& other);
type& operator=(const type& other);
type(type&& other);
type& operator=(type&& other);
~type();
template<typename T>
std::shared_ptr<T> get() const;
bool empty() const;
};
struct alias_type
{
type reference;
};
struct pointer_type
{
const type base;
explicit pointer_type(type base);
};
struct array_type
{
const type base;
const std::uint64_t size;
array_type(type base, std::uint64_t size);
};
struct primitive_type
{
const std::string identifier;
explicit primitive_type(const std::string& identifier);
};
using type_field = typename std::pair<std::string, type>;
struct record_type
{
std::vector<type_field> fields;
};
struct union_type
{
std::vector<type_field> fields;
};
class type_info;
class info : public std::enable_shared_from_this<info>
{
public:
virtual ~info() = 0;
virtual std::shared_ptr<type_info> is_type();
};
class type_info : public info
{
public:
const type symbol;
explicit type_info(const type symbol);
std::shared_ptr<type_info> is_type() override;
};
/**
* Symbol table.
*/
@ -120,5 +236,9 @@ namespace boot
return this->outer_scope;
}
};
using symbol_table = symbol_map<std::shared_ptr<info>, std::nullptr_t, nullptr>;
std::shared_ptr<symbol_table> builtin_symbol_table();
}
}

View File

@ -34,7 +34,8 @@ namespace elna
{
namespace gcc
{
void do_semantic_analysis(std::shared_ptr<symbol_table> symbols, std::unique_ptr<boot::program>& ast);
void do_semantic_analysis(const char *path, std::unique_ptr<boot::program>& ast,
std::shared_ptr<symbol_table> symbols);
class generic_visitor final : public boot::empty_visitor
{