Type check the return statement
This commit is contained in:
parent
c022805c53
commit
d359056354
191
boot/ast.cc
191
boot/ast.cc
@ -33,14 +33,6 @@ namespace elna::boot
|
||||
return this->source_position;
|
||||
}
|
||||
|
||||
statement::statement()
|
||||
{
|
||||
}
|
||||
|
||||
statement::~statement()
|
||||
{
|
||||
}
|
||||
|
||||
assign_statement *statement::is_assign()
|
||||
{
|
||||
return nullptr;
|
||||
@ -71,14 +63,6 @@ namespace elna::boot
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
expression::expression()
|
||||
{
|
||||
}
|
||||
|
||||
expression::~expression()
|
||||
{
|
||||
}
|
||||
|
||||
cast_expression *expression::is_cast()
|
||||
{
|
||||
return nullptr;
|
||||
@ -114,39 +98,6 @@ namespace elna::boot
|
||||
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_expression *node = is_literal())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
type_expression::type_expression(const struct position position)
|
||||
: node(position)
|
||||
{
|
||||
@ -182,35 +133,6 @@ namespace elna::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)
|
||||
{
|
||||
@ -301,8 +223,8 @@ namespace elna::boot
|
||||
}
|
||||
|
||||
variable_declaration::variable_declaration(const struct position position, const std::string& identifier,
|
||||
std::shared_ptr<type_expression> type, const bool exported)
|
||||
: definition(position, identifier, exported), m_type(type)
|
||||
std::shared_ptr<type_expression> variable_type, const bool exported)
|
||||
: definition(position, identifier, exported), m_variable_type(variable_type)
|
||||
{
|
||||
}
|
||||
|
||||
@ -313,7 +235,7 @@ namespace elna::boot
|
||||
|
||||
type_expression& variable_declaration::variable_type()
|
||||
{
|
||||
return *m_type;
|
||||
return *m_variable_type;
|
||||
}
|
||||
|
||||
definition::definition(const struct position position, const std::string& identifier, const bool exported)
|
||||
@ -462,47 +384,16 @@ namespace elna::boot
|
||||
return this;
|
||||
}
|
||||
|
||||
void literal_expression::accept(parser_visitor *visitor)
|
||||
{
|
||||
if (literal<std::int32_t> *node = is_int())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (literal<std::uint32_t> *node = is_word())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (literal<double> *node = is_float())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (literal<bool> *node = is_bool())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (literal<unsigned char> *node = is_char())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (literal<std::nullptr_t> *node = is_nil())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (literal<std::string> *node = is_string())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else
|
||||
{
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
defer_statement::defer_statement(const struct position position)
|
||||
: node(position)
|
||||
{
|
||||
}
|
||||
|
||||
void defer_statement::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
defer_statement *defer_statement::is_defer()
|
||||
{
|
||||
return this;
|
||||
@ -529,11 +420,37 @@ namespace elna::boot
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
void variable_expression::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
variable_expression *variable_expression::is_variable()
|
||||
{
|
||||
return this;
|
||||
@ -545,6 +462,11 @@ namespace elna::boot
|
||||
{
|
||||
}
|
||||
|
||||
void array_access_expression::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
expression& array_access_expression::index()
|
||||
{
|
||||
return *m_index;
|
||||
@ -572,6 +494,11 @@ namespace elna::boot
|
||||
{
|
||||
}
|
||||
|
||||
void field_access_expression::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
expression& field_access_expression::base()
|
||||
{
|
||||
return *m_base;
|
||||
@ -598,6 +525,11 @@ namespace elna::boot
|
||||
{
|
||||
}
|
||||
|
||||
void dereference_expression::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
expression& dereference_expression::base()
|
||||
{
|
||||
return *m_base;
|
||||
@ -686,6 +618,11 @@ namespace elna::boot
|
||||
{
|
||||
}
|
||||
|
||||
void procedure_call::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
procedure_call *procedure_call::is_call_statement()
|
||||
{
|
||||
return this;
|
||||
@ -780,6 +717,11 @@ namespace elna::boot
|
||||
{
|
||||
}
|
||||
|
||||
void return_statement::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
return_statement *return_statement::is_return()
|
||||
{
|
||||
return this;
|
||||
@ -801,6 +743,11 @@ namespace elna::boot
|
||||
{
|
||||
}
|
||||
|
||||
void assign_statement::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
assign_statement *assign_statement::is_assign()
|
||||
{
|
||||
return this;
|
||||
@ -847,6 +794,11 @@ namespace elna::boot
|
||||
{
|
||||
}
|
||||
|
||||
void if_statement::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
if_statement *if_statement::is_if()
|
||||
{
|
||||
return this;
|
||||
@ -877,6 +829,11 @@ namespace elna::boot
|
||||
{
|
||||
}
|
||||
|
||||
void while_statement::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
while_statement *while_statement::is_while()
|
||||
{
|
||||
return this;
|
||||
|
@ -286,10 +286,15 @@ if_statement:
|
||||
$$ = new boot::if_statement(boot::make_position(@1), then, _else);
|
||||
std::swap($5, $$->branches);
|
||||
}
|
||||
return_statement: "return" expression
|
||||
return_statement:
|
||||
"return" expression
|
||||
{
|
||||
$$ = new boot::return_statement(boot::make_position(@1), $2);
|
||||
}
|
||||
| "return"
|
||||
{
|
||||
$$ = new boot::return_statement(boot::make_position(@1));
|
||||
}
|
||||
defer_statement: DEFER statements "end"
|
||||
{
|
||||
$$ = new boot::defer_statement(boot::make_position(@1));
|
||||
@ -472,9 +477,9 @@ statements:
|
||||
field_declaration:
|
||||
IDENTIFIER ":" type_expression { $$ = std::make_pair($1, $3); }
|
||||
required_fields:
|
||||
field_declaration required_fields
|
||||
field_declaration ";" required_fields
|
||||
{
|
||||
std::swap($$, $2);
|
||||
std::swap($$, $3);
|
||||
$$.emplace($$.cbegin(), $1);
|
||||
}
|
||||
| field_declaration { $$.emplace_back($1); }
|
||||
@ -534,14 +539,14 @@ constant_definition: identifier_definition "=" literal
|
||||
$$ = new boot::constant_definition(boot::make_position(@1), $1.first, $1.second, $3);
|
||||
}
|
||||
constant_definitions:
|
||||
constant_definition constant_definitions
|
||||
constant_definition ";" constant_definitions
|
||||
{
|
||||
std::swap($$, $2);
|
||||
std::swap($$, $3);
|
||||
$$.insert($$.cbegin(), $1);
|
||||
}
|
||||
| /* no constant definitions */ {}
|
||||
constant_part:
|
||||
{}
|
||||
/* no constant definitions */ {}
|
||||
| "const" constant_definitions { std::swap($$, $2); }
|
||||
type_definition: identifier_definition "=" type_expression
|
||||
{
|
||||
@ -553,10 +558,9 @@ type_definitions:
|
||||
std::swap($$, $2);
|
||||
$$.insert($$.cbegin(), $1);
|
||||
}
|
||||
| type_definition { $$.push_back($1); }
|
||||
| /* no type definitions */ {}
|
||||
type_part:
|
||||
/* no type definitions */ {}
|
||||
| "type" {}
|
||||
| "type" type_definitions { std::swap($$, $2); }
|
||||
formal_parameter: IDENTIFIER ":" type_expression
|
||||
{
|
||||
|
179
boot/semantic.cc
179
boot/semantic.cc
@ -65,6 +65,18 @@ namespace elna::boot
|
||||
auto info = std::make_shared<type_info>(type_info(type(unresolved.second)));
|
||||
this->symbols->enter(std::move(unresolved.first), info);
|
||||
}
|
||||
for (variable_declaration *const variable : program->variables)
|
||||
{
|
||||
variable->accept(this);
|
||||
}
|
||||
for (procedure_definition *const procedure : program->procedures)
|
||||
{
|
||||
procedure->accept(this);
|
||||
}
|
||||
for (statement *const statement : program->body)
|
||||
{
|
||||
statement->accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(type_definition *definition)
|
||||
@ -106,142 +118,219 @@ namespace elna::boot
|
||||
this->current_type = type(std::make_shared<array_type>(this->current_type, type_expression->size));
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(record_type_expression *)
|
||||
void declaration_visitor::visit(record_type_expression *type_expression)
|
||||
{
|
||||
this->current_type = type(std::make_shared<record_type>());
|
||||
auto result_type = std::make_shared<record_type>();
|
||||
|
||||
for (auto& field : type_expression->fields)
|
||||
{
|
||||
field.second->accept(this);
|
||||
result_type->fields.push_back(std::make_pair(field.first, this->current_type));
|
||||
}
|
||||
this->current_type = type(result_type);
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(union_type_expression *)
|
||||
void declaration_visitor::visit(union_type_expression *type_expression)
|
||||
{
|
||||
this->current_type = type(std::make_shared<union_type>());
|
||||
auto result_type = std::make_shared<union_type>();
|
||||
|
||||
for (auto& field : type_expression->fields)
|
||||
{
|
||||
field.second->accept(this);
|
||||
result_type->fields.push_back(std::make_pair(field.first, this->current_type));
|
||||
}
|
||||
this->current_type = type(result_type);
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(procedure_type_expression *)
|
||||
{
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(variable_declaration *)
|
||||
void declaration_visitor::visit(variable_declaration *declaration)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
declaration->variable_type().accept(this);
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(constant_definition *)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(procedure_definition *)
|
||||
void declaration_visitor::visit(procedure_definition *definition)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
for (auto heading_parameter : definition->heading().parameters)
|
||||
{
|
||||
heading_parameter->accept(this);
|
||||
}
|
||||
if (definition->heading().return_type.type != nullptr)
|
||||
{
|
||||
definition->heading().return_type.type->accept(this);
|
||||
}
|
||||
if (definition->body != nullptr)
|
||||
{
|
||||
definition->body->accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(assign_statement *)
|
||||
void declaration_visitor::visit(assign_statement *statement)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
statement->lvalue().accept(this);
|
||||
statement->rvalue().accept(this);
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(if_statement *)
|
||||
void declaration_visitor::visit(if_statement *statement)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
statement->body().prerequisite().accept(this);
|
||||
for (struct statement *const statement : statement->body().statements)
|
||||
{
|
||||
statement->accept(this);
|
||||
}
|
||||
for (const auto branch : statement->branches)
|
||||
{
|
||||
branch->prerequisite().accept(this);
|
||||
|
||||
for (struct statement *const statement : branch->statements)
|
||||
{
|
||||
statement->accept(this);
|
||||
}
|
||||
}
|
||||
if (statement->alternative() != nullptr)
|
||||
{
|
||||
for (struct statement *const statement : *statement->alternative())
|
||||
{
|
||||
statement->accept(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(while_statement *)
|
||||
void declaration_visitor::visit(while_statement *statement)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
statement->body().prerequisite().accept(this);
|
||||
for (struct statement *const statement : statement->body().statements)
|
||||
{
|
||||
statement->accept(this);
|
||||
}
|
||||
for (const auto branch : statement->branches)
|
||||
{
|
||||
branch->prerequisite().accept(this);
|
||||
|
||||
for (struct statement *const statement : branch->statements)
|
||||
{
|
||||
statement->accept(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(return_statement *)
|
||||
void declaration_visitor::visit(return_statement *statement)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
if (statement->return_expression() != nullptr)
|
||||
{
|
||||
statement->return_expression()->accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(defer_statement *)
|
||||
void declaration_visitor::visit(defer_statement *statement)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
for (struct statement *const statement : statement->statements)
|
||||
{
|
||||
statement->accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(procedure_call *)
|
||||
void declaration_visitor::visit(procedure_call *call)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
call->callable().accept(this);
|
||||
for (expression *const argument: call->arguments)
|
||||
{
|
||||
argument->accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(block *)
|
||||
void declaration_visitor::visit(block *block)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
for (constant_definition *const constant : block->constants)
|
||||
{
|
||||
constant->accept(this);
|
||||
}
|
||||
for (variable_declaration *const variable : block->variables)
|
||||
{
|
||||
variable->accept(this);
|
||||
}
|
||||
for (statement *const statement : block->body)
|
||||
{
|
||||
statement->accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(traits_expression *)
|
||||
void declaration_visitor::visit(traits_expression *trait)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
if (!trait->parameters.empty())
|
||||
{
|
||||
trait->parameters.front()->accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(cast_expression *)
|
||||
void declaration_visitor::visit(cast_expression *expression)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
expression->value().accept(this);
|
||||
expression->target().accept(this);
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(binary_expression *)
|
||||
void declaration_visitor::visit(binary_expression *expression)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
expression->lhs().accept(this);
|
||||
expression->rhs().accept(this);
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(unary_expression *)
|
||||
void declaration_visitor::visit(unary_expression *expression)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
expression->operand().accept(this);
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(variable_expression *)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(array_access_expression *)
|
||||
void declaration_visitor::visit(array_access_expression *expression)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
expression->base().accept(this);
|
||||
expression->index().accept(this);
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(field_access_expression *)
|
||||
void declaration_visitor::visit(field_access_expression *expression)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
expression->base().accept(this);
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(dereference_expression *)
|
||||
void declaration_visitor::visit(dereference_expression *expression)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
expression->base().accept(this);
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(literal<std::int32_t> *)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(literal<std::uint32_t> *)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(literal<double> *)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(literal<bool> *)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(literal<unsigned char> *)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(literal<std::nullptr_t> *)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(literal<std::string> *)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
@ -49,17 +49,29 @@ namespace elna::gcc
|
||||
layout_type(elna_string_type_node);
|
||||
}
|
||||
|
||||
static
|
||||
void declare_builtin_type(std::shared_ptr<symbol_table> symbol_table, const char *name, tree type)
|
||||
{
|
||||
tree identifier = get_identifier(name);
|
||||
tree type_declaration = build_decl(UNKNOWN_LOCATION, TYPE_DECL, identifier, type);
|
||||
|
||||
TREE_PUBLIC(type_declaration) = 1;
|
||||
TYPE_NAME(type_declaration) = identifier;
|
||||
|
||||
symbol_table->enter(name, type_declaration);
|
||||
}
|
||||
|
||||
std::shared_ptr<symbol_table> builtin_symbol_table()
|
||||
{
|
||||
std::shared_ptr<elna::gcc::symbol_table> symbol_table = std::make_shared<elna::gcc::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);
|
||||
declare_builtin_type(symbol_table, "Int", elna_int_type_node);
|
||||
declare_builtin_type(symbol_table, "Word", elna_word_type_node);
|
||||
declare_builtin_type(symbol_table, "Char", elna_char_type_node);
|
||||
declare_builtin_type(symbol_table, "Bool", elna_bool_type_node);
|
||||
declare_builtin_type(symbol_table, "Byte", elna_byte_type_node);
|
||||
declare_builtin_type(symbol_table, "Float", elna_float_type_node);
|
||||
declare_builtin_type(symbol_table, "String", elna_string_type_node);
|
||||
|
||||
return symbol_table;
|
||||
}
|
||||
|
@ -36,11 +36,20 @@ along with GCC; see the file COPYING3. If not see
|
||||
|
||||
namespace elna::gcc
|
||||
{
|
||||
tree get_inner_alias(const boot::type& type, std::shared_ptr<symbol_table> symbols)
|
||||
tree get_inner_alias(const boot::type& type, std::shared_ptr<symbol_table> symbols,
|
||||
std::unordered_map<std::string, tree>& unresolved)
|
||||
{
|
||||
if (auto reference = type.get<boot::primitive_type>())
|
||||
{
|
||||
return symbols->lookup(reference->identifier);
|
||||
auto looked_up = unresolved.find(reference->identifier);
|
||||
if (looked_up == unresolved.cend())
|
||||
{
|
||||
return symbols->lookup(reference->identifier);
|
||||
}
|
||||
else
|
||||
{
|
||||
return looked_up->second;
|
||||
}
|
||||
}
|
||||
else if (auto reference = type.get<boot::record_type>())
|
||||
{
|
||||
@ -52,7 +61,7 @@ namespace elna::gcc
|
||||
}
|
||||
else if (auto reference = type.get<boot::pointer_type>())
|
||||
{
|
||||
return build_pointer_type_for_mode(get_inner_alias(reference->base, symbols), VOIDmode, true);
|
||||
return build_global_pointer_type(get_inner_alias(reference->base, symbols, unresolved));
|
||||
}
|
||||
else if (auto reference = type.get<boot::array_type>())
|
||||
{
|
||||
@ -60,30 +69,31 @@ namespace elna::gcc
|
||||
tree upper_bound = build_int_cst_type(integer_type_node, reference->size);
|
||||
tree range_type = build_range_type(integer_type_node, lower_bound, upper_bound);
|
||||
|
||||
return build_array_type(get_inner_alias(reference->base, symbols), range_type);
|
||||
return build_array_type(get_inner_alias(reference->base, symbols, unresolved), range_type);
|
||||
}
|
||||
else if (auto reference = type.get<boot::alias_type>())
|
||||
{
|
||||
return handle_symbol(reference->name, reference->reference, symbols);
|
||||
return handle_symbol(reference->name, reference->reference, symbols, unresolved);
|
||||
}
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
tree handle_symbol(const std::string& symbol_name, const boot::type& type, std::shared_ptr<symbol_table> symbols)
|
||||
tree handle_symbol(const std::string& symbol_name, const boot::type& type,
|
||||
std::shared_ptr<symbol_table> symbols, std::unordered_map<std::string, tree>& unresolved)
|
||||
{
|
||||
auto looked_up = symbols->lookup(symbol_name);
|
||||
|
||||
if (looked_up == NULL_TREE)
|
||||
{
|
||||
looked_up = get_inner_alias(type, symbols);
|
||||
symbols->enter(symbol_name, looked_up);
|
||||
looked_up = get_inner_alias(type, symbols, unresolved);
|
||||
unresolved.insert({ symbol_name, looked_up });
|
||||
}
|
||||
return looked_up;
|
||||
}
|
||||
|
||||
std::deque<std::unique_ptr<boot::error>> do_semantic_analysis(const char *path,
|
||||
std::unique_ptr<boot::program>& ast, std::shared_ptr<boot::symbol_table> info_table,
|
||||
std::shared_ptr<symbol_table> symbols)
|
||||
std::shared_ptr<symbol_table> symbols, std::unordered_map<std::string, tree>& unresolved)
|
||||
{
|
||||
boot::declaration_visitor declaration_visitor(path, info_table);
|
||||
|
||||
@ -93,15 +103,16 @@ namespace elna::gcc
|
||||
{
|
||||
for (auto& [symbol_name, symbol_info] : declaration_visitor.unresolved)
|
||||
{
|
||||
handle_symbol(symbol_name, boot::type(symbol_info), symbols);
|
||||
handle_symbol(symbol_name, boot::type(symbol_info), symbols, unresolved);
|
||||
}
|
||||
}
|
||||
return std::move(declaration_visitor.errors());
|
||||
}
|
||||
|
||||
generic_visitor::generic_visitor(std::shared_ptr<symbol_table> symbol_table)
|
||||
generic_visitor::generic_visitor(std::shared_ptr<symbol_table> symbol_table,
|
||||
std::unordered_map<std::string, tree>&& unresolved)
|
||||
: symbols(symbol_table), unresolved(std::move(unresolved))
|
||||
{
|
||||
this->symbols = symbol_table;
|
||||
}
|
||||
|
||||
void generic_visitor::build_procedure_call(location_t call_location,
|
||||
@ -201,14 +212,14 @@ namespace elna::gcc
|
||||
? this->current_expression
|
||||
: TREE_TYPE(this->current_expression);
|
||||
|
||||
if (TYPE_P(this->current_expression) && TREE_CODE(expression_type) == RECORD_TYPE)
|
||||
if (TREE_CODE(expression_type) == RECORD_TYPE)
|
||||
{
|
||||
build_record_call(call_location, this->current_expression, call->arguments);
|
||||
build_record_call(call_location, expression_type, call->arguments);
|
||||
}
|
||||
else if (TREE_CODE(expression_type) == FUNCTION_TYPE)
|
||||
{
|
||||
this->current_expression = build1(ADDR_EXPR,
|
||||
build_pointer_type_for_mode(expression_type, VOIDmode, true), this->current_expression);
|
||||
build_global_pointer_type(expression_type), this->current_expression);
|
||||
build_procedure_call(call_location, this->current_expression, call->arguments);
|
||||
}
|
||||
else if (is_pointer_type(expression_type) && TREE_CODE(TREE_TYPE(expression_type)) == FUNCTION_TYPE)
|
||||
@ -263,8 +274,8 @@ namespace elna::gcc
|
||||
{
|
||||
procedure->accept(this);
|
||||
}
|
||||
tree declaration_type = build_function_type_list(integer_type_node, integer_type_node,
|
||||
build_pointer_type(build_pointer_type(char_type_node)), NULL_TREE);
|
||||
tree declaration_type = build_function_type_list(integer_type_node, elna_int_type_node,
|
||||
build_global_pointer_type(build_global_pointer_type(elna_char_type_node)), NULL_TREE);
|
||||
tree fndecl = build_fn_decl("main", declaration_type);
|
||||
|
||||
tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, integer_type_node);
|
||||
@ -702,7 +713,7 @@ namespace elna::gcc
|
||||
TREE_ADDRESSABLE(this->current_expression) = 1;
|
||||
this->current_expression = build_fold_addr_expr_with_type_loc(location,
|
||||
this->current_expression,
|
||||
build_pointer_type_for_mode(TREE_TYPE(this->current_expression), VOIDmode, true));
|
||||
build_global_pointer_type(TREE_TYPE(this->current_expression)));
|
||||
TREE_NO_TRAMPOLINE(this->current_expression) = 1;
|
||||
break;
|
||||
case boot::unary_operator::negation:
|
||||
@ -763,8 +774,7 @@ namespace elna::gcc
|
||||
}
|
||||
else
|
||||
{
|
||||
error_at(definition_location,
|
||||
"variable '%s' already declared in this scope",
|
||||
error_at(definition_location, "Variable '%s' already declared in this scope",
|
||||
definition->identifier.c_str());
|
||||
}
|
||||
this->current_expression = NULL_TREE;
|
||||
@ -773,15 +783,18 @@ namespace elna::gcc
|
||||
void generic_visitor::visit(boot::type_definition *definition)
|
||||
{
|
||||
location_t definition_location = get_location(&definition->position());
|
||||
this->current_expression = this->symbols->lookup(definition->identifier);
|
||||
this->current_expression = this->unresolved.at(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->symbols->enter(definition->identifier, this->current_expression);
|
||||
|
||||
TREE_PUBLIC(definition_tree) = definition->exported;
|
||||
TYPE_NAME(this->current_expression) = get_identifier(definition->identifier.c_str());
|
||||
|
||||
auto result = this->symbols->enter(definition->identifier, definition_tree);
|
||||
gcc_assert(result);
|
||||
|
||||
this->current_expression = NULL_TREE;
|
||||
}
|
||||
|
||||
@ -878,8 +891,7 @@ namespace elna::gcc
|
||||
|
||||
if (symbol == NULL_TREE)
|
||||
{
|
||||
error_at(get_location(&expression->position()),
|
||||
"symbol '%s' not declared in the current scope",
|
||||
error_at(get_location(&expression->position()), "Symbol '%s' not declared in the current scope",
|
||||
expression->name.c_str());
|
||||
this->current_expression = error_mark_node;
|
||||
}
|
||||
@ -1051,7 +1063,7 @@ namespace elna::gcc
|
||||
}
|
||||
else if (is_array_type(aggregate_type) && expression->field() == "ptr")
|
||||
{
|
||||
tree ptr_type = build_pointer_type_for_mode(TREE_TYPE(aggregate_type), VOIDmode, true);
|
||||
tree ptr_type = build_global_pointer_type(TREE_TYPE(aggregate_type));
|
||||
this->current_expression = build1(ADDR_EXPR,
|
||||
build_qualified_type(ptr_type, TYPE_QUAL_CONST), this->current_expression);
|
||||
}
|
||||
@ -1225,29 +1237,65 @@ namespace elna::gcc
|
||||
void generic_visitor::visit(boot::return_statement *statement)
|
||||
{
|
||||
boot::expression *return_expression = statement->return_expression();
|
||||
location_t statement_position = get_location(&statement->position());
|
||||
tree set_result{ NULL_TREE };
|
||||
tree return_type = TREE_TYPE(TREE_TYPE(current_function_decl));
|
||||
|
||||
if (return_expression == nullptr)
|
||||
if (TREE_THIS_VOLATILE(current_function_decl) == 1)
|
||||
{
|
||||
error_at(statement_position, "This procedure is not allowed to return");
|
||||
return;
|
||||
}
|
||||
return_expression->accept(this);
|
||||
|
||||
tree set_result = build2(INIT_EXPR, void_type_node, DECL_RESULT(current_function_decl),
|
||||
this->current_expression);
|
||||
tree return_stmt = build1(RETURN_EXPR, void_type_node, set_result);
|
||||
append_statement(return_stmt);
|
||||
if (return_expression != nullptr)
|
||||
{
|
||||
return_expression->accept(this);
|
||||
|
||||
set_result = build2(INIT_EXPR, void_type_node, DECL_RESULT(current_function_decl),
|
||||
this->current_expression);
|
||||
}
|
||||
if (return_type == void_type_node && set_result != NULL_TREE)
|
||||
{
|
||||
error_at(statement_position, "Proper procedure is not allowed to return a value");
|
||||
}
|
||||
else if (return_type != void_type_node && set_result == NULL_TREE)
|
||||
{
|
||||
error_at(statement_position, "Procedure is expected to return a value of type '%s'",
|
||||
print_type(return_type).c_str());
|
||||
}
|
||||
else if (return_type != void_type_node && !is_assignable_from(return_type, this->current_expression))
|
||||
{
|
||||
error_at(statement_position, "Cannot return '%s' from a procedure returning '%s'",
|
||||
print_type(return_type).c_str(),
|
||||
print_type(TREE_TYPE(this->current_expression)).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
tree return_stmt = build1_loc(statement_position, RETURN_EXPR, void_type_node, set_result);
|
||||
append_statement(return_stmt);
|
||||
}
|
||||
this->current_expression = NULL_TREE;
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::primitive_type_expression *type)
|
||||
{
|
||||
tree symbol = this->symbols->lookup(type->name);
|
||||
auto looked_up = this->unresolved.find(type->name);
|
||||
tree symbol;
|
||||
|
||||
if (looked_up == this->unresolved.cend())
|
||||
{
|
||||
symbol = this->symbols->lookup(type->name);
|
||||
if (symbol != NULL_TREE)
|
||||
{
|
||||
symbol = TREE_TYPE(symbol);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
symbol = looked_up->second;
|
||||
}
|
||||
if (symbol == NULL_TREE || !TYPE_P(symbol))
|
||||
{
|
||||
error_at(get_location(&type->position()),
|
||||
"type '%s' not declared", type->name.c_str());
|
||||
error_at(get_location(&type->position()), "Type '%s' not declared", type->name.c_str());
|
||||
|
||||
this->current_expression = error_mark_node;
|
||||
}
|
||||
@ -1277,7 +1325,7 @@ namespace elna::gcc
|
||||
|
||||
if (this->current_expression != NULL_TREE && this->current_expression != error_mark_node)
|
||||
{
|
||||
this->current_expression = build_pointer_type_for_mode(this->current_expression, VOIDmode, true);
|
||||
this->current_expression = build_global_pointer_type(this->current_expression);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1302,7 +1350,7 @@ namespace elna::gcc
|
||||
void generic_visitor::visit(boot::procedure_type_expression *type)
|
||||
{
|
||||
tree procedure_type_node = build_procedure_type(*type);
|
||||
this->current_expression = build_pointer_type_for_mode(procedure_type_node, VOIDmode, true);
|
||||
this->current_expression = build_global_pointer_type(procedure_type_node);
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::defer_statement *statement)
|
||||
|
@ -248,4 +248,9 @@ namespace elna::gcc
|
||||
}
|
||||
return field_declaration;
|
||||
}
|
||||
|
||||
tree build_global_pointer_type(tree type)
|
||||
{
|
||||
return build_pointer_type_for_mode(type, VOIDmode, true);
|
||||
}
|
||||
}
|
||||
|
@ -85,12 +85,14 @@ static void elna_parse_file(const char *filename)
|
||||
{
|
||||
std::shared_ptr<elna::boot::symbol_table> info_table = elna::boot::builtin_symbol_table();
|
||||
std::shared_ptr<elna::gcc::symbol_table> symbol_table = elna::gcc::builtin_symbol_table();
|
||||
std::unordered_map<std::string, tree> unresolved;
|
||||
|
||||
auto semantic_errors = elna::gcc::do_semantic_analysis(filename, driver.tree, info_table, symbol_table);
|
||||
auto semantic_errors = elna::gcc::do_semantic_analysis(filename, driver.tree,
|
||||
info_table, symbol_table, unresolved);
|
||||
|
||||
if (semantic_errors.empty())
|
||||
{
|
||||
elna::gcc::generic_visitor generic_visitor{ symbol_table };
|
||||
elna::gcc::generic_visitor generic_visitor{ symbol_table, std::move(unresolved) };
|
||||
generic_visitor.visit(driver.tree.get());
|
||||
}
|
||||
else
|
||||
|
@ -138,6 +138,7 @@ namespace elna::boot
|
||||
explicit node(const position position);
|
||||
|
||||
public:
|
||||
virtual void accept(parser_visitor *visitor) = 0;
|
||||
virtual ~node() = 0;
|
||||
|
||||
/**
|
||||
@ -155,41 +156,6 @@ namespace elna::boot
|
||||
virtual return_statement *is_return();
|
||||
virtual defer_statement *is_defer();
|
||||
virtual procedure_call *is_call_statement();
|
||||
|
||||
template<typename V>
|
||||
void accept(V *visitor)
|
||||
{
|
||||
if (assign_statement *node = is_assign())
|
||||
{
|
||||
return visitor->visit(node);
|
||||
}
|
||||
else if (if_statement *node = is_if())
|
||||
{
|
||||
return visitor->visit(node);
|
||||
}
|
||||
else if (while_statement *node = is_while())
|
||||
{
|
||||
return visitor->visit(node);
|
||||
}
|
||||
else if (return_statement *node = is_return())
|
||||
{
|
||||
return visitor->visit(node);
|
||||
}
|
||||
else if (defer_statement *node = is_defer())
|
||||
{
|
||||
return visitor->visit(node);
|
||||
}
|
||||
else if (procedure_call *node = is_call_statement())
|
||||
{
|
||||
return visitor->visit(node);
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
~statement() = 0;
|
||||
|
||||
protected:
|
||||
statement();
|
||||
};
|
||||
|
||||
class expression : public virtual node
|
||||
@ -202,12 +168,6 @@ namespace elna::boot
|
||||
virtual designator_expression *is_designator();
|
||||
virtual procedure_call *is_call_expression();
|
||||
virtual literal_expression *is_literal();
|
||||
|
||||
void accept(parser_visitor *visitor);
|
||||
~expression() = 0;
|
||||
|
||||
protected:
|
||||
expression();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -236,8 +196,6 @@ namespace elna::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);
|
||||
};
|
||||
@ -251,7 +209,7 @@ namespace elna::boot
|
||||
const std::string name;
|
||||
|
||||
primitive_type_expression(const struct position position, const std::string& name);
|
||||
void accept(parser_visitor *visitor);
|
||||
void accept(parser_visitor *visitor) override;
|
||||
std::shared_ptr<primitive_type_expression> is_primitive() override;
|
||||
};
|
||||
|
||||
@ -264,7 +222,7 @@ namespace elna::boot
|
||||
|
||||
array_type_expression(const struct position position,
|
||||
std::shared_ptr<type_expression> base, const std::uint32_t size);
|
||||
void accept(parser_visitor *visitor);
|
||||
void accept(parser_visitor *visitor) override;
|
||||
std::shared_ptr<array_type_expression> is_array() override;
|
||||
|
||||
type_expression& base();
|
||||
@ -276,7 +234,7 @@ namespace elna::boot
|
||||
|
||||
public:
|
||||
pointer_type_expression(const struct position position, std::shared_ptr<type_expression> base);
|
||||
void accept(parser_visitor *visitor);
|
||||
void accept(parser_visitor *visitor) override;
|
||||
std::shared_ptr<pointer_type_expression> is_pointer() override;
|
||||
|
||||
type_expression& base();
|
||||
@ -291,7 +249,7 @@ namespace elna::boot
|
||||
|
||||
record_type_expression(const struct position position, std::vector<field_declaration>&& fields);
|
||||
|
||||
void accept(parser_visitor *visitor);
|
||||
void accept(parser_visitor *visitor) override;
|
||||
std::shared_ptr<record_type_expression> is_record() override;
|
||||
};
|
||||
|
||||
@ -302,7 +260,7 @@ namespace elna::boot
|
||||
|
||||
union_type_expression(const struct position position, std::vector<field_declaration>&& fields);
|
||||
|
||||
void accept(parser_visitor *visitor);
|
||||
void accept(parser_visitor *visitor) override;
|
||||
std::shared_ptr<union_type_expression> is_union() override;
|
||||
};
|
||||
|
||||
@ -311,12 +269,12 @@ namespace elna::boot
|
||||
*/
|
||||
class variable_declaration : public definition
|
||||
{
|
||||
std::shared_ptr<type_expression> m_type;
|
||||
std::shared_ptr<type_expression> m_variable_type;
|
||||
|
||||
public:
|
||||
variable_declaration(const struct position position, const std::string& identifier,
|
||||
std::shared_ptr<type_expression> type, const bool exported = false);
|
||||
void accept(parser_visitor *visitor);
|
||||
std::shared_ptr<type_expression> variable_type, const bool exported = false);
|
||||
void accept(parser_visitor *visitor) override;
|
||||
|
||||
type_expression& variable_type();
|
||||
};
|
||||
@ -336,7 +294,6 @@ namespace elna::boot
|
||||
virtual literal<std::string> *is_string() = 0;
|
||||
|
||||
literal_expression *is_literal() override;
|
||||
void accept(parser_visitor *visitor);
|
||||
|
||||
protected:
|
||||
literal_expression();
|
||||
@ -350,14 +307,9 @@ namespace elna::boot
|
||||
literal_expression *m_body;
|
||||
|
||||
public:
|
||||
/**
|
||||
* \param position Source code position.
|
||||
* \param identifier Constant name.
|
||||
* \param body Constant value.
|
||||
*/
|
||||
constant_definition(const struct position position, const std::string& identifier,
|
||||
const bool exported, literal_expression *body);
|
||||
void accept(parser_visitor *visitor);
|
||||
void accept(parser_visitor *visitor) override;
|
||||
|
||||
literal_expression& body();
|
||||
|
||||
@ -389,7 +341,7 @@ namespace elna::boot
|
||||
procedure_type_expression(const struct position position,
|
||||
return_declaration return_type = return_declaration());
|
||||
|
||||
void accept(parser_visitor *visitor);
|
||||
void accept(parser_visitor *visitor) override;
|
||||
std::shared_ptr<procedure_type_expression> is_procedure() override;
|
||||
};
|
||||
|
||||
@ -406,7 +358,7 @@ namespace elna::boot
|
||||
|
||||
procedure_definition(const struct position position, const std::string& identifier,
|
||||
const bool exported, std::shared_ptr<procedure_type_expression> heading, block *body = nullptr);
|
||||
void accept(parser_visitor *visitor);
|
||||
void accept(parser_visitor *visitor) override;
|
||||
|
||||
procedure_type_expression& heading();
|
||||
|
||||
@ -423,7 +375,7 @@ namespace elna::boot
|
||||
public:
|
||||
type_definition(const struct position position, const std::string& identifier,
|
||||
const bool exported, std::shared_ptr<type_expression> expression);
|
||||
void accept(parser_visitor *visitor);
|
||||
void accept(parser_visitor *visitor) override;
|
||||
|
||||
type_expression& body();
|
||||
};
|
||||
@ -438,7 +390,7 @@ namespace elna::boot
|
||||
|
||||
public:
|
||||
cast_expression(const struct position position, std::shared_ptr<type_expression> target, expression *value);
|
||||
void accept(parser_visitor *visitor);
|
||||
void accept(parser_visitor *visitor) override;
|
||||
cast_expression *is_cast() override;
|
||||
|
||||
type_expression& target();
|
||||
@ -454,7 +406,7 @@ namespace elna::boot
|
||||
const std::string name;
|
||||
|
||||
traits_expression(const struct position position, const std::string& name);
|
||||
void accept(parser_visitor *visitor);
|
||||
void accept(parser_visitor *visitor) override;
|
||||
traits_expression *is_traits() override;
|
||||
};
|
||||
|
||||
@ -480,17 +432,12 @@ namespace elna::boot
|
||||
expression *m_return_expression{ nullptr };
|
||||
|
||||
public:
|
||||
return_statement(const struct position position, expression *return_expression);
|
||||
|
||||
template<typename V>
|
||||
void accept(V *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
return_statement(const struct position position, expression *return_expression = nullptr);
|
||||
void accept(parser_visitor *visitor) override;
|
||||
virtual return_statement *is_return() override;
|
||||
|
||||
expression *return_expression();
|
||||
|
||||
virtual return_statement *is_return() override;
|
||||
virtual ~return_statement() override;
|
||||
};
|
||||
|
||||
@ -502,29 +449,8 @@ namespace elna::boot
|
||||
virtual field_access_expression *is_field_access();
|
||||
virtual dereference_expression *is_dereference();
|
||||
|
||||
template<typename V>
|
||||
void accept(V *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();
|
||||
}
|
||||
|
||||
designator_expression *is_designator() override;
|
||||
void accept(parser_visitor *visitor);
|
||||
~designator_expression() = 0;
|
||||
|
||||
protected:
|
||||
@ -537,12 +463,7 @@ namespace elna::boot
|
||||
const std::string name;
|
||||
|
||||
variable_expression(const struct position position, const std::string& name);
|
||||
|
||||
template<typename V>
|
||||
void accept(V *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
void accept(parser_visitor *visitor) override;
|
||||
|
||||
variable_expression *is_variable() override;
|
||||
};
|
||||
@ -554,12 +475,7 @@ namespace elna::boot
|
||||
|
||||
public:
|
||||
array_access_expression(const struct position position, expression *base, expression *index);
|
||||
|
||||
template<typename V>
|
||||
void accept(V *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
void accept(parser_visitor *visitor) override;
|
||||
|
||||
expression& base();
|
||||
expression& index();
|
||||
@ -577,12 +493,7 @@ namespace elna::boot
|
||||
public:
|
||||
field_access_expression(const struct position position, expression *base,
|
||||
const std::string& field);
|
||||
|
||||
template<typename V>
|
||||
void accept(V *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
void accept(parser_visitor *visitor) override;
|
||||
|
||||
expression& base();
|
||||
std::string& field();
|
||||
@ -598,16 +509,12 @@ namespace elna::boot
|
||||
|
||||
public:
|
||||
dereference_expression(const struct position position, expression *base);
|
||||
|
||||
template<typename V>
|
||||
void accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
void accept(parser_visitor *visitor) override;
|
||||
|
||||
expression& base();
|
||||
|
||||
dereference_expression *is_dereference() override;
|
||||
|
||||
~dereference_expression() override;
|
||||
};
|
||||
|
||||
@ -622,17 +529,12 @@ namespace elna::boot
|
||||
std::vector<expression *> arguments;
|
||||
|
||||
procedure_call(const struct position position, designator_expression *callable);
|
||||
|
||||
template<typename V>
|
||||
void accept(V *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
void accept(parser_visitor *visitor) override;
|
||||
virtual procedure_call *is_call_statement() override;
|
||||
virtual procedure_call *is_call_expression() override;
|
||||
|
||||
designator_expression& callable();
|
||||
|
||||
virtual procedure_call *is_call_statement() override;
|
||||
virtual procedure_call *is_call_expression() override;
|
||||
virtual ~procedure_call() override;
|
||||
};
|
||||
|
||||
@ -649,18 +551,13 @@ namespace elna::boot
|
||||
*/
|
||||
assign_statement(const struct position position, designator_expression *lvalue,
|
||||
expression *rvalue);
|
||||
|
||||
template<typename V>
|
||||
void accept(V *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
void accept(parser_visitor *visitor) override;
|
||||
|
||||
designator_expression& lvalue();
|
||||
expression& rvalue();
|
||||
|
||||
assign_statement *is_assign() override;
|
||||
virtual ~assign_statement() override;
|
||||
assign_statement *is_assign() override;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -676,17 +573,12 @@ namespace elna::boot
|
||||
|
||||
if_statement(const struct position position, conditional_statements *body,
|
||||
std::vector<statement *> *alternative = nullptr);
|
||||
|
||||
template<typename V>
|
||||
void accept(V *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
void accept(parser_visitor *visitor) override;
|
||||
virtual if_statement *is_if() override;
|
||||
|
||||
conditional_statements& body();
|
||||
std::vector<statement *> *alternative();
|
||||
|
||||
virtual if_statement *is_if() override;
|
||||
virtual ~if_statement() override;
|
||||
};
|
||||
|
||||
@ -700,16 +592,11 @@ namespace elna::boot
|
||||
public:
|
||||
std::vector<conditional_statements *> branches;
|
||||
while_statement(const struct position position, conditional_statements *body);
|
||||
|
||||
template<typename V>
|
||||
void accept(V *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
void accept(parser_visitor *visitor) override;
|
||||
while_statement *is_while() override;
|
||||
|
||||
conditional_statements& body();
|
||||
|
||||
while_statement *is_while() override;
|
||||
virtual ~while_statement() override;
|
||||
};
|
||||
|
||||
@ -721,7 +608,7 @@ namespace elna::boot
|
||||
std::vector<statement *> body;
|
||||
|
||||
block(const struct position position);
|
||||
void accept(parser_visitor *visitor);
|
||||
virtual void accept(parser_visitor *visitor) override;
|
||||
|
||||
virtual ~block() override;
|
||||
};
|
||||
@ -733,7 +620,7 @@ namespace elna::boot
|
||||
std::vector<procedure_definition *> procedures;
|
||||
|
||||
program(const struct position position);
|
||||
void accept(parser_visitor *visitor);
|
||||
void accept(parser_visitor *visitor) override;
|
||||
|
||||
virtual ~program() override;
|
||||
};
|
||||
@ -833,8 +720,7 @@ namespace elna::boot
|
||||
}
|
||||
}
|
||||
|
||||
template<typename V>
|
||||
void accept(V *visitor)
|
||||
void accept(parser_visitor *visitor) override
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
@ -846,14 +732,9 @@ namespace elna::boot
|
||||
std::vector<statement *> statements;
|
||||
|
||||
defer_statement(const struct position position);
|
||||
|
||||
template<typename V>
|
||||
void accept(V *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
void accept(parser_visitor *visitor) override;
|
||||
defer_statement *is_defer() override;
|
||||
|
||||
virtual ~defer_statement() override;
|
||||
};
|
||||
|
||||
@ -867,7 +748,7 @@ namespace elna::boot
|
||||
binary_expression(const struct position position, expression *lhs,
|
||||
expression *rhs, const binary_operator operation);
|
||||
|
||||
void accept(parser_visitor *visitor);
|
||||
void accept(parser_visitor *visitor) override;
|
||||
binary_expression *is_binary() override;
|
||||
|
||||
expression& lhs();
|
||||
@ -886,7 +767,7 @@ namespace elna::boot
|
||||
unary_expression(const struct position position, expression *operand,
|
||||
const unary_operator operation);
|
||||
|
||||
void accept(parser_visitor *visitor);
|
||||
void accept(parser_visitor *visitor) override;
|
||||
unary_expression *is_unary() override;
|
||||
|
||||
expression& operand();
|
||||
|
@ -61,28 +61,28 @@ namespace elna::boot
|
||||
void visit(pointer_type_expression *type_expression) override;
|
||||
void visit(program *program) override;
|
||||
void visit(type_definition *definition) override;
|
||||
void visit(record_type_expression *) override;
|
||||
void visit(union_type_expression *) override;
|
||||
void visit(record_type_expression *type_expression) override;
|
||||
void visit(union_type_expression *type_expression) override;
|
||||
void visit(procedure_type_expression *) override;
|
||||
|
||||
void visit(variable_declaration *) override;
|
||||
void visit(variable_declaration *declaration) override;
|
||||
void visit(constant_definition *) override;
|
||||
void visit(procedure_definition *) override;
|
||||
void visit(assign_statement *) override;
|
||||
void visit(if_statement *) override;
|
||||
void visit(while_statement *) override;
|
||||
void visit(return_statement *) override;
|
||||
void visit(defer_statement *) override;
|
||||
void visit(procedure_call *) override;
|
||||
void visit(block *) override;
|
||||
void visit(cast_expression *) override;
|
||||
void visit(traits_expression *) override;
|
||||
void visit(binary_expression *) override;
|
||||
void visit(unary_expression *) override;
|
||||
void visit(procedure_definition *definition) override;
|
||||
void visit(assign_statement *statement) override;
|
||||
void visit(if_statement *statement) override;
|
||||
void visit(while_statement *statement) override;
|
||||
void visit(return_statement *statement) override;
|
||||
void visit(defer_statement *statement) override;
|
||||
void visit(procedure_call *call) override;
|
||||
void visit(block *block) override;
|
||||
void visit(cast_expression *expression) override;
|
||||
void visit(traits_expression *trait) override;
|
||||
void visit(binary_expression *expression) override;
|
||||
void visit(unary_expression *expression) override;
|
||||
void visit(variable_expression *) override;
|
||||
void visit(array_access_expression *) override;
|
||||
void visit(field_access_expression *) override;
|
||||
void visit(dereference_expression *) override;
|
||||
void visit(array_access_expression *expression) override;
|
||||
void visit(field_access_expression *expression) override;
|
||||
void visit(dereference_expression *expression) override;
|
||||
void visit(literal<std::int32_t> *) override;
|
||||
void visit(literal<std::uint32_t> *) override;
|
||||
void visit(literal<double> *) override;
|
||||
|
@ -111,12 +111,16 @@ namespace elna::boot
|
||||
explicit primitive_type(const std::string& identifier);
|
||||
};
|
||||
|
||||
using type_field = std::pair<std::string, type>;
|
||||
|
||||
struct record_type
|
||||
{
|
||||
std::vector<type_field> fields;
|
||||
};
|
||||
|
||||
struct union_type
|
||||
{
|
||||
std::vector<type_field> fields;
|
||||
};
|
||||
|
||||
class type_info;
|
||||
|
@ -34,13 +34,15 @@ namespace elna::gcc
|
||||
{
|
||||
std::deque<std::unique_ptr<boot::error>> do_semantic_analysis(const char *path,
|
||||
std::unique_ptr<boot::program>& ast, std::shared_ptr<boot::symbol_table> info_table,
|
||||
std::shared_ptr<symbol_table> symbols);
|
||||
tree handle_symbol(const std::string& symbol_name, const boot::type& type, std::shared_ptr<symbol_table> symbols);
|
||||
std::shared_ptr<symbol_table> symbols, std::unordered_map<std::string, tree>& unresolved);
|
||||
tree handle_symbol(const std::string& symbol_name, const boot::type& type,
|
||||
std::shared_ptr<symbol_table> symbols, std::unordered_map<std::string, tree>& unresolved);
|
||||
|
||||
class generic_visitor final : public boot::parser_visitor
|
||||
{
|
||||
tree current_expression{ NULL_TREE };
|
||||
std::shared_ptr<symbol_table> symbols;
|
||||
std::unordered_map<std::string, tree> unresolved;
|
||||
|
||||
tree build_label_decl(const char *name, location_t loc);
|
||||
tree build_procedure_type(boot::procedure_type_expression& type);
|
||||
@ -68,7 +70,8 @@ namespace elna::gcc
|
||||
void visit_statements(const std::vector<boot::statement *>& statements);
|
||||
|
||||
public:
|
||||
generic_visitor(std::shared_ptr<symbol_table> symbol_table);
|
||||
generic_visitor(std::shared_ptr<symbol_table> symbol_table,
|
||||
std::unordered_map<std::string, tree>&& unresolved);
|
||||
|
||||
void visit(boot::program *program) override;
|
||||
void visit(boot::procedure_definition *definition) override;
|
||||
|
@ -81,4 +81,5 @@ namespace elna::gcc
|
||||
tree_code operator_code, tree left, tree right);
|
||||
tree build_field(location_t location, tree record_type, const std::string name, tree type);
|
||||
tree find_field_by_name(location_t expression_location, tree type, const std::string& field_name);
|
||||
tree build_global_pointer_type(tree type);
|
||||
}
|
||||
|
162
source.elna
162
source.elna
@ -1,110 +1,110 @@
|
||||
const
|
||||
SEEK_SET* = 0
|
||||
SEEK_CUR* = 1
|
||||
SEEK_END* = 2
|
||||
SEEK_SET* = 0;
|
||||
SEEK_CUR* = 1;
|
||||
SEEK_END* = 2;
|
||||
|
||||
TOKEN_IDENTIFIER* = 1
|
||||
TOKEN_IF* = 2
|
||||
TOKEN_THEN* = 3
|
||||
TOKEN_ELSE* = 4
|
||||
TOKEN_ELSIF* = 5
|
||||
TOKEN_WHILE* = 6
|
||||
TOKEN_DO* = 7
|
||||
TOKEN_PROC* = 8
|
||||
TOKEN_BEGIN* = 9
|
||||
TOKEN_END* = 10
|
||||
TOKEN_EXTERN* = 11
|
||||
TOKEN_CONST* = 12
|
||||
TOKEN_VAR* = 13
|
||||
TOKEN_ARRAY* = 14
|
||||
TOKEN_OF* = 15
|
||||
TOKEN_TYPE* = 16
|
||||
TOKEN_RECORD* = 17
|
||||
TOKEN_UNION* = 18
|
||||
TOKEN_POINTER* = 19
|
||||
TOKEN_TO* = 20
|
||||
TOKEN_BOOLEAN* = 21
|
||||
TOKEN_NIL* = 22
|
||||
TOKEN_AND* = 23
|
||||
TOKEN_OR* = 24
|
||||
TOKEN_NOT* = 25
|
||||
TOKEN_RETURN* = 26
|
||||
TOKEN_CAST* = 27
|
||||
TOKEN_SHIFT_LEFT* = 28
|
||||
TOKEN_SHIFT_RIGHT* = 29
|
||||
TOKEN_LEFT_PAREN* = 30
|
||||
TOKEN_RIGHT_PAREN* = 31
|
||||
TOKEN_LEFT_SQUARE* = 32
|
||||
TOKEN_RIGHT_SQUARE* = 33
|
||||
TOKEN_GREATER_EQUAL* = 34
|
||||
TOKEN_LESS_EQUAL* = 35
|
||||
TOKEN_GREATER_THAN* = 36
|
||||
TOKEN_LESS_THAN* = 37
|
||||
TOKEN_NOT_EQUAL* = 38
|
||||
TOKEN_EQUAL* = 39
|
||||
TOKEN_SEMICOLON* = 40
|
||||
TOKEN_DOT* = 41
|
||||
TOKEN_COMMA* = 42
|
||||
TOKEN_PLUS* = 43
|
||||
TOKEN_MINUS* = 44
|
||||
TOKEN_MULTIPLICATION* = 45
|
||||
TOKEN_DIVISION* = 46
|
||||
TOKEN_REMAINDER* = 47
|
||||
TOKEN_ASSIGNMENT* = 48
|
||||
TOKEN_COLON* = 49
|
||||
TOKEN_HAT* = 50
|
||||
TOKEN_AT* = 51
|
||||
TOKEN_COMMENT* = 52
|
||||
TOKEN_INTEGER* = 53
|
||||
TOKEN_WORD* = 54
|
||||
TOKEN_CHARACTER* = 55
|
||||
TOKEN_STRING* = 56
|
||||
TOKEN_DEFER* = 57
|
||||
TOKEN_EXCLAMATION* = 58
|
||||
TOKEN_ARROW = 59
|
||||
TOKEN_IDENTIFIER* = 1;
|
||||
TOKEN_IF* = 2;
|
||||
TOKEN_THEN* = 3;
|
||||
TOKEN_ELSE* = 4;
|
||||
TOKEN_ELSIF* = 5;
|
||||
TOKEN_WHILE* = 6;
|
||||
TOKEN_DO* = 7;
|
||||
TOKEN_PROC* = 8;
|
||||
TOKEN_BEGIN* = 9;
|
||||
TOKEN_END* = 10;
|
||||
TOKEN_EXTERN* = 11;
|
||||
TOKEN_CONST* = 12;
|
||||
TOKEN_VAR* = 13;
|
||||
TOKEN_ARRAY* = 14;
|
||||
TOKEN_OF* = 15;
|
||||
TOKEN_TYPE* = 16;
|
||||
TOKEN_RECORD* = 17;
|
||||
TOKEN_UNION* = 18;
|
||||
TOKEN_POINTER* = 19;
|
||||
TOKEN_TO* = 20;
|
||||
TOKEN_BOOLEAN* = 21;
|
||||
TOKEN_NIL* = 22;
|
||||
TOKEN_AND* = 23;
|
||||
TOKEN_OR* = 24;
|
||||
TOKEN_NOT* = 25;
|
||||
TOKEN_RETURN* = 26;
|
||||
TOKEN_CAST* = 27;
|
||||
TOKEN_SHIFT_LEFT* = 28;
|
||||
TOKEN_SHIFT_RIGHT* = 29;
|
||||
TOKEN_LEFT_PAREN* = 30;
|
||||
TOKEN_RIGHT_PAREN* = 31;
|
||||
TOKEN_LEFT_SQUARE* = 32;
|
||||
TOKEN_RIGHT_SQUARE* = 33;
|
||||
TOKEN_GREATER_EQUAL* = 34;
|
||||
TOKEN_LESS_EQUAL* = 35;
|
||||
TOKEN_GREATER_THAN* = 36;
|
||||
TOKEN_LESS_THAN* = 37;
|
||||
TOKEN_NOT_EQUAL* = 38;
|
||||
TOKEN_EQUAL* = 39;
|
||||
TOKEN_SEMICOLON* = 40;
|
||||
TOKEN_DOT* = 41;
|
||||
TOKEN_COMMA* = 42;
|
||||
TOKEN_PLUS* = 43;
|
||||
TOKEN_MINUS* = 44;
|
||||
TOKEN_MULTIPLICATION* = 45;
|
||||
TOKEN_DIVISION* = 46;
|
||||
TOKEN_REMAINDER* = 47;
|
||||
TOKEN_ASSIGNMENT* = 48;
|
||||
TOKEN_COLON* = 49;
|
||||
TOKEN_HAT* = 50;
|
||||
TOKEN_AT* = 51;
|
||||
TOKEN_COMMENT* = 52;
|
||||
TOKEN_INTEGER* = 53;
|
||||
TOKEN_WORD* = 54;
|
||||
TOKEN_CHARACTER* = 55;
|
||||
TOKEN_STRING* = 56;
|
||||
TOKEN_DEFER* = 57;
|
||||
TOKEN_EXCLAMATION* = 58;
|
||||
TOKEN_ARROW = 59;
|
||||
|
||||
type
|
||||
Position* = record
|
||||
line: Word
|
||||
line: Word;
|
||||
column: Word
|
||||
end
|
||||
Location* = record
|
||||
first: Position
|
||||
first: Position;
|
||||
last: Position
|
||||
end
|
||||
SourceFile* = record
|
||||
buffer: [1024]Char
|
||||
handle: ^FILE
|
||||
size: Word
|
||||
buffer: [1024]Char;
|
||||
handle: ^FILE;
|
||||
size: Word;
|
||||
index: Word
|
||||
end
|
||||
FILE* = record end
|
||||
StringBuffer* = record
|
||||
data: ^Byte
|
||||
size: Word
|
||||
data: ^Byte;
|
||||
size: Word;
|
||||
capacity: Word
|
||||
end
|
||||
SourceCode = record
|
||||
position: Position
|
||||
position: Position;
|
||||
|
||||
input: ^Byte
|
||||
empty: proc(^Byte) -> Bool
|
||||
advance: proc(^Byte)
|
||||
input: ^Byte;
|
||||
empty: proc(^Byte) -> Bool;
|
||||
advance: proc(^Byte);
|
||||
head: proc(^Byte) -> Char
|
||||
end
|
||||
Token* = record
|
||||
kind: Int
|
||||
kind: Int;
|
||||
value: union
|
||||
int_value: Int
|
||||
string: String
|
||||
boolean_value: Bool
|
||||
int_value: Int;
|
||||
string: String;
|
||||
boolean_value: Bool;
|
||||
char_value: Char
|
||||
end
|
||||
end;
|
||||
location: Location
|
||||
end
|
||||
CommandLine* = record
|
||||
input: ^Char
|
||||
tokenize: Bool
|
||||
input: ^Char;
|
||||
tokenize: Bool;
|
||||
syntax_tree: Bool
|
||||
end
|
||||
|
||||
@ -985,5 +985,5 @@ begin
|
||||
end
|
||||
|
||||
begin
|
||||
exit(process(cast(count: Int), cast(parameters: ^^Char)))
|
||||
exit(process(count, parameters))
|
||||
end.
|
||||
|
Loading…
x
Reference in New Issue
Block a user