Move type definitions to the program node

This commit is contained in:
Eugen Wissner 2025-01-12 10:35:24 +01:00
parent 7985704981
commit 3bf9189d8d
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
8 changed files with 160 additions and 47 deletions

View File

@ -30,7 +30,6 @@ elna_OBJS = \
elna/lexer.o \
elna/parser.o \
elna/result.o \
elna/types.o \
$(END)
elna1$(exeext): attribs.o $(elna_OBJS) $(BACKEND) $(LIBDEPS)

View File

@ -15,9 +15,14 @@ namespace elna
{
namespace gcc
{
generic_visitor::generic_visitor()
{
this->symbol_map = std::make_shared<source::symbol_table<tree>>();
}
void generic_visitor::visit(source::call_statement *statement)
{
auto symbol = this->symbol_map.find(statement->name());
auto symbol = this->symbol_map->lookup(statement->name());
if (statement->name() == "writei")
{
@ -80,10 +85,10 @@ namespace gcc
append_to_statement_list(stmt, &this->current_statements);
this->current_expression = NULL_TREE;
}
else if (symbol != this->symbol_map.end())
else if (symbol)
{
tree fndecl_type = build_function_type_list(integer_type_node, NULL_TREE);
tree printf_fn = build1(ADDR_EXPR, build_pointer_type(fndecl_type), symbol->second);
tree printf_fn = build1(ADDR_EXPR, build_pointer_type(fndecl_type), symbol->payload);
tree stmt = build_call_nary(integer_type_node, printf_fn, 0);
@ -100,7 +105,7 @@ namespace gcc
void generic_visitor::visit(source::program *program)
{
for (const auto& constant : program->definitions())
for (const auto& constant : program->type_definitions)
{
constant->accept(this);
}
@ -153,7 +158,7 @@ namespace gcc
definition->parameters().size(), parameter_types);
this->main_fndecl = build_fn_decl(definition->identifier().c_str(), declaration_type);
this->symbol_map.insert({ definition->identifier(), this->main_fndecl });
this->symbol_map->enter(definition->identifier(), source::make_info(this->main_fndecl));
tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, integer_type_node);
DECL_CONTEXT(resdecl) = this->main_fndecl;
@ -186,6 +191,7 @@ namespace gcc
{
this->current_statements = alloc_stmt_list();
this->variable_chain = tree_chain();
this->symbol_map = std::make_shared<source::symbol_table<tree>>(this->symbol_map);
}
tree_symbol_mapping generic_visitor::leave_scope()
@ -194,6 +200,7 @@ namespace gcc
NULL_TREE, NULL_TREE, NULL_TREE);
tree bind_expr = build3(BIND_EXPR, void_type_node, variable_chain.head(),
this->current_statements, new_block);
this->symbol_map = this->symbol_map->scope();
return tree_symbol_mapping{ bind_expr, new_block };
}
@ -344,9 +351,9 @@ namespace gcc
location_t definition_location = get_location(&definition->position());
tree definition_tree = build_decl(definition_location, CONST_DECL,
get_identifier(definition->identifier().c_str()), integer_type_node);
auto result = this->symbol_map.insert({ definition->identifier(), definition_tree });
auto result = this->symbol_map->enter(definition->identifier(), source::make_info(definition_tree));
if (result.second)
if (result)
{
definition->body().accept(this);
@ -378,9 +385,9 @@ namespace gcc
location_t definition_location = get_location(&definition->position());
tree definition_tree = build_decl(definition_location, TYPE_DECL,
get_identifier(definition->identifier().c_str()), tree_type);
auto result = this->symbol_map.insert({ definition->identifier(), definition_tree });
auto result = this->symbol_map->enter(definition->identifier(), source::make_info(definition_tree));
if (result.second)
if (result)
{
DECL_CONTEXT(definition_tree) = this->main_fndecl;
variable_chain.append(definition_tree);
@ -421,11 +428,11 @@ namespace gcc
{
return elna_string_type_node;
}
auto symbol = this->symbol_map.find(basic_type->base_name());
auto symbol = this->symbol_map->lookup(basic_type->base_name());
if (symbol != this->symbol_map.end())
if (symbol)
{
return TREE_TYPE(symbol->second);
return TREE_TYPE(symbol->payload);
}
error_at(get_location(&basic_type->position()),
"type '%s' not declared", basic_type->base_name().c_str());
@ -499,9 +506,9 @@ namespace gcc
auto declaration_location = get_location(&declaration->position());
tree declaration_tree = build_decl(declaration_location, VAR_DECL,
get_identifier(declaration->identifier().c_str()), declaration_type);
auto result = this->symbol_map.insert({ declaration->identifier(), declaration_tree });
auto result = this->symbol_map->enter(declaration->identifier(), source::make_info(declaration_tree));
if (result.second)
if (result)
{
DECL_CONTEXT(declaration_tree) = this->main_fndecl;
variable_chain.append(declaration_tree);
@ -520,9 +527,9 @@ namespace gcc
void generic_visitor::visit(source::variable_expression *expression)
{
auto symbol = this->symbol_map.find(expression->name());
auto symbol = this->symbol_map->lookup(expression->name());
if (symbol == this->symbol_map.end())
if (!symbol)
{
error_at(get_location(&expression->position()),
"variable '%s' not declared in the current scope",
@ -530,7 +537,7 @@ namespace gcc
this->current_expression = error_mark_node;
return;
}
this->current_expression = symbol->second;
this->current_expression = symbol->payload;
}
void generic_visitor::visit(source::array_access_expression *expression)

View File

@ -1,6 +1,7 @@
#pragma once
#include "elna/source/ast.h"
#include "elna/source/symbol.h"
#include "elna/gcc/elna-tree.h"
#include "config.h"
@ -20,7 +21,7 @@ namespace gcc
{
tree current_statements{ NULL_TREE };
tree current_expression{ NULL_TREE };
std::unordered_map<std::string, tree> symbol_map;
std::shared_ptr<source::symbol_table<tree>> symbol_map;
tree main_fndecl{ NULL_TREE };
tree_chain variable_chain;
@ -31,6 +32,8 @@ namespace gcc
tree_symbol_mapping leave_scope();
public:
generic_visitor();
void visit(source::program *program) override;
void visit(source::procedure_definition *definition) override;
void visit(source::call_statement *statement) override;

View File

@ -8,7 +8,6 @@
#include <string>
#include <vector>
#include "elna/source/result.h"
#include "elna/source/types.h"
namespace elna
{
@ -210,7 +209,6 @@ namespace source
{
public:
std::shared_ptr<operand> place;
std::shared_ptr<const type> data_type;
protected:
/**
@ -596,19 +594,16 @@ namespace source
class block : public node
{
std::vector<definition *> m_definitions;
statement *m_body;
public:
std::vector<definition *> value_definitions;
block(const struct position position, std::vector<definition *>&& definitions,
std::vector<definition *>&& value_definitions,
block(const struct position position, std::vector<definition *>&& value_definitions,
statement *body);
virtual void accept(parser_visitor *visitor) override;
statement& body();
std::vector<definition *>& definitions();
virtual ~block() override;
};
@ -616,9 +611,13 @@ namespace source
class program : public block
{
public:
program(const struct position position, std::vector<definition *>&& definitions,
std::vector<definition *> type_definitions;
program(const struct position position, std::vector<definition *>&& type_definitions,
std::vector<definition *>&& value_definitions, statement *body);
virtual void accept(parser_visitor *visitor) override;
virtual ~program() override;
};
template<typename T>

View File

@ -4,7 +4,7 @@
#pragma once
#include <cstddef>
#include "elna/source/types.h"
#include <string>
namespace elna
{

View File

@ -0,0 +1,106 @@
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#pragma once
#include <cstdint>
#include <unordered_map>
#include <string>
#include <memory>
namespace elna
{
namespace source
{
/**
* Generic language entity information.
*/
template<typename T>
class info
{
public:
T payload;
info(T payload)
: payload(payload)
{
}
};
template<typename T>
std::shared_ptr<info<T>> make_info(T payload)
{
return std::make_shared<info<T>>(info(payload));
}
/**
* Symbol table.
*/
template<typename T>
class symbol_table
{
public:
using symbol_ptr = std::shared_ptr<info<T>>;
private:
std::unordered_map<std::string, symbol_ptr> entries;
std::shared_ptr<symbol_table> outer_scope;
public:
/**
* Constructs a new symbol with an optional outer scope.
*
* \param scope Outer scope.
*/
explicit symbol_table(std::shared_ptr<symbol_table> scope = nullptr)
: outer_scope(scope)
{
}
/**
* Looks for symbol in the table by name. Returns nullptr if the symbol
* can not be found.
*
* \param name Symbol name.
* \return Symbol from the table if found.
*/
symbol_ptr lookup(const std::string& name)
{
auto entry = entries.find(name);
if (entry != entries.cend())
{
return entry->second;
}
if (this->outer_scope != nullptr)
{
return this->outer_scope->lookup(name);
}
return nullptr;
}
/**
* Registers new symbol.
*
* \param name Symbol name.
* \param entry Symbol information.
*
* \return Whether the insertion took place.
*/
bool enter(const std::string& name, symbol_ptr entry)
{
return entries.insert({ name, entry }).second;
}
/**
* Returns the outer scope or nullptr if the this is the global scope.
*
* \return Outer scope.
*/
std::shared_ptr<symbol_table> scope()
{
return this->outer_scope;
}
};
}
}

View File

@ -65,10 +65,6 @@ namespace source
void empty_visitor::visit(block *block)
{
for (const auto& constant : block->definitions())
{
constant->accept(this);
}
for (const auto& definition : block->value_definitions)
{
definition->accept(this);
@ -78,6 +74,10 @@ namespace source
void empty_visitor::visit(program *program)
{
for (auto definition : program->type_definitions)
{
definition->accept(this);
}
visit(reinterpret_cast<block *>(program));
}
@ -447,11 +447,9 @@ namespace source
delete m_body;
}
block::block(const struct position position, std::vector<definition *>&& definitions,
std::vector<definition *>&& value_definitions,
block::block(const struct position position, std::vector<definition *>&& value_definitions,
statement *body)
: node(position), m_definitions(std::move(definitions)),
m_body(std::move(body)), value_definitions(std::move(value_definitions))
: node(position), m_body(std::move(body)), value_definitions(std::move(value_definitions))
{
}
@ -460,11 +458,6 @@ namespace source
visitor->visit(this);
}
std::vector<definition *>& block::definitions()
{
return m_definitions;
}
statement& block::body()
{
return *m_body;
@ -472,10 +465,6 @@ namespace source
block::~block()
{
for (auto definition : m_definitions)
{
delete definition;
}
for (auto definition : value_definitions)
{
delete definition;
@ -483,9 +472,11 @@ namespace source
delete m_body;
}
program::program(const struct position position, std::vector<definition *>&& definitions,
program::program(const struct position position,
std::vector<definition *>&& type_definitions,
std::vector<definition *>&& value_definitions, statement *body)
: block(position, std::move(definitions), std::move(value_definitions), body)
: block(position, std::move(value_definitions), body),
type_definitions(std::move(type_definitions))
{
}
@ -494,6 +485,14 @@ namespace source
visitor->visit(this);
}
program::~program()
{
for (auto definition : type_definitions)
{
delete definition;
}
}
char_literal::char_literal(const struct position position, const unsigned char value)
: expression(position), m_character(value)
{

View File

@ -143,7 +143,7 @@ block: constant_part variable_part statement
*definition++ = variable;
}
$$ = new elna::source::block(elna::source::position{},
{}, std::move(definitions), std::move($3));
std::move(definitions), std::move($3));
};
procedure_definition:
PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON block SEMICOLON