Parse import declarations
This commit is contained in:
parent
981059e745
commit
573d812f1c
102
boot/ast.cc
102
boot/ast.cc
@ -308,8 +308,14 @@ namespace elna::boot
|
||||
}
|
||||
|
||||
procedure_definition::procedure_definition(const struct position position, identifier_definition identifier,
|
||||
procedure_type_expression *heading, block *body)
|
||||
: definition(position, identifier), m_heading(heading), body(body)
|
||||
procedure_type_expression *heading, block&& body)
|
||||
: definition(position, identifier), m_heading(heading), body(std::move(body))
|
||||
{
|
||||
}
|
||||
|
||||
procedure_definition::procedure_definition(const struct position position, identifier_definition identifier,
|
||||
procedure_type_expression *heading)
|
||||
: definition(position, identifier), m_heading(heading), body(std::nullopt)
|
||||
{
|
||||
}
|
||||
|
||||
@ -326,7 +332,6 @@ namespace elna::boot
|
||||
procedure_definition::~procedure_definition()
|
||||
{
|
||||
delete m_heading;
|
||||
delete body;
|
||||
}
|
||||
|
||||
type_definition::type_definition(const struct position position, identifier_definition identifier,
|
||||
@ -350,34 +355,94 @@ namespace elna::boot
|
||||
return *m_body;
|
||||
}
|
||||
|
||||
block::block(const struct position position)
|
||||
: node(position)
|
||||
block::block(std::vector<constant_definition *>&& constants, std::vector<variable_declaration *>&& variables,
|
||||
std::vector<statement *>&& body)
|
||||
: m_variables(std::move(variables)), m_constants(std::move(constants)), m_body(std::move(body))
|
||||
{
|
||||
}
|
||||
|
||||
void block::accept(parser_visitor *visitor)
|
||||
block::block(block&& that)
|
||||
: m_variables(std::move(that.m_variables)), m_constants(std::move(that.m_constants)),
|
||||
m_body(std::move(that.m_body))
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
block& block::operator=(block&& that)
|
||||
{
|
||||
std::swap(m_variables, that.m_variables);
|
||||
std::swap(m_constants, that.m_constants);
|
||||
std::swap(m_body, that.m_body);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const std::vector<variable_declaration *>& block::variables()
|
||||
{
|
||||
return m_variables;
|
||||
}
|
||||
|
||||
const std::vector<constant_definition *>& block::constants()
|
||||
{
|
||||
return m_constants;
|
||||
}
|
||||
|
||||
const std::vector<statement *>& block::body()
|
||||
{
|
||||
return m_body;
|
||||
}
|
||||
|
||||
block::~block()
|
||||
{
|
||||
for (statement *body_statement : this->body)
|
||||
for (statement *body_statement : this->body())
|
||||
{
|
||||
delete body_statement;
|
||||
}
|
||||
for (variable_declaration *variable : this->variables)
|
||||
for (variable_declaration *variable : this->variables())
|
||||
{
|
||||
delete variable;
|
||||
}
|
||||
for (constant_definition *constant : this->constants)
|
||||
for (constant_definition *constant : this->constants())
|
||||
{
|
||||
delete constant;
|
||||
}
|
||||
}
|
||||
|
||||
unit::unit(const struct position position)
|
||||
: node(position)
|
||||
{
|
||||
}
|
||||
|
||||
void unit::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
unit::~unit()
|
||||
{
|
||||
for (procedure_definition *procedure : this->procedures)
|
||||
{
|
||||
delete procedure;
|
||||
}
|
||||
for (variable_declaration *variable : this->variables)
|
||||
{
|
||||
delete variable;
|
||||
}
|
||||
for (type_definition *type : this->types)
|
||||
{
|
||||
delete type;
|
||||
}
|
||||
for (constant_definition *constant : this->constants)
|
||||
{
|
||||
delete constant;
|
||||
}
|
||||
for (import_declaration *declaration : this->imports)
|
||||
{
|
||||
delete declaration;
|
||||
}
|
||||
}
|
||||
|
||||
program::program(const struct position position)
|
||||
: block(position)
|
||||
: unit(position)
|
||||
{
|
||||
}
|
||||
|
||||
@ -388,13 +453,9 @@ namespace elna::boot
|
||||
|
||||
program::~program()
|
||||
{
|
||||
for (procedure_definition *procedure : this->procedures)
|
||||
for (statement *body_statement : this->body)
|
||||
{
|
||||
delete procedure;
|
||||
}
|
||||
for (type_definition *type : this->types)
|
||||
{
|
||||
delete type;
|
||||
delete body_statement;
|
||||
}
|
||||
}
|
||||
|
||||
@ -837,13 +898,12 @@ namespace elna::boot
|
||||
delete this->alternative;
|
||||
}
|
||||
|
||||
escape_statement::escape_statement(const struct position position,
|
||||
escape_direction direction, const std::string& label)
|
||||
: node(position), direction(direction), label(label)
|
||||
import_declaration::import_declaration(const struct position position, std::vector<std::string>&& segments)
|
||||
: node(position), segments(std::move(segments))
|
||||
{
|
||||
}
|
||||
|
||||
void escape_statement::accept(parser_visitor *visitor)
|
||||
void import_declaration::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
@ -125,12 +125,15 @@ or {
|
||||
return {
|
||||
return yy::parser::make_RETURN(this->location);
|
||||
}
|
||||
break {
|
||||
return yy::parser::make_BREAK(this->location);
|
||||
module {
|
||||
return yy::parser::make_MODULE(this->location);
|
||||
}
|
||||
program {
|
||||
return yy::parser::make_PROGRAM(this->location);
|
||||
}
|
||||
import {
|
||||
return yy::parser::make_IMPORT(this->location);
|
||||
}
|
||||
cast {
|
||||
return yy::parser::make_CAST(this->location);
|
||||
}
|
||||
|
@ -109,7 +109,8 @@ along with GCC; see the file COPYING3. If not see
|
||||
ELSIF "elsif"
|
||||
RETURN "return"
|
||||
PROGRAM "program"
|
||||
BREAK "break"
|
||||
MODULE "module"
|
||||
IMPORT "import"
|
||||
BEGIN_BLOCK "begin"
|
||||
END_BLOCK "end"
|
||||
DEFER "defer"
|
||||
@ -154,7 +155,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
%type <std::vector<elna::boot::procedure_definition *>> procedure_definitions procedure_part;
|
||||
%type <elna::boot::type_definition *> type_definition;
|
||||
%type <std::vector<elna::boot::type_definition *>> type_definitions type_part;
|
||||
%type <elna::boot::block *> block;
|
||||
%type <std::unique_ptr<elna::boot::block>> block;
|
||||
%type <elna::boot::field_declaration> field_declaration formal_parameter;
|
||||
%type <std::vector<std::pair<std::string, elna::boot::type_expression *>>>
|
||||
optional_fields required_fields formal_parameters;
|
||||
@ -163,28 +164,38 @@ along with GCC; see the file COPYING3. If not see
|
||||
%type <elna::boot::cast_expression *> cast_expression;
|
||||
%type <elna::boot::identifier_definition> identifier_definition;
|
||||
%type <std::vector<elna::boot::identifier_definition>> identifier_definitions;
|
||||
%type <std::vector<std::string>> identifiers;
|
||||
%type <std::vector<std::string>> identifiers import_declaration;
|
||||
%type <std::vector<elna::boot::import_declaration *>> import_declarations import_part;
|
||||
%%
|
||||
program:
|
||||
"program" constant_part type_part variable_part procedure_part "begin" statements "end" "."
|
||||
"program" import_part constant_part type_part variable_part procedure_part "begin" statements "end" "."
|
||||
{
|
||||
auto tree = new boot::program(boot::make_position(@6));
|
||||
auto tree = new boot::program(boot::make_position(@7));
|
||||
|
||||
std::swap(tree->constants, $2);
|
||||
std::swap(tree->types , $3);
|
||||
std::swap(tree->variables, $4);
|
||||
std::swap(tree->procedures, $5);
|
||||
std::swap(tree->body, $7);
|
||||
std::swap(tree->imports, $2);
|
||||
std::swap(tree->constants, $3);
|
||||
std::swap(tree->types , $4);
|
||||
std::swap(tree->variables, $5);
|
||||
std::swap(tree->procedures, $6);
|
||||
std::swap(tree->body, $8);
|
||||
|
||||
driver.tree.reset(tree);
|
||||
}
|
||||
| "module" import_part constant_part type_part variable_part procedure_part "end" "."
|
||||
{
|
||||
auto tree = new boot::program(boot::make_position(@7));
|
||||
|
||||
std::swap(tree->imports, $2);
|
||||
std::swap(tree->constants, $3);
|
||||
std::swap(tree->types , $4);
|
||||
std::swap(tree->variables, $5);
|
||||
std::swap(tree->procedures, $6);
|
||||
|
||||
driver.tree.reset(tree);
|
||||
}
|
||||
block: constant_part variable_part "begin" statements "end"
|
||||
{
|
||||
$$ = new boot::block(boot::make_position(@3));
|
||||
|
||||
std::swap($$->constants, $1);
|
||||
std::swap($$->variables, $2);
|
||||
std::swap($$->body, $4);
|
||||
$$ = std::make_unique<boot::block>(std::move($1), std::move($2), std::move($4));
|
||||
}
|
||||
identifier_definition:
|
||||
IDENTIFIER "*" { $$ = boot::identifier_definition{ $1, true }; }
|
||||
@ -211,12 +222,12 @@ procedure_heading:
|
||||
}
|
||||
}
|
||||
procedure_definition:
|
||||
"proc" identifier_definition procedure_heading block
|
||||
"proc" identifier_definition procedure_heading ";" block
|
||||
{
|
||||
$$ = new boot::procedure_definition(boot::make_position(@1), std::move($2), $3.second, $4);
|
||||
$$ = new boot::procedure_definition(boot::make_position(@1), std::move($2), $3.second, std::move(*$5));
|
||||
std::swap($3.first, $$->parameter_names);
|
||||
}
|
||||
| "proc" identifier_definition procedure_heading "extern"
|
||||
| "proc" identifier_definition procedure_heading ";" "extern"
|
||||
{
|
||||
$$ = new boot::procedure_definition(boot::make_position(@1), std::move($2), $3.second);
|
||||
std::swap($3.first, $$->parameter_names);
|
||||
@ -417,8 +428,6 @@ statement:
|
||||
$$ = new boot::if_statement(boot::make_position(@1), then, std::move($5), $6);
|
||||
}
|
||||
| return_statement { $$ = $1; }
|
||||
| "break" IDENTIFIER
|
||||
{ $$ = new boot::escape_statement(boot::make_position(@1), boot::escape_direction::end, $2); }
|
||||
| call_expression { $$ = $1; }
|
||||
| "defer" statements "end" { $$ = new boot::defer_statement(boot::make_position(@1), std::move($2)); }
|
||||
| "case" expression "of" switch_cases else_statements "end"
|
||||
@ -532,6 +541,27 @@ constant_definitions:
|
||||
constant_part:
|
||||
/* no constant definitions */ {}
|
||||
| "const" constant_definitions { std::swap($$, $2); }
|
||||
import_declaration:
|
||||
IDENTIFIER "." import_declaration
|
||||
{
|
||||
std::swap($$, $3);
|
||||
$$.emplace($$.cbegin(), std::move($1));
|
||||
}
|
||||
| IDENTIFIER { $$.emplace_back(std::move($1)); }
|
||||
import_declarations:
|
||||
/* no import declarations */ {}
|
||||
| import_declaration "," import_declarations
|
||||
{
|
||||
std::swap($$, $3);
|
||||
$$.emplace($$.cbegin(), new boot::import_declaration(boot::make_position(@1), std::move($1)));
|
||||
}
|
||||
| import_declaration
|
||||
{
|
||||
$$.emplace_back(new boot::import_declaration(boot::make_position(@1), std::move($1)));
|
||||
}
|
||||
import_part:
|
||||
/* no import declarations */ {}
|
||||
| "import" import_declarations { std::swap($$, $2); }
|
||||
type_definition: identifier_definition "=" type_expression
|
||||
{
|
||||
$$ = new boot::type_definition(boot::make_position(@1), std::move($1), $3);
|
||||
|
@ -75,33 +75,8 @@ namespace elna::boot
|
||||
|
||||
void declaration_visitor::visit(program *program)
|
||||
{
|
||||
for (type_definition *const type : program->types)
|
||||
{
|
||||
const std::string& type_identifier = type->identifier.identifier;
|
||||
visit(static_cast<unit *>(program));
|
||||
|
||||
if (!this->unresolved.insert({ type_identifier, std::make_shared<alias_type>(type_identifier) }).second
|
||||
|| this->symbols->contains(type_identifier))
|
||||
{
|
||||
add_error<already_declared_error>(type->identifier.identifier, this->input_file, type->position());
|
||||
}
|
||||
}
|
||||
for (type_definition *const type : program->types)
|
||||
{
|
||||
type->accept(this);
|
||||
}
|
||||
for (auto& unresolved : this->unresolved)
|
||||
{
|
||||
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);
|
||||
@ -205,9 +180,20 @@ namespace elna::boot
|
||||
build_procedure(definition->heading()), definition->parameter_names);
|
||||
|
||||
this->symbols->enter(definition->identifier.identifier, info);
|
||||
if (definition->body != nullptr)
|
||||
if (definition->body.has_value())
|
||||
{
|
||||
definition->body->accept(this);
|
||||
for (constant_definition *const constant : definition->body.value().constants())
|
||||
{
|
||||
constant->accept(this);
|
||||
}
|
||||
for (variable_declaration *const variable : definition->body.value().variables())
|
||||
{
|
||||
variable->accept(this);
|
||||
}
|
||||
for (statement *const statement : definition->body.value().body())
|
||||
{
|
||||
statement->accept(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -242,7 +228,7 @@ namespace elna::boot
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(escape_statement *)
|
||||
void declaration_visitor::visit(import_declaration *)
|
||||
{
|
||||
}
|
||||
|
||||
@ -305,19 +291,34 @@ namespace elna::boot
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(block *block)
|
||||
void declaration_visitor::visit(unit *unit)
|
||||
{
|
||||
for (constant_definition *const constant : block->constants)
|
||||
for (type_definition *const type : unit->types)
|
||||
{
|
||||
constant->accept(this);
|
||||
const std::string& type_identifier = type->identifier.identifier;
|
||||
|
||||
if (!this->unresolved.insert({ type_identifier, std::make_shared<alias_type>(type_identifier) }).second
|
||||
|| this->symbols->contains(type_identifier))
|
||||
{
|
||||
add_error<already_declared_error>(type->identifier.identifier, this->input_file, type->position());
|
||||
}
|
||||
}
|
||||
for (variable_declaration *const variable : block->variables)
|
||||
for (type_definition *const type : unit->types)
|
||||
{
|
||||
type->accept(this);
|
||||
}
|
||||
for (auto& unresolved : this->unresolved)
|
||||
{
|
||||
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 : unit->variables)
|
||||
{
|
||||
variable->accept(this);
|
||||
}
|
||||
for (statement *const statement : block->body)
|
||||
for (procedure_definition *const procedure : unit->procedures)
|
||||
{
|
||||
statement->accept(this);
|
||||
procedure->accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,31 +352,13 @@ namespace elna::gcc
|
||||
DECL_ARGUMENTS(fndecl) = argument_chain;
|
||||
TREE_PUBLIC(fndecl) = definition->identifier.exported;
|
||||
TREE_ADDRESSABLE(fndecl) = 1;
|
||||
DECL_EXTERNAL(fndecl) = definition->body == nullptr;
|
||||
DECL_EXTERNAL(fndecl) = !definition->body.has_value();
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::program *program)
|
||||
{
|
||||
for (boot::constant_definition *const constant : program->constants)
|
||||
{
|
||||
constant->accept(this);
|
||||
}
|
||||
for (boot::type_definition *const type : program->types)
|
||||
{
|
||||
type->accept(this);
|
||||
}
|
||||
for (boot::variable_declaration *const variable : program->variables)
|
||||
{
|
||||
variable->accept(this);
|
||||
}
|
||||
for (boot::procedure_definition *const procedure : program->procedures)
|
||||
{
|
||||
declare_procedure(procedure);
|
||||
}
|
||||
for (boot::procedure_definition *const procedure : program->procedures)
|
||||
{
|
||||
procedure->accept(this);
|
||||
}
|
||||
visit(static_cast<boot::unit *>(program));
|
||||
|
||||
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);
|
||||
@ -421,22 +403,37 @@ namespace elna::gcc
|
||||
cgraph_node::finalize_function(fndecl, true);
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::block *block)
|
||||
void generic_visitor::visit(boot::unit *unit)
|
||||
{
|
||||
for (boot::constant_definition *const constant : block->constants)
|
||||
for (boot::import_declaration *const declaration : unit->imports)
|
||||
{
|
||||
declaration->accept(this);
|
||||
}
|
||||
for (boot::constant_definition *const constant : unit->constants)
|
||||
{
|
||||
constant->accept(this);
|
||||
}
|
||||
for (boot::variable_declaration *const variable : block->variables)
|
||||
for (boot::type_definition *const type : unit->types)
|
||||
{
|
||||
type->accept(this);
|
||||
}
|
||||
for (boot::variable_declaration *const variable : unit->variables)
|
||||
{
|
||||
variable->accept(this);
|
||||
}
|
||||
visit_statements(block->body);
|
||||
for (boot::procedure_definition *const procedure : unit->procedures)
|
||||
{
|
||||
declare_procedure(procedure);
|
||||
}
|
||||
for (boot::procedure_definition *const procedure : unit->procedures)
|
||||
{
|
||||
procedure->accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::procedure_definition *definition)
|
||||
{
|
||||
if (definition->body == nullptr)
|
||||
if (!definition->body.has_value())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -452,7 +449,16 @@ namespace elna::gcc
|
||||
{
|
||||
this->symbols->enter(IDENTIFIER_POINTER(DECL_NAME(argument_chain)), argument_chain);
|
||||
}
|
||||
definition->body->accept(this);
|
||||
for (boot::constant_definition *const constant : definition->body.value().constants())
|
||||
{
|
||||
constant->accept(this);
|
||||
}
|
||||
for (boot::variable_declaration *const variable : definition->body.value().variables())
|
||||
{
|
||||
variable->accept(this);
|
||||
}
|
||||
visit_statements(definition->body.value().body());
|
||||
|
||||
tree mapping = leave_scope();
|
||||
|
||||
BLOCK_SUPERCONTEXT(BIND_EXPR_BLOCK(mapping)) = fndecl;
|
||||
@ -1285,32 +1291,8 @@ namespace elna::gcc
|
||||
append_statement(else_label_expr);
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::escape_statement *statement)
|
||||
void generic_visitor::visit(boot::import_declaration *)
|
||||
{
|
||||
for (const auto& [begin, end] : this->loops)
|
||||
{
|
||||
if (statement->label == IDENTIFIER_POINTER(DECL_NAME(begin)))
|
||||
{
|
||||
tree target_declaration{ NULL_TREE };
|
||||
|
||||
switch (statement->direction)
|
||||
{
|
||||
case boot::escape_direction::begin:
|
||||
target_declaration = begin;
|
||||
break;
|
||||
case boot::escape_direction::end:
|
||||
target_declaration = end;
|
||||
break;
|
||||
default:
|
||||
gcc_unreachable();
|
||||
}
|
||||
tree goto_expression = build1(GOTO_EXPR, void_type_node, target_declaration);
|
||||
TREE_USED(target_declaration) = 1;
|
||||
append_statement(goto_expression);
|
||||
return;
|
||||
}
|
||||
}
|
||||
error_at(get_location(&statement->position()), "Unknown loop labeled '%s'", statement->label.c_str());
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::while_statement *statement)
|
||||
@ -1324,8 +1306,6 @@ namespace elna::gcc
|
||||
tree branch_end_declaration = build_label_decl(loop_identifier.c_str(), UNKNOWN_LOCATION);
|
||||
tree branch_end_expression = build1_loc(UNKNOWN_LOCATION, LABEL_EXPR, void_type_node, branch_end_declaration);
|
||||
|
||||
this->loops.push_front({ prerequisite_label_decl, branch_end_declaration });
|
||||
|
||||
append_statement(prerequisite_label_expr);
|
||||
make_if_branch(statement->body(), goto_check);
|
||||
|
||||
|
@ -53,12 +53,6 @@ namespace elna::boot
|
||||
minus
|
||||
};
|
||||
|
||||
enum class escape_direction
|
||||
{
|
||||
begin,
|
||||
end
|
||||
};
|
||||
|
||||
class variable_declaration;
|
||||
class constant_definition;
|
||||
class procedure_definition;
|
||||
@ -67,12 +61,12 @@ namespace elna::boot
|
||||
class cast_expression;
|
||||
class assign_statement;
|
||||
class if_statement;
|
||||
class escape_statement;
|
||||
class import_declaration;
|
||||
class while_statement;
|
||||
class return_statement;
|
||||
class case_statement;
|
||||
class traits_expression;
|
||||
class block;
|
||||
class unit;
|
||||
class program;
|
||||
class binary_expression;
|
||||
class unary_expression;
|
||||
@ -107,12 +101,12 @@ namespace elna::boot
|
||||
virtual void visit(traits_expression *) = 0;
|
||||
virtual void visit(assign_statement *) = 0;
|
||||
virtual void visit(if_statement *) = 0;
|
||||
virtual void visit(escape_statement *) = 0;
|
||||
virtual void visit(import_declaration *) = 0;
|
||||
virtual void visit(while_statement *) = 0;
|
||||
virtual void visit(return_statement *) = 0;
|
||||
virtual void visit(defer_statement *) = 0;
|
||||
virtual void visit(case_statement *) = 0;
|
||||
virtual void visit(block *) = 0;
|
||||
virtual void visit(unit *) = 0;
|
||||
virtual void visit(program *) = 0;
|
||||
virtual void visit(binary_expression *) = 0;
|
||||
virtual void visit(unary_expression *) = 0;
|
||||
@ -358,6 +352,29 @@ namespace elna::boot
|
||||
procedure_type_expression *is_procedure() override;
|
||||
};
|
||||
|
||||
struct block
|
||||
{
|
||||
block(std::vector<constant_definition *>&& constants, std::vector<variable_declaration *>&& variables,
|
||||
std::vector<statement *>&& body);
|
||||
block(const block&) = delete;
|
||||
block(block&& that);
|
||||
|
||||
block& operator=(const block&) = delete;
|
||||
block& operator=(block&& that);
|
||||
|
||||
const std::vector<variable_declaration *>& variables();
|
||||
const std::vector<constant_definition *>& constants();
|
||||
const std::vector<statement *>& body();
|
||||
|
||||
virtual ~block();
|
||||
|
||||
private:
|
||||
std::vector<variable_declaration *> m_variables;
|
||||
std::vector<constant_definition *> m_constants;
|
||||
std::vector<statement *> m_body;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Procedure definition.
|
||||
*/
|
||||
@ -366,11 +383,13 @@ namespace elna::boot
|
||||
procedure_type_expression *m_heading;
|
||||
|
||||
public:
|
||||
block *const body;
|
||||
std::optional<block> body;
|
||||
std::vector<std::string> parameter_names;
|
||||
|
||||
procedure_definition(const struct position position, identifier_definition identifier,
|
||||
procedure_type_expression *heading, block *body = nullptr);
|
||||
procedure_type_expression *heading, block&& body);
|
||||
procedure_definition(const struct position position, identifier_definition identifier,
|
||||
procedure_type_expression *heading);
|
||||
void accept(parser_visitor *visitor) override;
|
||||
|
||||
procedure_type_expression& heading();
|
||||
@ -613,14 +632,15 @@ namespace elna::boot
|
||||
virtual ~if_statement() override;
|
||||
};
|
||||
|
||||
class escape_statement : public statement
|
||||
/**
|
||||
* Import statement.
|
||||
*/
|
||||
class import_declaration : public node
|
||||
{
|
||||
public:
|
||||
const escape_direction direction;
|
||||
const std::string label;
|
||||
const std::vector<std::string> segments;
|
||||
|
||||
escape_statement(const struct position position,
|
||||
escape_direction direction, const std::string& label);
|
||||
import_declaration(const struct position position, std::vector<std::string>&& segments);
|
||||
void accept(parser_visitor *visitor) override;
|
||||
};
|
||||
|
||||
@ -648,24 +668,25 @@ namespace elna::boot
|
||||
virtual ~while_statement() override;
|
||||
};
|
||||
|
||||
class block : public node
|
||||
class unit : public node
|
||||
{
|
||||
public:
|
||||
std::vector<variable_declaration *> variables;
|
||||
std::vector<import_declaration *> imports;
|
||||
std::vector<constant_definition *> constants;
|
||||
std::vector<statement *> body;
|
||||
std::vector<type_definition *> types;
|
||||
std::vector<variable_declaration *> variables;
|
||||
std::vector<procedure_definition *> procedures;
|
||||
|
||||
block(const struct position position);
|
||||
unit(const struct position position);
|
||||
virtual void accept(parser_visitor *visitor) override;
|
||||
|
||||
virtual ~block() override;
|
||||
virtual ~unit() override;
|
||||
};
|
||||
|
||||
class program : public block
|
||||
class program : public unit
|
||||
{
|
||||
public:
|
||||
std::vector<type_definition *> types;
|
||||
std::vector<procedure_definition *> procedures;
|
||||
std::vector<statement *> body;
|
||||
|
||||
program(const struct position position);
|
||||
void accept(parser_visitor *visitor) override;
|
||||
|
@ -77,13 +77,13 @@ namespace elna::boot
|
||||
void visit(procedure_definition *definition) override;
|
||||
void visit(assign_statement *statement) override;
|
||||
void visit(if_statement *statement) override;
|
||||
void visit(escape_statement *) override;
|
||||
void visit(import_declaration *) override;
|
||||
void visit(while_statement *statement) override;
|
||||
void visit(return_statement *statement) override;
|
||||
void visit(defer_statement *statement) override;
|
||||
void visit(case_statement *statement) override;
|
||||
void visit(procedure_call *call) override;
|
||||
void visit(block *block) override;
|
||||
void visit(unit *unit) override;
|
||||
void visit(cast_expression *expression) override;
|
||||
void visit(traits_expression *trait) override;
|
||||
void visit(binary_expression *expression) override;
|
||||
|
@ -45,7 +45,6 @@ namespace elna::gcc
|
||||
tree current_expression{ NULL_TREE };
|
||||
std::shared_ptr<symbol_table> symbols;
|
||||
std::unordered_map<std::string, tree> unresolved;
|
||||
std::forward_list<std::pair<tree, tree>> loops;
|
||||
|
||||
void declare_procedure(boot::procedure_definition *const definition);
|
||||
tree build_procedure_type(boot::procedure_type_expression& type);
|
||||
@ -100,10 +99,10 @@ namespace elna::gcc
|
||||
void visit(boot::array_access_expression *expression) override;
|
||||
void visit(boot::field_access_expression *expression) override;
|
||||
void visit(boot::dereference_expression *expression) override;
|
||||
void visit(boot::block *block) override;
|
||||
void visit(boot::unit *unit) override;
|
||||
void visit(boot::assign_statement *statement) override;
|
||||
void visit(boot::if_statement *statement) override;
|
||||
void visit(boot::escape_statement *statement) override;
|
||||
void visit(boot::import_declaration *) override;
|
||||
void visit(boot::while_statement *statement) override;
|
||||
void visit(boot::named_type_expression *type) override;
|
||||
void visit(boot::array_type_expression *type) override;
|
||||
|
142
source.elna
142
source.elna
@ -1,5 +1,7 @@
|
||||
program
|
||||
|
||||
import dummy
|
||||
|
||||
const
|
||||
SEEK_SET* := 0
|
||||
SEEK_CUR* := 1
|
||||
@ -32,7 +34,7 @@ type
|
||||
pipe,
|
||||
to,
|
||||
boolean,
|
||||
_nil,
|
||||
null,
|
||||
and,
|
||||
_or,
|
||||
not,
|
||||
@ -71,7 +73,9 @@ type
|
||||
exclamation,
|
||||
arrow,
|
||||
trait,
|
||||
_program
|
||||
_program,
|
||||
_module,
|
||||
_import
|
||||
)
|
||||
Position* = record
|
||||
line: Word;
|
||||
@ -121,50 +125,50 @@ type
|
||||
External procedures.
|
||||
*)
|
||||
|
||||
proc fopen(pathname: ^Char, mode: ^Char) -> ^FILE extern
|
||||
proc fclose(stream: ^FILE) -> Int extern
|
||||
proc fseek(stream: ^FILE, off: Int, whence: Int) -> Int extern
|
||||
proc rewind(stream: ^FILE) extern
|
||||
proc ftell(stream: ^FILE) -> Int extern
|
||||
proc fread(ptr: ^Byte, size: Word, nmemb: Word, stream: ^FILE) -> Word extern
|
||||
proc write(fd: Int, buf: ^Byte, Word: Int) -> Int extern
|
||||
proc fopen(pathname: ^Char, mode: ^Char) -> ^FILE; extern
|
||||
proc fclose(stream: ^FILE) -> Int; extern
|
||||
proc fseek(stream: ^FILE, off: Int, whence: Int) -> Int; extern
|
||||
proc rewind(stream: ^FILE); extern
|
||||
proc ftell(stream: ^FILE) -> Int; extern
|
||||
proc fread(ptr: ^Byte, size: Word, nmemb: Word, stream: ^FILE) -> Word; extern
|
||||
proc write(fd: Int, buf: ^Byte, Word: Int) -> Int; extern
|
||||
|
||||
proc malloc(size: Word) -> ^Byte extern
|
||||
proc free(ptr: ^Byte) extern
|
||||
proc calloc(nmemb: Word, size: Word) -> ^Byte extern
|
||||
proc realloc(ptr: ^Byte, size: Word) -> ^Byte extern
|
||||
proc malloc(size: Word) -> ^Byte; extern
|
||||
proc free(ptr: ^Byte); extern
|
||||
proc calloc(nmemb: Word, size: Word) -> ^Byte; extern
|
||||
proc realloc(ptr: ^Byte, size: Word) -> ^Byte; extern
|
||||
|
||||
proc memset(ptr: ^Char, c: Int, n: Int) -> ^Char extern
|
||||
proc memset(ptr: ^Char, c: Int, n: Int) -> ^Char; extern
|
||||
|
||||
proc strcmp(s1: ^Char, s2: ^Char) -> Int extern
|
||||
proc strncmp(s1: ^Char, s2: ^Char, n: Word) -> Int extern
|
||||
proc strncpy(dst: ^Char, src: ^Char, dsize: Word) -> ^Char extern
|
||||
proc strcpy(dst: ^Char, src: ^Char) -> ^Char extern
|
||||
proc strlen(ptr: ^Char) -> Word extern
|
||||
proc strcmp(s1: ^Char, s2: ^Char) -> Int; extern
|
||||
proc strncmp(s1: ^Char, s2: ^Char, n: Word) -> Int; extern
|
||||
proc strncpy(dst: ^Char, src: ^Char, dsize: Word) -> ^Char; extern
|
||||
proc strcpy(dst: ^Char, src: ^Char) -> ^Char; extern
|
||||
proc strlen(ptr: ^Char) -> Word; extern
|
||||
|
||||
proc perror(s: ^Char) extern
|
||||
proc exit(code: Int) -> ! extern
|
||||
proc perror(s: ^Char); extern
|
||||
proc exit(code: Int) -> !; extern
|
||||
|
||||
(*
|
||||
Standard procedures.
|
||||
*)
|
||||
|
||||
proc reallocarray(ptr: ^Byte, n: Word, size: Word) -> ^Byte
|
||||
proc reallocarray(ptr: ^Byte, n: Word, size: Word) -> ^Byte;
|
||||
begin
|
||||
return realloc(ptr, n * size)
|
||||
end
|
||||
|
||||
proc write_s(value: String)
|
||||
proc write_s(value: String);
|
||||
begin
|
||||
write(0, cast(value.ptr: ^Byte), cast(value.length: Int))
|
||||
end
|
||||
|
||||
proc write_z(value: ^Char)
|
||||
proc write_z(value: ^Char);
|
||||
begin
|
||||
write(0, cast(value: ^Byte), cast(strlen(value): Int))
|
||||
end
|
||||
|
||||
proc write_b(value: Bool)
|
||||
proc write_b(value: Bool);
|
||||
begin
|
||||
if value then
|
||||
write_s("true")
|
||||
@ -173,12 +177,12 @@ begin
|
||||
end
|
||||
end
|
||||
|
||||
proc write_c(value: Char)
|
||||
proc write_c(value: Char);
|
||||
begin
|
||||
write(0, cast(@value: ^Byte), 1)
|
||||
end
|
||||
|
||||
proc write_i(value: Int)
|
||||
proc write_i(value: Int);
|
||||
var
|
||||
digit: Int
|
||||
n: Word
|
||||
@ -202,42 +206,42 @@ begin
|
||||
end
|
||||
end
|
||||
|
||||
proc write_u(value: Word)
|
||||
proc write_u(value: Word);
|
||||
begin
|
||||
write_i(cast(value: Int))
|
||||
end
|
||||
|
||||
proc is_digit(c: Char) -> Bool
|
||||
proc is_digit(c: Char) -> Bool;
|
||||
begin
|
||||
return cast(c: Int) >= cast('0': Int) & cast(c: Int) <= cast('9': Int)
|
||||
end
|
||||
|
||||
proc is_alpha(c: Char) -> Bool
|
||||
proc is_alpha(c: Char) -> Bool;
|
||||
begin
|
||||
return cast(c: Int) >= cast('A': Int) & cast(c: Int) <= cast('z': Int)
|
||||
end
|
||||
|
||||
proc is_alnum(c: Char) -> Bool
|
||||
proc is_alnum(c: Char) -> Bool;
|
||||
begin
|
||||
return is_digit(c) or is_alpha(c)
|
||||
end
|
||||
|
||||
proc is_space(c: Char) -> Bool
|
||||
proc is_space(c: Char) -> Bool;
|
||||
begin
|
||||
return c = ' ' or c = '\n' or c = '\t'
|
||||
end
|
||||
|
||||
proc substring(string: String, start: Word, count: Word) -> String
|
||||
proc substring(string: String, start: Word, count: Word) -> String;
|
||||
begin
|
||||
return String(string.ptr + start, count)
|
||||
end
|
||||
|
||||
proc open_substring(string: String, start: Word) -> String
|
||||
proc open_substring(string: String, start: Word) -> String;
|
||||
begin
|
||||
return substring(string, start, string.length - start)
|
||||
end
|
||||
|
||||
proc string_dup(origin: String) -> String
|
||||
proc string_dup(origin: String) -> String;
|
||||
var
|
||||
copy: ^Char
|
||||
begin
|
||||
@ -247,7 +251,7 @@ begin
|
||||
return String(copy, origin.length)
|
||||
end
|
||||
|
||||
proc string_buffer_new() -> StringBuffer
|
||||
proc string_buffer_new() -> StringBuffer;
|
||||
var
|
||||
result: StringBuffer
|
||||
begin
|
||||
@ -258,7 +262,7 @@ begin
|
||||
return result
|
||||
end
|
||||
|
||||
proc string_buffer_push(buffer: ^StringBuffer, char: Char)
|
||||
proc string_buffer_push(buffer: ^StringBuffer, char: Char);
|
||||
begin
|
||||
if buffer^.size >= buffer^.capacity then
|
||||
buffer^.capacity := buffer^.capacity + 1024u;
|
||||
@ -268,12 +272,12 @@ begin
|
||||
buffer^.size := buffer^.size + 1u
|
||||
end
|
||||
|
||||
proc string_buffer_pop(buffer: ^StringBuffer, count: Word)
|
||||
proc string_buffer_pop(buffer: ^StringBuffer, count: Word);
|
||||
begin
|
||||
buffer^.size := buffer^.size - count
|
||||
end
|
||||
|
||||
proc string_buffer_clear(buffer: ^StringBuffer) -> String
|
||||
proc string_buffer_clear(buffer: ^StringBuffer) -> String;
|
||||
var
|
||||
result: String
|
||||
begin
|
||||
@ -286,7 +290,7 @@ end
|
||||
Source code stream procedures.
|
||||
*)
|
||||
|
||||
proc read_source(filename: ^Char) -> ^SourceFile
|
||||
proc read_source(filename: ^Char) -> ^SourceFile;
|
||||
var
|
||||
result: ^SourceFile
|
||||
file_handle: ^FILE
|
||||
@ -302,7 +306,7 @@ begin
|
||||
return result
|
||||
end
|
||||
|
||||
proc source_file_empty(source_input: ^Byte) -> Bool
|
||||
proc source_file_empty(source_input: ^Byte) -> Bool;
|
||||
var
|
||||
source_file: ^SourceFile
|
||||
begin
|
||||
@ -316,7 +320,7 @@ begin
|
||||
return source_file^.size = 0u
|
||||
end
|
||||
|
||||
proc source_file_head(source_input: ^Byte) -> Char
|
||||
proc source_file_head(source_input: ^Byte) -> Char;
|
||||
var
|
||||
source_file: ^SourceFile
|
||||
begin
|
||||
@ -325,7 +329,7 @@ begin
|
||||
return source_file^.buffer[source_file^.index]
|
||||
end
|
||||
|
||||
proc source_file_advance(source_input: ^Byte)
|
||||
proc source_file_advance(source_input: ^Byte);
|
||||
var
|
||||
source_file: ^SourceFile
|
||||
begin
|
||||
@ -334,29 +338,29 @@ begin
|
||||
source_file^.index := source_file^.index + 1u
|
||||
end
|
||||
|
||||
proc source_code_empty(source_code: ^SourceCode) -> Bool
|
||||
proc source_code_empty(source_code: ^SourceCode) -> Bool;
|
||||
begin
|
||||
return source_code^.empty(source_code^.input)
|
||||
end
|
||||
|
||||
proc source_code_head(source_code: SourceCode) -> Char
|
||||
proc source_code_head(source_code: SourceCode) -> Char;
|
||||
begin
|
||||
return source_code.head(source_code.input)
|
||||
end
|
||||
|
||||
proc source_code_advance(source_code: ^SourceCode)
|
||||
proc source_code_advance(source_code: ^SourceCode);
|
||||
begin
|
||||
source_code^.advance(source_code^.input);
|
||||
source_code^.position.column := source_code^.position.column
|
||||
end
|
||||
|
||||
proc source_code_break(source_code: ^SourceCode)
|
||||
proc source_code_break(source_code: ^SourceCode);
|
||||
begin
|
||||
source_code^.position.line := source_code^.position.line + 1u;
|
||||
source_code^.position.column := 0u
|
||||
end
|
||||
|
||||
proc source_code_expect(source_code: ^SourceCode, expected: Char) -> Bool
|
||||
proc source_code_expect(source_code: ^SourceCode, expected: Char) -> Bool;
|
||||
begin
|
||||
return ~source_code_empty(source_code) & source_code_head(source_code^) = expected
|
||||
end
|
||||
@ -365,7 +369,7 @@ end
|
||||
Token procedures.
|
||||
*)
|
||||
|
||||
proc escape_char(escape: Char, result: ^Char) -> Bool
|
||||
proc escape_char(escape: Char, result: ^Char) -> Bool;
|
||||
var
|
||||
successful: Bool
|
||||
begin
|
||||
@ -411,15 +415,15 @@ begin
|
||||
return successful
|
||||
end
|
||||
|
||||
proc skip_spaces(source_code: ^SourceCode)
|
||||
proc skip_spaces(source_code: ^SourceCode);
|
||||
var
|
||||
current: Char
|
||||
begin
|
||||
while ~source_code_empty(source_code), loop do
|
||||
while ~source_code_empty(source_code) do
|
||||
current := source_code_head(source_code^);
|
||||
|
||||
if ~is_space(current) then
|
||||
break loop
|
||||
return
|
||||
elsif current = '\n' then
|
||||
source_code_break(source_code)
|
||||
end;
|
||||
@ -427,12 +431,12 @@ begin
|
||||
end
|
||||
end
|
||||
|
||||
proc is_ident(char: Char) -> Bool
|
||||
proc is_ident(char: Char) -> Bool;
|
||||
begin
|
||||
return is_alnum(char) or char = '_'
|
||||
end
|
||||
|
||||
proc lex_identifier(source_code: ^SourceCode, token_content: ^StringBuffer)
|
||||
proc lex_identifier(source_code: ^SourceCode, token_content: ^StringBuffer);
|
||||
var
|
||||
content_length: Word
|
||||
begin
|
||||
@ -442,7 +446,7 @@ begin
|
||||
end
|
||||
end
|
||||
|
||||
proc lex_comment(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool
|
||||
proc lex_comment(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool;
|
||||
var
|
||||
trailing: Word
|
||||
begin
|
||||
@ -465,7 +469,7 @@ begin
|
||||
return trailing = 2u
|
||||
end
|
||||
|
||||
proc lex_character(source_code: ^SourceCode, token_content: ^Char) -> Bool
|
||||
proc lex_character(source_code: ^SourceCode, token_content: ^Char) -> Bool;
|
||||
var
|
||||
successful: Bool
|
||||
begin
|
||||
@ -487,7 +491,7 @@ begin
|
||||
return successful
|
||||
end
|
||||
|
||||
proc lex_string(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool
|
||||
proc lex_string(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool;
|
||||
var
|
||||
token_end, constructed_string: ^Char
|
||||
token_length: Word
|
||||
@ -512,7 +516,7 @@ begin
|
||||
return is_valid
|
||||
end
|
||||
|
||||
proc lex_number(source_code: ^SourceCode, token_content: ^Int)
|
||||
proc lex_number(source_code: ^SourceCode, token_content: ^Int);
|
||||
begin
|
||||
token_content^ := 0;
|
||||
|
||||
@ -523,7 +527,7 @@ begin
|
||||
end
|
||||
end
|
||||
|
||||
proc print_tokens(tokens: ^Token, tokens_size: Word)
|
||||
proc print_tokens(tokens: ^Token, tokens_size: Word);
|
||||
var
|
||||
current_token: ^Token
|
||||
i: Word
|
||||
@ -575,7 +579,7 @@ begin
|
||||
write_s("BOOLEAN<");
|
||||
write_b(current_token^.value.boolean_value);
|
||||
write_c('>')
|
||||
| TokenKind._nil:
|
||||
| TokenKind.null:
|
||||
write_s("NIL")
|
||||
| TokenKind.and:
|
||||
write_s("&")
|
||||
@ -666,6 +670,10 @@ begin
|
||||
write_s("->")
|
||||
| TokenKind._program:
|
||||
write_s("PROGRAM")
|
||||
| TokenKind._module:
|
||||
write_s("MODULE")
|
||||
| TokenKind._import:
|
||||
write_s("IMPORT")
|
||||
else
|
||||
write_s("UNKNOWN<");
|
||||
write_i(cast(current_token^.kind: Int));
|
||||
@ -678,7 +686,7 @@ begin
|
||||
write_c('\n')
|
||||
end
|
||||
|
||||
proc categorize_identifier(token_content: String) -> Token
|
||||
proc categorize_identifier(token_content: String) -> Token;
|
||||
var
|
||||
current_token: Token
|
||||
begin
|
||||
@ -723,7 +731,7 @@ begin
|
||||
current_token.kind := TokenKind.boolean;
|
||||
current_token.value.boolean_value := false
|
||||
elsif token_content = "nil" then
|
||||
current_token.kind := TokenKind._nil
|
||||
current_token.kind := TokenKind.null
|
||||
elsif token_content = "or" then
|
||||
current_token.kind := TokenKind._or
|
||||
elsif token_content = "return" then
|
||||
@ -734,6 +742,10 @@ begin
|
||||
current_token.kind := TokenKind._defer
|
||||
elsif token_content = "program" then
|
||||
current_token.kind := TokenKind._program
|
||||
elsif token_content = "module" then
|
||||
current_token.kind := TokenKind._module
|
||||
elsif token_content = "import" then
|
||||
current_token.kind := TokenKind._import
|
||||
else
|
||||
current_token.kind := TokenKind.identifier;
|
||||
current_token.value.string := string_dup(token_content)
|
||||
@ -742,7 +754,7 @@ begin
|
||||
return current_token
|
||||
end
|
||||
|
||||
proc tokenize(source_code: SourceCode, tokens_size: ^Word) -> ^Token
|
||||
proc tokenize(source_code: SourceCode, tokens_size: ^Word) -> ^Token;
|
||||
var
|
||||
tokens, current_token: ^Token
|
||||
first_char: Char
|
||||
@ -938,7 +950,7 @@ end
|
||||
Command line handling.
|
||||
*)
|
||||
|
||||
proc parse_command_line*(argc: Int, argv: ^^Char) -> ^CommandLine
|
||||
proc parse_command_line*(argc: Int, argv: ^^Char) -> ^CommandLine;
|
||||
var
|
||||
parameter: ^^Char
|
||||
i: Int
|
||||
@ -986,7 +998,7 @@ end
|
||||
Compilation entry.
|
||||
*)
|
||||
|
||||
proc process(argc: Int, argv: ^^Char) -> Int
|
||||
proc process(argc: Int, argv: ^^Char) -> Int;
|
||||
var
|
||||
tokens: ^Token
|
||||
tokens_size: Word
|
||||
|
Loading…
x
Reference in New Issue
Block a user