Parse import declarations

This commit is contained in:
Eugen Wissner 2025-05-16 23:16:19 +02:00
parent 981059e745
commit 573d812f1c
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
9 changed files with 333 additions and 227 deletions

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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