Add second GENERIC visitor

This commit is contained in:
Eugen Wissner 2025-03-04 22:56:32 +01:00
parent c5930285bf
commit 8dc02047df
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
12 changed files with 572 additions and 341 deletions

104
Rakefile
View File

@ -76,107 +76,3 @@ file (TMP + 'elna').to_path => ['source.elna']
file (TMP + 'elna').to_path => [(HOST_INSTALL + 'bin/gelna').to_path] do |task|
sh (HOST_INSTALL + 'bin/gelna').to_path, '-o', task.name, task.prerequisites.first
end
namespace :cross do
desc 'Build cross toolchain'
task :init, [:target] do |_, args|
args.with_defaults target: 'riscv32-unknown-linux-gnu'
options = find_build_target GCC_VERSION, args[:target]
env = {
'PATH' => "#{options.rootfs.realpath + 'bin'}:#{ENV['PATH']}"
}
sh env, 'riscv32-unknown-linux-gnu-gcc',
'-ffreestanding', '-static',
'-o', (options.tools + 'init').to_path,
'tools/init.c'
end
end
namespace :test do
test_sources = FileList['tests/vm/*.elna', 'tests/vm/*.s']
compiler = TMP + 'bin/elna'
object_directory = TMP + 'riscv/tests'
root_directory = TMP + 'riscv/root'
executable_directory = root_directory + 'tests'
expectation_directory = root_directory + 'expectations'
init = TMP + 'riscv/root/init'
builtin = TMP + 'riscv/builtin.o'
directory root_directory
directory object_directory
directory executable_directory
directory expectation_directory
file builtin => ['tools/builtin.s', object_directory] do |task|
sh AS, '-o', task.name, task.prerequisites.first
end
test_files = test_sources.flat_map do |test_source|
test_basename = File.basename(test_source, '.*')
test_object = object_directory + test_basename.ext('.o')
file test_object => [test_source, object_directory] do |task|
case File.extname(task.prerequisites.first)
when '.s'
sh AS, '-mno-relax', '-o', task.name, task.prerequisites.first
when '.elna'
sh compiler, '--output', task.name, task.prerequisites.first
else
raise "Unknown source file extension #{task.prerequisites.first}"
end
end
test_executable = executable_directory + test_basename
file test_executable => [test_object, executable_directory, builtin] do |task|
objects = task.prerequisites.filter { |prerequisite| File.file? prerequisite }
sh LINKER, '-o', test_executable.to_path, *objects
end
expectation_name = test_basename.ext '.txt'
source_expectation = "tests/expectations/#{expectation_name}"
target_expectation = expectation_directory + expectation_name
file target_expectation => [source_expectation, expectation_directory] do
cp source_expectation, target_expectation
end
[test_executable, target_expectation]
end
file init => [root_directory] do |task|
cp (TMP + 'tools/init'), task.name
end
# Directories should come first.
test_files.unshift executable_directory, expectation_directory, init
file (TMP + 'riscv/root.cpio') => test_files do |task|
root_files = task.prerequisites
.map { |prerequisite| Pathname.new(prerequisite).relative_path_from(root_directory).to_path }
File.open task.name, 'wb' do |cpio_file|
cpio_options = {
chdir: root_directory.to_path
}
cpio_stream = Open3.popen2 'cpio', '-o', '--format=newc', cpio_options do |stdin, stdout, wait_thread|
stdin.write root_files.join("\n")
stdin.close
stdout.each { |chunk| cpio_file.write chunk }
wait_thread.value
end
end
end
task :vm => (TMP + 'riscv/root.cpio') do |task|
kernels = FileList.glob(TMP + 'tools/linux-*/arch/riscv/boot/Image')
sh 'qemu-system-riscv32',
'-nographic',
'-M', 'virt',
'-bios', 'default',
'-kernel', kernels.first,
'-append', 'quiet panic=1',
'-initrd', task.prerequisites.first,
'-no-reboot'
end
end

View File

