From 573d812f1c757136a4f96bdfed46473de2af7668 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Fri, 16 May 2025 23:16:19 +0200 Subject: [PATCH] Parse import declarations --- boot/ast.cc | 102 ++++++++++++++++++----- boot/lexer.ll | 7 +- boot/parser.yy | 70 +++++++++++----- boot/semantic.cc | 71 ++++++++-------- gcc/elna-generic.cc | 88 ++++++++------------ include/elna/boot/ast.h | 71 ++++++++++------ include/elna/boot/semantic.h | 4 +- include/elna/gcc/elna-generic.h | 5 +- source.elna | 142 +++++++++++++++++--------------- 9 files changed, 333 insertions(+), 227 deletions(-) diff --git a/boot/ast.cc b/boot/ast.cc index 5320522..efaaad1 100644 --- a/boot/ast.cc +++ b/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&& constants, std::vector&& variables, + std::vector&& 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& block::variables() + { + return m_variables; + } + + const std::vector& block::constants() + { + return m_constants; + } + + const std::vector& 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&& segments) + : node(position), segments(std::move(segments)) { } - void escape_statement::accept(parser_visitor *visitor) + void import_declaration::accept(parser_visitor *visitor) { visitor->visit(this); } diff --git a/boot/lexer.ll b/boot/lexer.ll index 4e18376..5ac68ff 100644 --- a/boot/lexer.ll +++ b/boot/lexer.ll @@ -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); } diff --git a/boot/parser.yy b/boot/parser.yy index 4f64e51..e82a421 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -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 > procedure_definitions procedure_part; %type type_definition; %type > type_definitions type_part; -%type block; +%type > block; %type field_declaration formal_parameter; %type >> optional_fields required_fields formal_parameters; @@ -163,28 +164,38 @@ along with GCC; see the file COPYING3. If not see %type cast_expression; %type identifier_definition; %type > identifier_definitions; -%type > identifiers; +%type > identifiers import_declaration; +%type > 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(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); diff --git a/boot/semantic.cc b/boot/semantic.cc index f8dc1b4..bf086dd 100644 --- a/boot/semantic.cc +++ b/boot/semantic.cc @@ -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(program)); - if (!this->unresolved.insert({ type_identifier, std::make_shared(type_identifier) }).second - || this->symbols->contains(type_identifier)) - { - add_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(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(type_identifier) }).second + || this->symbols->contains(type_identifier)) + { + add_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(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); } } diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 0865ca1..761344d 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -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(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); diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index dd40164..4de7bbd 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -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&& constants, std::vector&& variables, + std::vector&& body); + block(const block&) = delete; + block(block&& that); + + block& operator=(const block&) = delete; + block& operator=(block&& that); + + const std::vector& variables(); + const std::vector& constants(); + const std::vector& body(); + + virtual ~block(); + + private: + std::vector m_variables; + std::vector m_constants; + std::vector m_body; + + }; + /** * Procedure definition. */ @@ -366,11 +383,13 @@ namespace elna::boot procedure_type_expression *m_heading; public: - block *const body; + std::optional body; std::vector 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 segments; - escape_statement(const struct position position, - escape_direction direction, const std::string& label); + import_declaration(const struct position position, std::vector&& 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 variables; + std::vector imports; std::vector constants; - std::vector body; + std::vector types; + std::vector variables; + std::vector 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 types; - std::vector procedures; + std::vector body; program(const struct position position); void accept(parser_visitor *visitor) override; diff --git a/include/elna/boot/semantic.h b/include/elna/boot/semantic.h index f398f65..5594d76 100644 --- a/include/elna/boot/semantic.h +++ b/include/elna/boot/semantic.h @@ -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; diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index ad2a141..fe241ff 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -45,7 +45,6 @@ namespace elna::gcc tree current_expression{ NULL_TREE }; std::shared_ptr symbols; std::unordered_map unresolved; - std::forward_list> 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; diff --git a/source.elna b/source.elna index 27c74ed..4fb3d65 100644 --- a/source.elna +++ b/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