@ -191,6 +191,10 @@ namespace boot
{
}
node::~node()
{
}
const struct position& node::position() const
{
return this->source_position;
@ -200,10 +204,145 @@ namespace boot
{
}
statement::~statement()
{
}
assign_statement *statement::is_assign()
{
return nullptr;
}
if_statement *statement::is_if()
{
return nullptr;
}
while_statement *statement::is_while()
{
return nullptr;
}
return_statement *statement::is_return()
{
return nullptr;
}
defer_statement *statement::is_defer()
{
return nullptr;
}
procedure_call *statement::is_call_statement()
{
return nullptr;
}
void statement::accept(parser_visitor *visitor)
{
if (assign_statement *node = is_assign())
{
return node->accept(visitor);
}
else if (if_statement *node = is_if())
{
return node->accept(visitor);
}
else if (while_statement *node = is_while())
{
return node->accept(visitor);
}
else if (return_statement *node = is_return())
{
return node->accept(visitor);
}
else if (defer_statement *node = is_defer())
{
return node->accept(visitor);
}
else if (procedure_call *node = is_call_statement())
{
return node->accept(visitor);
}
__builtin_unreachable();
}
expression::expression()
{
}
expression::~expression()
{
}
cast_expression *expression::is_cast()
{
return nullptr;
}
traits_expression *expression::is_traits()
{
return nullptr;
}
binary_expression *expression::is_binary()
{
return nullptr;
}
unary_expression *expression::is_unary()
{
return nullptr;
}
designator_expression *expression::is_designator()
{
return nullptr;
}
procedure_call *expression::is_call_expression()
{
return nullptr;
}
literal *expression::is_literal()
{
return nullptr;
}
void expression::accept(parser_visitor *visitor)
{
if (cast_expression *node = is_cast())
{
return node->accept(visitor);
}
else if (traits_expression *node = is_traits())
{
return node->accept(visitor);
}
else if (binary_expression *node = is_binary())
{
return node->accept(visitor);
}
else if (unary_expression *node = is_unary())
{
return node->accept(visitor);
}
else if (designator_expression *node = is_designator())
{
return node->accept(visitor);
}
else if (procedure_call *node = is_call_expression())
{
return node->accept(visitor);
}
else if (literal *node = is_literal())
{
return node->accept(visitor);
}
__builtin_unreachable();
}
type_expression::type_expression(const struct position position)
: node(position)
{
@ -239,6 +378,35 @@ namespace boot
return nullptr;
}
void type_expression::accept(parser_visitor *visitor)
{
if (std::shared_ptr<primitive_type_expression> node = is_primitive())
{
return node->accept(visitor);
}
else if (std::shared_ptr<array_type_expression> node = is_array())
{
return node->accept(visitor);
}
else if (std::shared_ptr<pointer_type_expression> node = is_pointer())
{
return node->accept(visitor);
}
else if (std::shared_ptr<record_type_expression> node = is_record())
{
return node->accept(visitor);
}
else if (std::shared_ptr<union_type_expression> node = is_union())
{
return node->accept(visitor);
}
else if (std::shared_ptr<procedure_type_expression> node = is_procedure())
{
return node->accept(visitor);
}
__builtin_unreachable();
}
primitive_type_expression::primitive_type_expression(const struct position position, const std::string& name)
: type_expression(position), name(name)
{
@ -486,6 +654,47 @@ namespace boot
{
}
literal *literal::is_literal()
{
return this;
}
void literal::accept(parser_visitor *visitor)
{
if (number_literal<std::int32_t> *node = is_int())
{
return node->accept(visitor);
}
else if (number_literal<std::uint32_t> *node = is_word())
{
return node->accept(visitor);
}
else if (number_literal<double> *node = is_float())
{
return node->accept(visitor);
}
else if (number_literal<bool> *node = is_bool())
{
return node->accept(visitor);
}
else if (number_literal<unsigned char> *node = is_char())
{
return node->accept(visitor);
}
else if (number_literal<std::nullptr_t> *node = is_nil())
{
return node->accept(visitor);
}
else if (number_literal<std::string> *node = is_string())
{
return node->accept(visitor);
}
else
{
__builtin_unreachable();
}
}
defer_statement::defer_statement(const struct position position)
: node(position)
{
@ -496,6 +705,11 @@ namespace boot
visitor->visit(this);
}
defer_statement *defer_statement::is_defer()
{
return this;
}
defer_statement::~defer_statement()
{
for (statement *body_statement : statements)
@ -508,6 +722,36 @@ namespace boot
{
}
designator_expression::~designator_expression()
{
}
designator_expression *designator_expression::is_designator()
{
return this;
}
void designator_expression::accept(parser_visitor *visitor)
{
if (variable_expression *node = is_variable())
{
return visitor->visit(node);
}
else if (array_access_expression *node = is_array_access())
{
return visitor->visit(node);
}
else if (field_access_expression *node = is_field_access())
{
return visitor->visit(node);
}
else if (dereference_expression *node = is_dereference())
{
return visitor->visit(node);
}
__builtin_unreachable();
}
variable_expression::variable_expression(const struct position position, const std::string& name)
: node(position), name(name)
{
@ -623,6 +867,11 @@ namespace boot
visitor->visit(this);
}
binary_expression *binary_expression::is_binary()
{
return this;
}
expression& binary_expression::lhs()
{
return *m_lhs;
@ -655,6 +904,11 @@ namespace boot
visitor->visit(this);
}
unary_expression *unary_expression::is_unary()
{
return this;
}
expression& unary_expression::operand()
{
return *m_operand;
@ -680,6 +934,16 @@ namespace boot
visitor->visit(this);
}
procedure_call *procedure_call::is_call_statement()
{
return this;
}
procedure_call *procedure_call::is_call_expression()
{
return this;
}
designator_expression& procedure_call::callable()
{
return *m_callable;
@ -705,6 +969,11 @@ namespace boot
visitor->visit(this);
}
cast_expression *cast_expression::is_cast()
{
return this;
}
type_expression& cast_expression::target()
{
return *m_target;
@ -731,6 +1000,11 @@ namespace boot
visitor->visit(this);
}
traits_expression *traits_expression::is_traits()
{
return this;
}
type_expression& traits_expression::type()
{
return *m_type;
@ -765,6 +1039,11 @@ namespace boot
visitor->visit(this);
}
return_statement *return_statement::is_return()
{
return this;
}
expression *return_statement::return_expression()
{
return m_return_expression;
@ -775,15 +1054,20 @@ namespace boot
delete m_return_expression;
}
assign_statement::assign_statement(const struct position position, designator_expression *lvalue,
expression *rvalue)
: node(position), m_lvalue(lvalue), m_rvalue(rvalue)
{
}
void assign_statement::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
assign_statement::assign_statement(const struct position position, designator_expression *lvalue,
expression *rvalue)
: node(position), m_lvalue(lvalue), m_rvalue(rvalue)
assign_statement *assign_statement::is_assign()
{
return this;
}
variable_expression *designator_expression::is_variable()
@ -832,6 +1116,11 @@ namespace boot
visitor->visit(this);
}
if_statement *if_statement::is_if()
{
return this;
}
conditional_statements& if_statement::body()
{
return *m_body;
@ -862,6 +1151,11 @@ namespace boot
visitor->visit(this);
}
while_statement *while_statement::is_while()
{
return this;
}
conditional_statements& while_statement::body()
{
return *m_body;

View File

@ -1,33 +0,0 @@
/* Semantic analysis visitors.
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/>. */
#include "elna/boot/semantic.h"
namespace elna
{
namespace boot
{
declaration_visitor::declaration_visitor(std::shared_ptr<symbol_table> table)
: table(table)
{
}
void declaration_visitor::visit(program *program)
{
}
}
}

View File

@ -1,37 +0,0 @@
/* 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/>. */
#include "elna/boot/symbol.h"
namespace elna
{
namespace boot
{
type::~type()
{
}
info::~info()
{
}
type_info::type_info(const std::string& name)
: name(name)
{
}
}
}

View File

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

View File

@ -38,9 +38,73 @@ namespace elna
{
namespace gcc
{
declaration_visitor::declaration_visitor(std::shared_ptr<symbol_table> symbol_table)
: symbols(symbol_table)
{
this->unresolved.insert({ "Int", std::make_shared<type>(elna_int_type_node) });
this->unresolved.insert({ "Word", std::make_shared<type>(elna_word_type_node) });
this->unresolved.insert({ "Char", std::make_shared<type>(elna_char_type_node) });
this->unresolved.insert({ "Bool", std::make_shared<type>(elna_bool_type_node) });
this->unresolved.insert({ "Byte", std::make_shared<type>(elna_byte_type_node) });
this->unresolved.insert({ "Float", std::make_shared<type>(elna_float_type_node) });
this->unresolved.insert({ "String", std::make_shared<type>(elna_string_type_node) });
}
tree get_inner_alias(const type& t)
{
if (t.reference == nullptr)
{
return t.resolved;
}
else
{
return get_inner_alias(*t.reference);
}
}
void declaration_visitor::visit(boot::program *program)
{
for (boot::type_definition *const type : program->types)
{
type->accept(this);
}
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 if (auto alias_node = type->body().is_record())
{
unresolved_declaration->resolved = make_node(RECORD_TYPE);
}
else if (auto alias_node = type->body().is_union())
{
unresolved_declaration->resolved = make_node(UNION_TYPE);
}
}
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, std::make_shared<type>() });
}
generic_visitor::generic_visitor(std::shared_ptr<symbol_table> symbol_table)
{
this->symbol_map = symbol_table;
this->symbols = symbol_table;
}
void generic_visitor::build_procedure_call(location_t call_location,
@ -180,23 +244,6 @@ namespace gcc
constant->accept(this);
}
for (boot::type_definition *const type : program->types)
{
tree type_node = NULL_TREE;
if (type->body().is_record())
{
type_node = make_node(RECORD_TYPE);
}
else if (type->body().is_union())
{
type_node = make_node(UNION_TYPE);
}
if (type_node != NULL_TREE)
{
this->symbol_map->enter(type->identifier, type_node);
}
}
for (boot::type_definition *const type : program->types)
{
type->accept(this);
}
@ -229,7 +276,7 @@ namespace gcc
DECL_CONTEXT(declaration_tree) = fndecl;
DECL_ARG_TYPE(declaration_tree) = TREE_VALUE(parameter_type);
this->symbol_map->enter(argument_name, declaration_tree);
this->symbols->enter(argument_name, declaration_tree);
DECL_ARGUMENTS(fndecl) = chainon(DECL_ARGUMENTS(fndecl), declaration_tree);
parameter_type = TREE_CHAIN(parameter_type);
}
@ -269,7 +316,7 @@ namespace gcc
{
tree declaration_type = build_procedure_type(definition->heading());
tree fndecl = build_fn_decl(definition->identifier.c_str(), declaration_type);
this->symbol_map->enter(definition->identifier, fndecl);
this->symbols->enter(definition->identifier, fndecl);
if (definition->heading().no_return)
{
@ -299,7 +346,7 @@ namespace gcc
if (definition->body != nullptr)
{
this->symbol_map->enter(parameter->identifier, declaration_tree);
this->symbols->enter(parameter->identifier, declaration_tree);
}
argument_chain = chainon(argument_chain, declaration_tree);
function_args_iter_next(&parameter_type);
@ -332,7 +379,7 @@ namespace gcc
void generic_visitor::enter_scope()
{
this->symbol_map = std::make_shared<symbol_table>(this->symbol_map);
this->symbols = std::make_shared<symbol_table>(this->symbols);
// Chain the binding levels.
struct binding_level *new_level = ggc_cleared_alloc<binding_level>();
@ -352,7 +399,7 @@ namespace gcc
BLOCK_SUPERCONTEXT(it) = new_block;
}
tree bind_expr = build3(BIND_EXPR, void_type_node, variables, chain_defer(), new_block);
this->symbol_map = this->symbol_map->scope();
this->symbols = this->symbols->scope();
f_binding_level = f_binding_level->level_chain;
@ -365,35 +412,7 @@ namespace gcc
tree generic_visitor::lookup(const std::string& name)
{
if (name == "Int")
{
return elna_int_type_node;
}
if (name == "Word")
{
return elna_word_type_node;
}
if (name == "Char")
{
return elna_char_type_node;
}
if (name == "Bool")
{
return elna_bool_type_node;
}
if (name == "Byte")
{
return elna_byte_type_node;
}
if (name == "Float")
{
return elna_float_type_node;
}
if (name == "String")
{
return elna_string_type_node;
}
return this->symbol_map->lookup(name);
return this->symbols->lookup(name);
}
void generic_visitor::visit(boot::number_literal<std::int32_t> *literal)
@ -720,7 +739,7 @@ namespace gcc
tree definition_tree = build_decl(definition_location, CONST_DECL,
get_identifier(definition->identifier.c_str()), TREE_TYPE(this->current_expression));
auto result = this->symbol_map->enter(definition->identifier, definition_tree);
auto result = this->symbols->enter(definition->identifier, definition_tree);
if (result)
{
@ -748,12 +767,12 @@ namespace gcc
void generic_visitor::visit(boot::type_definition *definition)
{
location_t definition_location = get_location(&definition->position());
this->current_expression = this->symbol_map->lookup(definition->identifier);
this->current_expression = lookup(definition->identifier);
definition->body().accept(this);
tree definition_tree = build_decl(definition_location, TYPE_DECL,
get_identifier(definition->identifier.c_str()), this->current_expression);
auto result = this->symbol_map->enter(definition->identifier, this->current_expression);
auto result = this->symbols->enter(definition->identifier, this->current_expression);
/* if (result)
{ */
@ -798,7 +817,7 @@ namespace gcc
location_t declaration_location = get_location(&declaration->position());
tree declaration_tree = build_decl(declaration_location, VAR_DECL,
get_identifier(declaration->identifier.c_str()), this->current_expression);
bool result = this->symbol_map->enter(declaration->identifier, declaration_tree);
bool result = this->symbols->enter(declaration->identifier, declaration_tree);
if (is_pointer_type(this->current_expression))
{
@ -829,7 +848,7 @@ namespace gcc
void generic_visitor::visit(boot::variable_expression *expression)
{
auto symbol = this->lookup(expression->name);
auto symbol = lookup(expression->name);
if (symbol == NULL_TREE)
{
@ -1122,9 +1141,9 @@ namespace gcc
void generic_visitor::visit(boot::primitive_type_expression *type)
{
tree symbol = this->lookup(type->name);
tree symbol = lookup(type->name);
if (symbol == NULL_TREE && TYPE_P(symbol))
if (symbol == NULL_TREE || !TYPE_P(symbol))
{
error_at(get_location(&type->position()),
"type '%s' not declared", type->name.c_str());

View File

@ -30,7 +30,6 @@ along with GCC; see the file COPYING3. If not see
#include <fstream>
#include "elna/boot/driver.h"
#include "elna/boot/semantic.h"
#include "elna/gcc/elna-tree.h"
#include "elna/gcc/elna-generic.h"
#include "elna/gcc/elna-diagnostic.h"
@ -89,8 +88,10 @@ static void elna_parse_file(const char *filename)
}
else
{
elna::boot::declaration_visitor declaration_visitor{ std::make_shared<elna::boot::symbol_table>() };
elna::gcc::generic_visitor generic_visitor{ std::make_shared<elna::gcc::symbol_table>() };
std::shared_ptr<elna::gcc::symbol_table> symbol_table = std::make_shared<elna::gcc::symbol_table>();
elna::gcc::declaration_visitor declaration_visitor{ symbol_table };
elna::gcc::generic_visitor generic_visitor{ symbol_table };
declaration_visitor.visit(driver.tree.get());
generic_visitor.visit(driver.tree.get());

View File

@ -79,6 +79,8 @@ namespace boot
class array_access_expression;
class field_access_expression;
class dereference_expression;
class designator_expression;
class literal;
template<typename T>
class number_literal;
class defer_statement;
@ -132,9 +134,9 @@ namespace boot
virtual void visit(constant_definition *) override;
virtual void visit(procedure_definition *) override;
virtual void visit(type_definition *) override;
virtual void visit(traits_expression *) override;
virtual void visit(procedure_call *) override;
virtual void visit(cast_expression *) override;
virtual void visit(traits_expression *) override;
virtual void visit(assign_statement *) override;
virtual void visit(if_statement *) override;
virtual void visit(while_statement *) override;
@ -177,8 +179,7 @@ namespace boot
explicit node(const position position);
public:
virtual ~node() = default;
virtual void accept(parser_visitor *) = 0;
virtual ~node() = 0;
/**
* \return Node position in the source code.
@ -188,12 +189,35 @@ namespace boot
class statement : public virtual node
{
public:
virtual assign_statement *is_assign();
virtual if_statement *is_if();
virtual while_statement *is_while();
virtual return_statement *is_return();
virtual defer_statement *is_defer();
virtual procedure_call *is_call_statement();
void accept(parser_visitor *visitor);
~statement() = 0;
protected:
statement();
};
class expression : public virtual node
{
public:
virtual cast_expression *is_cast();
virtual traits_expression *is_traits();
virtual binary_expression *is_binary();
virtual unary_expression *is_unary();
virtual designator_expression *is_designator();
virtual procedure_call *is_call_expression();
virtual literal *is_literal();
void accept(parser_visitor *visitor);
~expression() = 0;
protected:
expression();
};
@ -224,6 +248,8 @@ namespace boot
virtual std::shared_ptr<union_type_expression> is_union();
virtual std::shared_ptr<procedure_type_expression> is_procedure();
void accept(parser_visitor *visitor);
protected:
type_expression(const struct position position);
};
@ -237,7 +263,7 @@ namespace boot
const std::string name;
primitive_type_expression(const struct position position, const std::string& name);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
std::shared_ptr<primitive_type_expression> is_primitive() override;
};
@ -250,7 +276,7 @@ namespace boot
array_type_expression(const struct position position,
std::shared_ptr<type_expression> base, const std::uint32_t size);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
std::shared_ptr<array_type_expression> is_array() override;
type_expression& base();
@ -262,7 +288,7 @@ namespace boot
public:
pointer_type_expression(const struct position position, std::shared_ptr<type_expression> base);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
std::shared_ptr<pointer_type_expression> is_pointer() override;
type_expression& base();
@ -278,7 +304,7 @@ namespace boot
record_type_expression(const struct position position, fields_t&& fields);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
std::shared_ptr<record_type_expression> is_record() override;
};
@ -289,7 +315,7 @@ namespace boot
union_type_expression(const struct position position, fields_t&& fields);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
std::shared_ptr<union_type_expression> is_union() override;
};
@ -303,7 +329,7 @@ namespace boot
public:
variable_declaration(const struct position position, const std::string& identifier,
std::shared_ptr<type_expression> type, const bool exported = false);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
type_expression& variable_type();
};
@ -313,6 +339,18 @@ namespace boot
*/
class literal : public expression
{
public:
virtual number_literal<std::int32_t> *is_int() = 0;
virtual number_literal<std::uint32_t> *is_word() = 0;
virtual number_literal<double> *is_float() = 0;
virtual number_literal<bool> *is_bool() = 0;
virtual number_literal<unsigned char> *is_char() = 0;
virtual number_literal<std::nullptr_t> *is_nil() = 0;
virtual number_literal<std::string> *is_string() = 0;
literal *is_literal() override;
void accept(parser_visitor *visitor);
protected:
literal();
};
@ -332,7 +370,7 @@ namespace boot
*/
constant_definition(const struct position position, const std::string& identifier,
const bool exported, literal *body);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
literal& body();
@ -361,7 +399,7 @@ namespace boot
std::shared_ptr<type_expression> return_type = nullptr);
procedure_type_expression(const struct position position, no_return_t);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
std::shared_ptr<procedure_type_expression> is_procedure() override;
virtual ~procedure_type_expression() override;
@ -379,7 +417,7 @@ namespace boot
procedure_definition(const struct position position, const std::string& identifier,
const bool exported, std::shared_ptr<procedure_type_expression> heading, block *body = nullptr);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
procedure_type_expression& heading();
@ -396,7 +434,7 @@ namespace boot
public:
type_definition(const struct position position, const std::string& identifier,
const bool exported, std::shared_ptr<type_expression> expression);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
type_expression& body();
};
@ -411,7 +449,8 @@ namespace boot
public:
cast_expression(const struct position position, std::shared_ptr<type_expression> target, expression *value);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
cast_expression *is_cast() override;
type_expression& target();
expression& value();
@ -428,7 +467,8 @@ namespace boot
traits_expression(const struct position position, const std::string& name,
std::shared_ptr<type_expression> type);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
traits_expression *is_traits() override;
type_expression& type();
};
@ -456,7 +496,8 @@ namespace boot
public:
return_statement(const struct position position, expression *return_expression);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
virtual return_statement *is_return() override;
expression *return_expression();
@ -471,6 +512,10 @@ namespace boot
virtual field_access_expression *is_field_access();
virtual dereference_expression *is_dereference();
designator_expression *is_designator() override;
void accept(parser_visitor *visitor);
~designator_expression() = 0;
protected:
designator_expression();
};
@ -481,7 +526,7 @@ namespace boot
const std::string name;
variable_expression(const struct position position, const std::string& name);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
variable_expression *is_variable() override;
};
@ -493,7 +538,7 @@ namespace boot
public:
array_access_expression(const struct position position, expression *base, expression *index);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
expression& base();
expression& index();
@ -511,7 +556,7 @@ namespace boot
public:
field_access_expression(const struct position position, expression *base,
const std::string& field);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
expression& base();
std::string& field();
@ -527,7 +572,7 @@ namespace boot
public:
dereference_expression(const struct position position, expression *base);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
expression& base();
@ -547,7 +592,9 @@ namespace boot
std::vector<expression *> arguments;
procedure_call(const struct position position, designator_expression *callable);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
virtual procedure_call *is_call_statement() override;
virtual procedure_call *is_call_expression() override;
designator_expression& callable();
@ -567,12 +614,13 @@ namespace boot
*/
assign_statement(const struct position position, designator_expression *lvalue,
expression *rvalue);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
designator_expression& lvalue();
expression& rvalue();
virtual ~assign_statement() override;
assign_statement *is_assign() override;
};
/**
@ -588,7 +636,8 @@ namespace boot
if_statement(const struct position position, conditional_statements *body,
std::vector<statement *> *alternative = nullptr);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
virtual if_statement *is_if() override;
conditional_statements& body();
std::vector<statement *> *alternative();
@ -606,7 +655,8 @@ namespace boot
public:
std::vector<conditional_statements *> branches;
while_statement(const struct position position, conditional_statements *body);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
while_statement *is_while() override;
conditional_statements& body();
@ -621,7 +671,7 @@ namespace boot
std::vector<statement *> body;
block(const struct position position);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
virtual ~block() override;
};
@ -633,7 +683,7 @@ namespace boot
std::vector<procedure_definition *> procedures;
program(const struct position position);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
virtual ~program() override;
};
@ -649,7 +699,91 @@ namespace boot
{
}
virtual void accept(parser_visitor *visitor) override
number_literal<std::int32_t> *is_int() override
{
if (std::is_same<T, std::int32_t>::value)
{
return reinterpret_cast<number_literal<std::int32_t> *>(this);
}
else
{
return nullptr;
}
}
number_literal<std::uint32_t> *is_word() override
{
if (std::is_same<T, std::uint32_t>::value)
{
return reinterpret_cast<number_literal<std::uint32_t> *>(this);
}
else
{
return nullptr;
}
}
number_literal<double> *is_float() override
{
if (std::is_same<T, double>::value)
{
return reinterpret_cast<number_literal<double> *>(this);
}
else
{
return nullptr;
}
}
number_literal<bool> *is_bool() override
{
if (std::is_same<T, bool>::value)
{
return reinterpret_cast<number_literal<bool> *>(this);
}
else
{
return nullptr;
}
}
number_literal<unsigned char> *is_char() override
{
if (std::is_same<T, unsigned char>::value)
{
return reinterpret_cast<number_literal<unsigned char> *>(this);
}
else
{
return nullptr;
}
}
number_literal<std::nullptr_t> *is_nil() override
{
if (std::is_same<T, std::nullptr_t>::value)
{
return reinterpret_cast<number_literal<std::nullptr_t> *>(this);
}
else
{
return nullptr;
}
}
number_literal<std::string> *is_string() override
{
if (std::is_same<T, std::string>::value)
{
return reinterpret_cast<number_literal<std::string> *>(this);
}
else
{
return nullptr;
}
}
void accept(parser_visitor *visitor)
{
visitor->visit(this);
}
@ -661,7 +795,8 @@ namespace boot
std::vector<statement *> statements;
defer_statement(const struct position position);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
defer_statement *is_defer() override;
virtual ~defer_statement() override;
};
@ -676,7 +811,9 @@ namespace boot
binary_expression(const struct position position, expression *lhs,
expression *rhs, const binary_operator operation);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
binary_expression *is_binary() override;
expression& lhs();
expression& rhs();
binary_operator operation() const;
@ -693,7 +830,9 @@ namespace boot
unary_expression(const struct position position, expression *operand,
const unary_operator operation);
virtual void accept(parser_visitor *visitor) override;
void accept(parser_visitor *visitor);
unary_expression *is_unary() override;
expression& operand();
unary_operator operation() const;

View File

@ -1,37 +0,0 @@
/* Semantic analysis visitors.
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/ast.h"
#include "elna/boot/symbol.h"
namespace elna
{
namespace boot
{
class declaration_visitor : public empty_visitor
{
std::shared_ptr<symbol_table> table;
public:
declaration_visitor(std::shared_ptr<symbol_table> table);
void visit(program *program) override;
};
}
}

View File

@ -26,32 +26,6 @@ namespace elna
{
namespace boot
{
class info
{
public:
virtual ~info() = 0;
protected:
info() = default;
};
class type
{
public:
virtual ~type() = 0;
protected:
type() = default;
};
class type_info : public info, public type
{
public:
const std::string name;
type_info(const std::string& name);
};
/**
* Symbol table.
*/
@ -146,7 +120,5 @@ namespace boot
return this->outer_scope;
}
};
using symbol_table = symbol_map<std::shared_ptr<info>, std::nullptr_t, nullptr>;
}
}

View File

@ -27,17 +27,39 @@ along with GCC; see the file COPYING3. If not see
#include "tree.h"
#include "tree-iterator.h"
#include <forward_list>
#include <unordered_map>
#include <string>
namespace elna
{
namespace gcc
{
struct type
{
type() {}
type(tree resolved): resolved(resolved) {}
type(std::shared_ptr<type> reference): reference(reference) {}
tree resolved{ NULL_TREE };
std::shared_ptr<type> reference;
};
class declaration_visitor final : public boot::empty_visitor
{
std::shared_ptr<symbol_table> symbols;
std::unordered_map<std::string, std::shared_ptr<type>> unresolved;
public:
declaration_visitor(std::shared_ptr<symbol_table> symbol_table);
void visit(boot::program *program) override;
void visit(boot::type_definition *definition) override;
};
class generic_visitor final : public boot::empty_visitor
{
tree current_expression{ NULL_TREE };
std::shared_ptr<symbol_table> symbol_map;
std::shared_ptr<symbol_table> symbols;
tree build_label_decl(const char *name, location_t loc);
tree build_procedure_type(boot::procedure_type_expression& type);

View File

@ -6,9 +6,6 @@ require 'uri'
require 'net/http'
require 'open3'
LINKER = 'build/rootfs/riscv32-unknown-linux-gnu/bin/ld'
AS = 'build/rootfs/riscv32-unknown-linux-gnu/bin/as'
TMP = Pathname.new('./build')
class BuildTarget