diff options
| author | Eugen Wissner <belka@caraus.de> | 2026-07-03 08:53:03 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2026-07-03 08:53:03 +0200 |
| commit | 4ad6052aa2816f8296e62569272e99fc0d2fd3c1 (patch) | |
| tree | e1002f3fc1d51929b6f7b77f4769eb84be4e9e82 | |
| parent | 453332311ac2d569093f9ef62d41d13b0ce024c8 (diff) | |
| download | elna-4ad6052aa2816f8296e62569272e99fc0d2fd3c1.tar.gz | |
Merge variable_expression and named_type_expression
| -rw-r--r-- | frontend/ast.cc | 86 | ||||
| -rw-r--r-- | frontend/lexer.ll | 6 | ||||
| -rw-r--r-- | frontend/parser.yy | 97 | ||||
| -rw-r--r-- | frontend/semantic.cc | 88 | ||||
| -rw-r--r-- | gcc/README.md | 2 | ||||
| -rw-r--r-- | gcc/elna-generic.cc | 6 | ||||
| -rw-r--r-- | include/elna/frontend/ast.h | 49 | ||||
| -rw-r--r-- | include/elna/frontend/semantic.h | 6 | ||||
| -rw-r--r-- | include/elna/gcc/elna-generic.h | 2 | ||||
| -rw-r--r-- | rakelib/gcc.rake | 6 | ||||
| -rw-r--r-- | source/cctype.elna | 23 | ||||
| -rw-r--r-- | source/command_line_interface.elna | 18 | ||||
| -rw-r--r-- | source/common.elna | 40 | ||||
| -rw-r--r-- | source/cstdio.elna | 49 | ||||
| -rw-r--r-- | source/cstdlib.elna | 22 | ||||
| -rw-r--r-- | source/cstring.elna | 27 | ||||
| -rw-r--r-- | source/lexer.elna | 139 | ||||
| -rw-r--r-- | source/main.elna | 209 |
18 files changed, 475 insertions, 400 deletions
diff --git a/frontend/ast.cc b/frontend/ast.cc index e067937..9a1f96b 100644 --- a/frontend/ast.cc +++ b/frontend/ast.cc @@ -24,7 +24,7 @@ namespace elna::frontend __builtin_unreachable(); } - void empty_visitor::visit(named_type_expression *) + void empty_visitor::visit(type_expression *) { not_implemented(); } @@ -149,7 +149,7 @@ namespace elna::frontend not_implemented(); } - void empty_visitor::visit(variable_expression *) + void empty_visitor::visit(named_expression *) { not_implemented(); } @@ -253,12 +253,7 @@ namespace elna::frontend return nullptr; } - type_expression::type_expression(const struct position position) - : node(position) - { - } - - named_type_expression *type_expression::is_named() + named_expression *type_expression::is_named() { return nullptr; } @@ -293,24 +288,46 @@ namespace elna::frontend return nullptr; } - named_type_expression::named_type_expression(const struct position position, const std::string& name) - : type_expression(position), name(name) + void type_expression::accept(parser_visitor *visitor) { + if (named_expression *node = is_named()) + { + return visitor->visit(node); + } + else if (array_type_expression *node = is_array()) + { + return visitor->visit(node); + } + else if (pointer_type_expression *node = is_pointer()) + { + return visitor->visit(node); + } + else if (record_type_expression *node = is_record()) + { + return visitor->visit(node); + } + else if (union_type_expression *node = is_union()) + { + return visitor->visit(node); + } + else if (procedure_type_expression *node = is_procedure()) + { + return visitor->visit(node); + } + else if (enumeration_type_expression *node = is_enumeration()) + { + return visitor->visit(node); + } + __builtin_unreachable(); } - void named_type_expression::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - named_type_expression *named_type_expression::is_named() + type_expression::~type_expression() { - return this; } array_type_expression::array_type_expression(const struct position position, type_expression *base, const std::uint32_t size) - : type_expression(position), m_base(base), size(size) + : node(position), m_base(base), size(size) { } @@ -336,7 +353,7 @@ namespace elna::frontend pointer_type_expression::pointer_type_expression(const struct position position, type_expression *base) - : type_expression(position), m_base(base) + : node(position), m_base(base) { } @@ -362,7 +379,7 @@ namespace elna::frontend record_type_expression::record_type_expression(const struct position position, std::vector<field_declaration>&& fields) - : type_expression(position), fields(std::move(fields)) + : node(position), fields(std::move(fields)) { } @@ -386,7 +403,7 @@ namespace elna::frontend union_type_expression::union_type_expression(const struct position position, std::vector<field_declaration>&& fields) - : type_expression(position), fields(std::move(fields)) + : node(position), fields(std::move(fields)) { } @@ -464,7 +481,7 @@ namespace elna::frontend } procedure_type_expression::procedure_type_expression(const struct position position, return_t return_type) - : type_expression(position), return_type(return_type) + : node(position), return_type(return_type) { } @@ -491,7 +508,7 @@ namespace elna::frontend } enumeration_type_expression::enumeration_type_expression(const struct position position, std::vector<std::string>&& members) - : type_expression(position), members(members) + : node(position), members(members) { } @@ -559,6 +576,11 @@ namespace elna::frontend { } + block::block(std::vector<constant_declaration*>&& constants, std::vector<variable_declaration *>&& variables) + : m_variables(std::move(variables)), m_constants(std::move(constants)) + { + } + 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)) @@ -657,10 +679,6 @@ namespace elna::frontend } } - literal_expression::literal_expression() - { - } - literal_expression *literal_expression::is_literal() { return this; @@ -684,10 +702,6 @@ namespace elna::frontend } } - designator_expression::designator_expression() - { - } - designator_expression::~designator_expression() { } @@ -699,7 +713,7 @@ namespace elna::frontend void designator_expression::accept(parser_visitor *visitor) { - if (variable_expression *node = is_variable()) + if (named_expression *node = is_named()) { return visitor->visit(node); } @@ -718,17 +732,17 @@ namespace elna::frontend __builtin_unreachable(); } - variable_expression::variable_expression(const struct position position, const std::string& name) + named_expression::named_expression(const struct position position, const std::string& name) : node(position), name(name) { } - void variable_expression::accept(parser_visitor *visitor) + void named_expression::accept(parser_visitor *visitor) { visitor->visit(this); } - variable_expression *variable_expression::is_variable() + named_expression *named_expression::is_named() { return this; } @@ -1039,7 +1053,7 @@ namespace elna::frontend visitor->visit(this); } - variable_expression *designator_expression::is_variable() + named_expression *designator_expression::is_named() { return nullptr; } diff --git a/frontend/lexer.ll b/frontend/lexer.ll index f14497b..7c18b32 100644 --- a/frontend/lexer.ll +++ b/frontend/lexer.ll @@ -130,12 +130,6 @@ or { return { return yy::parser::make_RETURN(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); } diff --git a/frontend/parser.yy b/frontend/parser.yy index bace8d7..5e3837b 100644 --- a/frontend/parser.yy +++ b/frontend/parser.yy @@ -102,8 +102,6 @@ along with GCC; see the file COPYING3. If not see ELSE "else" ELSIF "elsif" RETURN "return" - PROGRAM "program" - MODULE "module" IMPORT "import" BEGIN_BLOCK "begin" END_BLOCK "end" @@ -142,11 +140,12 @@ along with GCC; see the file COPYING3. If not see %type <elna::frontend::procedure_call*> call_expression; %type <elna::frontend::return_statement *> return_statement; %type <elna::frontend::statement *> statement; -%type <std::vector<elna::frontend::statement *>> required_statements optional_statements statement_part; +%type <std::vector<elna::frontend::statement *>> required_statements optional_statements; +%type <std::unique_ptr<std::vector<elna::frontend::statement *>>> statement_part; %type <elna::frontend::procedure_declaration *> procedure_declaration; %type <std::pair<std::vector<std::string>, elna::frontend::procedure_type_expression *>> procedure_heading; %type <elna::frontend::procedure_type_expression::return_t> return_declaration; -%type <std::vector<elna::frontend::procedure_declaration *>> procedure_declarations procedure_part; +%type <std::vector<elna::frontend::procedure_declaration *>> procedure_part; %type <elna::frontend::type_declaration *> type_declaration; %type <std::vector<elna::frontend::type_declaration *>> type_declarations type_part; %type <std::unique_ptr<elna::frontend::block>> block; @@ -162,43 +161,47 @@ along with GCC; see the file COPYING3. If not see %type <std::vector<elna::frontend::import_declaration *>> import_declarations import_part; %% program: - "program" ";" import_part constant_part type_part variable_part procedure_part statement_part "end" "." + import_part constant_part type_part variable_part procedure_part statement_part "end" "." { - auto tree = new frontend::program(frontend::make_position(@1)); - - std::swap(tree->imports, $3); - std::swap(tree->constants, $4); - std::swap(tree->types , $5); - std::swap(tree->variables, $6); - std::swap(tree->procedures, $7); - std::swap(tree->body, $8); - - driver.tree.reset(tree); - } - | "module" ";" import_part constant_part type_part variable_part procedure_part "end" "." - { - auto tree = new frontend::unit(frontend::make_position(@1)); - - std::swap(tree->imports, $3); - std::swap(tree->constants, $4); - std::swap(tree->types , $5); - std::swap(tree->variables, $6); - std::swap(tree->procedures, $7); + if ($6) + { + frontend::program *tree = new frontend::program(frontend::make_position(@1)); + std::swap(tree->body, *$6.release()); - driver.tree.reset(tree); + driver.tree.reset(tree); + } + else + { + driver.tree.reset(new frontend::unit(frontend::make_position(@1))); + } + std::swap(driver.tree->imports, $1); + std::swap(driver.tree->constants, $2); + std::swap(driver.tree->types , $3); + std::swap(driver.tree->variables, $4); + std::swap(driver.tree->procedures, $5); } block: constant_part variable_part statement_part "end" { - $$ = std::make_unique<frontend::block>(std::move($1), std::move($2), std::move($3)); + if ($3) + { + $$ = std::make_unique<frontend::block>(std::move($1), std::move($2), std::move(*$3.release())); + } + else + { + $$ = std::make_unique<frontend::block>(std::move($1), std::move($2)); + } } statement_part: /* no statements */ {} - | "begin" required_statements { std::swap($$, $2); } - | return_statement { $$.push_back($1); } + | "begin" required_statements { $$ = std::make_unique<std::vector<frontend::statement *>>(std::move($2));; } + | return_statement + { + $$ = std::make_unique<std::vector<frontend::statement *>>(std::vector<frontend::statement *>{ $1 }); + } | "begin" required_statements ";" return_statement { - std::swap($$, $2); - $$.push_back($4); + $$ = std::make_unique<std::vector<frontend::statement *>>(std::move($2)); + $$->push_back($4); } identifier_definition: IDENTIFIER "*" { $$ = frontend::identifier_definition{ $1, true }; } @@ -224,26 +227,24 @@ procedure_heading: formal_parameter_list return_declaration } } procedure_declaration: - "proc" identifier_definition procedure_heading ";" block ";" + "proc" identifier_definition procedure_heading block { - $$ = new frontend::procedure_declaration(frontend::make_position(@1), std::move($2), $3.second, std::move(*$5)); + $$ = new frontend::procedure_declaration(frontend::make_position(@1), std::move($2), $3.second, + std::move(*$4)); std::swap($3.first, $$->parameter_names); } - | "proc" identifier_definition procedure_heading ";" "extern" ";" + | "proc" identifier_definition procedure_heading "extern" { $$ = new frontend::procedure_declaration(frontend::make_position(@1), std::move($2), $3.second); std::swap($3.first, $$->parameter_names); } -procedure_declarations: - procedure_declaration procedure_declarations +procedure_part: + /* no procedure declarations */ {} + | procedure_declaration procedure_part { std::swap($$, $2); $$.emplace($$.cbegin(), std::move($1)); } - | procedure_declaration { $$.emplace_back(std::move($1)); } -procedure_part: - /* no procedure definitions */ {} - | procedure_declarations { std::swap($$, $1); } call_expression: designator_expression actual_parameter_list { $$ = new frontend::procedure_call(frontend::make_position(@1), $1); @@ -401,7 +402,7 @@ designator_expression: | simple_expression "^" { $$ = new frontend::dereference_expression(frontend::make_position(@1), $1); } | IDENTIFIER - { $$ = new frontend::variable_expression(frontend::make_position(@1), $1); } + { $$ = new frontend::named_expression(frontend::make_position(@1), $1); } statement: designator_expression ":=" expression { $$ = new frontend::assign_statement(frontend::make_position(@1), $1, $3); } @@ -487,7 +488,7 @@ type_expression: } | IDENTIFIER { - $$ = new frontend::named_type_expression(frontend::make_position(@1), $1); + $$ = new frontend::named_expression(frontend::make_position(@1), $1); } identifiers: IDENTIFIER "," identifiers @@ -497,18 +498,18 @@ identifiers: } | IDENTIFIER { $$.emplace_back(std::move($1)); } variable_declaration: - identifier_definitions ":" type_expression ";" + identifier_definitions ":" type_expression { std::shared_ptr<frontend::type_expression> shared_type{ $3 }; $$ = new frontend::variable_declaration( frontend::make_position(@2), std::move($1), shared_type); } - | identifier_definitions ":" type_expression ":=" "extern" ";" + | identifier_definitions ":" type_expression ":=" "extern" { std::shared_ptr<frontend::type_expression> shared_type{ $3 }; $$ = new frontend::variable_declaration( frontend::make_position(@2), std::move($1), shared_type, std::monostate{}); } - | identifier_definitions ":" type_expression ":=" expression ";" + | identifier_definitions ":" type_expression ":=" expression { std::shared_ptr<frontend::type_expression> shared_type{ $3 }; $$ = new frontend::variable_declaration( frontend::make_position(@2), std::move($1), shared_type, $5); @@ -523,7 +524,7 @@ variable_declarations: variable_part: /* no variable declarations */ {} | "var" variable_declarations { std::swap($$, $2); } -constant_declaration: identifier_definition ":=" expression ";" +constant_declaration: identifier_definition ":=" expression { $$ = new frontend::constant_declaration(frontend::make_position(@1), std::move($1), $3); } @@ -556,8 +557,8 @@ import_declarations: } import_part: /* no import declarations */ {} - | "import" import_declarations ";" { std::swap($$, $2); } -type_declaration: identifier_definition "=" type_expression ";" + | "import" import_declarations { std::swap($$, $2); } +type_declaration: identifier_definition "=" type_expression { $$ = new frontend::type_declaration(frontend::make_position(@1), std::move($1), $3); } diff --git a/frontend/semantic.cc b/frontend/semantic.cc index 36c75b8..ee18492 100644 --- a/frontend/semantic.cc +++ b/frontend/semantic.cc @@ -223,10 +223,20 @@ namespace elna::frontend { visit(static_cast<unit *>(program)); + this->bag.enter(); + auto variable_type = this->bag.lookup("Int")->is_type()->symbol; + this->bag.enter("count", std::make_shared<variable_info>(variable_type, false)); + + variable_type = this->bag.lookup("Char")->is_type()->symbol; + variable_type = type(std::make_shared<pointer_type>(variable_type)); + variable_type = type(std::make_shared<pointer_type>(variable_type)); + this->bag.enter("parameters", std::make_shared<variable_info>(variable_type, false)); + for (statement *const statement : program->body) { statement->accept(this); } + this->bag.leave(); } void name_analysis_visitor::visit(type_declaration *definition) @@ -239,23 +249,8 @@ namespace elna::frontend this->bag.enter(definition->identifier.name, info); } - void name_analysis_visitor::visit(named_type_expression *type_expression) + void name_analysis_visitor::visit(type_expression *) { - auto unresolved_alias = this->bag.declared(type_expression->name); - - if (unresolved_alias != nullptr) - { - this->current_type = type(unresolved_alias); - } - else if (auto from_symbol_table = this->bag.lookup(type_expression->name)) - { - this->current_type = from_symbol_table->is_type()->symbol; - } - else - { - add_error<undeclared_error>(type_expression->name, this->input_file, type_expression->position()); - this->current_type = type(); - } } void name_analysis_visitor::visit(pointer_type_expression *type_expression) @@ -267,7 +262,9 @@ namespace elna::frontend void name_analysis_visitor::visit(array_type_expression *type_expression) { type_expression->base().accept(this); - this->current_type = type(std::make_shared<array_type>(this->current_type, type_expression->size)); + auto result_type{ std::make_shared<array_type>(this->current_type, type_expression->size) }; + + this->current_type = type(result_type); } std::vector<type_field> name_analysis_visitor::build_composite_type(const std::vector<field_declaration>& fields) @@ -324,20 +321,27 @@ namespace elna::frontend this->current_type = type(result_type); } + std::shared_ptr<variable_info> name_analysis_visitor::register_variable(const std::string& name, + const bool is_extern, const struct position position) + { + auto variable_symbol = std::make_shared<variable_info>(this->current_type, is_extern); + + if (!this->bag.enter(name, variable_symbol)) + { + add_error<already_declared_error>(name, this->input_file, position); + } + return variable_symbol; + } + void name_analysis_visitor::visit(variable_declaration *declaration) { declaration->variable_type().accept(this); for (const auto& variable_identifier : declaration->identifiers) { - auto variable_symbol = std::make_shared<variable_info>(this->current_type, declaration->is_extern); - + auto variable_symbol = register_variable(variable_identifier.name, declaration->is_extern, + declaration->position()); variable_symbol->exported = variable_identifier.exported; - if (!this->bag.enter(variable_identifier.name, variable_symbol)) - { - add_error<already_declared_error>(variable_identifier.name, this->input_file, - declaration->position()); - } } } @@ -358,7 +362,19 @@ namespace elna::frontend if (definition->body.has_value()) { info = std::make_shared<procedure_info>(heading, definition->parameter_names, this->bag.enter()); + auto name_iterator = std::cbegin(definition->parameter_names); + auto type_iterator = std::cbegin(heading.parameters); + while (name_iterator != std::cend(definition->parameter_names) + && type_iterator != std::cend(heading.parameters)) + { + this->current_type = *type_iterator; + auto variable_symbol = register_variable(*name_iterator, false, definition->heading().position()); + variable_symbol->exported = false; + + ++name_iterator; + ++type_iterator; + } for (constant_declaration *const constant : definition->body.value().constants()) { constant->accept(this); @@ -489,6 +505,10 @@ namespace elna::frontend { variable->accept(this); } + for (constant_declaration *const constant : unit->constants) + { + constant->accept(this); + } for (procedure_declaration *const procedure : unit->procedures) { procedure->accept(this); @@ -522,8 +542,26 @@ namespace elna::frontend expression->operand().accept(this); } - void name_analysis_visitor::visit(variable_expression *) + void name_analysis_visitor::visit(named_expression *type_expression) { + auto unresolved_alias = this->bag.declared(type_expression->name); + + if (unresolved_alias != nullptr) + { + this->current_type = type(unresolved_alias); + } + else if (auto from_symbol_table = this->bag.lookup(type_expression->name)) + { + if (auto type_symbol = from_symbol_table->is_type()) + { + this->current_type = type_symbol->symbol; + } + } + else + { + add_error<undeclared_error>(type_expression->name, this->input_file, type_expression->position()); + this->current_type = type(); + } } void name_analysis_visitor::visit(array_access_expression *expression) diff --git a/gcc/README.md b/gcc/README.md index 99d03c3..14219d8 100644 --- a/gcc/README.md +++ b/gcc/README.md @@ -14,7 +14,7 @@ in the `boot/` directory. ## Build -The frontend requires GCC 15.2.0 (not tested with other versions). +The frontend requires GCC 15.3.0 (not tested with other versions). Download the GCC source. Copy the contents of this repository into `gcc/elna` inside GCC. Finally build GCC enabling the frontend with diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index b37b111..a5aa5f5 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -169,7 +169,7 @@ namespace elna::gcc { location_t call_location = get_location(&call->position()); - if (frontend::variable_expression *named_call = call->callable().is_variable()) + if (frontend::named_expression *named_call = call->callable().is_named()) { if (named_call->name == "assert") { @@ -784,7 +784,7 @@ namespace elna::gcc } } - void generic_visitor::visit(frontend::variable_expression *expression) + void generic_visitor::visit(frontend::named_expression *expression) { auto symbol = this->symbols->lookup(expression->name); @@ -1023,7 +1023,7 @@ namespace elna::gcc if (TREE_CODE(lvalue) == CONST_DECL) { error_at(statement_location, "Cannot modify constant '%s'", - statement->lvalue().is_variable()->name.c_str()); + statement->lvalue().is_named()->name.c_str()); } else if (TYPE_READONLY(TREE_TYPE(lvalue))) { diff --git a/include/elna/frontend/ast.h b/include/elna/frontend/ast.h index bbb8a36..0b5f3d7 100644 --- a/include/elna/frontend/ast.h +++ b/include/elna/frontend/ast.h @@ -71,14 +71,14 @@ namespace elna::frontend class program; class binary_expression; class unary_expression; - class named_type_expression; + class type_expression; class array_type_expression; class pointer_type_expression; class record_type_expression; class union_type_expression; class procedure_type_expression; class enumeration_type_expression; - class variable_expression; + class named_expression; class array_access_expression; class field_access_expression; class dereference_expression; @@ -111,14 +111,14 @@ namespace elna::frontend virtual void visit(program *) = 0; virtual void visit(binary_expression *) = 0; virtual void visit(unary_expression *) = 0; - virtual void visit(named_type_expression *) = 0; + virtual void visit(type_expression *) = 0; virtual void visit(array_type_expression *) = 0; virtual void visit(pointer_type_expression *) = 0; virtual void visit(record_type_expression *) = 0; virtual void visit(union_type_expression *) = 0; virtual void visit(procedure_type_expression *) = 0; virtual void visit(enumeration_type_expression *) = 0; - virtual void visit(variable_expression *) = 0; + virtual void visit(named_expression *) = 0; virtual void visit(array_access_expression *) = 0; virtual void visit(field_access_expression *) = 0; virtual void visit(dereference_expression *) = 0; @@ -139,7 +139,7 @@ namespace elna::frontend [[noreturn]] void not_implemented(); public: - [[noreturn]] virtual void visit(named_type_expression *) override; + [[noreturn]] virtual void visit(type_expression *) override; [[noreturn]] virtual void visit(array_type_expression *) override; [[noreturn]] virtual void visit(pointer_type_expression *) override; [[noreturn]] virtual void visit(program *) override; @@ -165,7 +165,7 @@ namespace elna::frontend [[noreturn]] virtual void visit(traits_expression *) override; [[noreturn]] virtual void visit(binary_expression *) override; [[noreturn]] virtual void visit(unary_expression *) override; - [[noreturn]] virtual void visit(variable_expression *) override; + [[noreturn]] virtual void visit(named_expression *) override; [[noreturn]] virtual void visit(array_access_expression *) override; [[noreturn]] virtual void visit(field_access_expression *) override; [[noreturn]] virtual void visit(dereference_expression *) override; @@ -232,10 +232,10 @@ namespace elna::frontend /** * Some type expression. */ - class type_expression : public node + class type_expression : public virtual node { public: - virtual named_type_expression *is_named(); + virtual named_expression *is_named(); virtual array_type_expression *is_array(); virtual pointer_type_expression *is_pointer(); virtual record_type_expression *is_record(); @@ -243,21 +243,8 @@ namespace elna::frontend virtual procedure_type_expression *is_procedure(); virtual enumeration_type_expression *is_enumeration(); - protected: - type_expression(const struct position position); - }; - - /** - * Expression refering to a type by its name. - */ - class named_type_expression : public type_expression - { - public: - const std::string name; - - named_type_expression(const struct position position, const std::string& name); void accept(parser_visitor *visitor) override; - named_type_expression *is_named() override; + ~type_expression() = 0; }; class array_type_expression : public type_expression @@ -363,9 +350,6 @@ namespace elna::frontend { public: literal_expression *is_literal() override; - - protected: - literal_expression(); }; /** @@ -407,6 +391,7 @@ namespace elna::frontend { block(std::vector<constant_declaration*>&& constants, std::vector<variable_declaration *>&& variables, std::vector<statement *>&& body); + block(std::vector<constant_declaration*>&& constants, std::vector<variable_declaration *>&& variables); block(const block&) = delete; block(block&& that); @@ -553,7 +538,7 @@ namespace elna::frontend class designator_expression : public expression { public: - virtual variable_expression *is_variable(); + virtual named_expression *is_named(); virtual array_access_expression *is_array_access(); virtual field_access_expression *is_field_access(); virtual dereference_expression *is_dereference(); @@ -561,20 +546,20 @@ namespace elna::frontend designator_expression *is_designator() override; void accept(parser_visitor *visitor); ~designator_expression() = 0; - - protected: - designator_expression(); }; - class variable_expression : public designator_expression, public literal_expression + /** + * Expression refering to an entity by its name. + */ + class named_expression : public designator_expression, public type_expression { public: const std::string name; - variable_expression(const struct position position, const std::string& name); + named_expression(const struct position position, const std::string& name); void accept(parser_visitor *visitor) override; - variable_expression *is_variable() override; + named_expression *is_named() override; }; class array_access_expression : public designator_expression diff --git a/include/elna/frontend/semantic.h b/include/elna/frontend/semantic.h index 8a295e4..887b660 100644 --- a/include/elna/frontend/semantic.h +++ b/include/elna/frontend/semantic.h @@ -127,11 +127,13 @@ namespace elna::frontend procedure_type build_procedure(procedure_type_expression& type_expression); std::vector<type_field> build_composite_type(const std::vector<field_declaration>& fields); + std::shared_ptr<variable_info> register_variable(const std::string& name, + const bool is_extern, const struct position position); public: name_analysis_visitor(const char *path, symbol_bag bag); - void visit(named_type_expression *type_expression) override; + void visit(type_expression *) override; void visit(array_type_expression *type_expression) override; void visit(pointer_type_expression *type_expression) override; void visit(program *program) override; @@ -157,7 +159,7 @@ namespace elna::frontend void visit(traits_expression *trait) override; void visit(binary_expression *expression) override; void visit(unary_expression *expression) override; - void visit(variable_expression *) override; + void visit(named_expression *type_expression) override; void visit(array_access_expression *expression) override; void visit(field_access_expression *expression) override; void visit(dereference_expression *expression) override; diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index 97cd512..ec6f32f 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -81,7 +81,7 @@ namespace elna::gcc void visit(frontend::unary_expression *expression) override; void visit(frontend::constant_declaration *definition) override; void visit(frontend::variable_declaration *declaration) override; - void visit(frontend::variable_expression *expression) override; + void visit(frontend::named_expression *expression) override; void visit(frontend::array_access_expression *expression) override; void visit(frontend::field_access_expression *expression) override; void visit(frontend::dereference_expression *expression) override; diff --git a/rakelib/gcc.rake b/rakelib/gcc.rake index 39b4442..2b8bbfb 100644 --- a/rakelib/gcc.rake +++ b/rakelib/gcc.rake @@ -10,7 +10,7 @@ require 'pathname' def gcc_verbose(gcc_binary) read, write = IO.pipe - sh({'LANG' => 'C'}, gcc_binary, '--verbose', err: write) + sh({'LC_ALL' => 'C'}, gcc_binary, '--verbose', err: write) write.close output = read.read read.close @@ -60,10 +60,10 @@ end namespace :gcc do # Dependencies. - GCC_VERSION = "15.2.0" + GCC_VERSION = "15.3.0" HOST_GCC = 'build/host/gcc' HOST_INSTALL = 'build/host/install' - GCC_PATCH = 'https://raw.githubusercontent.com/Homebrew/formula-patches/575ffcaed6d3112916fed77d271dd3799a7255c4/gcc/gcc-15.1.0.diff' + GCC_PATCH = 'https://raw.githubusercontent.com/Homebrew/homebrew-core/refs/heads/main/Patches/gcc/gcc-15.3.0.diff' directory HOST_GCC directory HOST_INSTALL diff --git a/source/cctype.elna b/source/cctype.elna index 3906cd1..13dc50a 100644 --- a/source/cctype.elna +++ b/source/cctype.elna @@ -1,14 +1,23 @@ (* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. *) -module; -proc isdigit*(c: Int ) -> Int; extern; -proc isalnum*(c: Int) -> Int; extern; -proc isalpha*(c: Int) -> Int; extern; -proc isspace*(c: Int) -> Int; extern; +proc isdigit*(c: Int ) -> Int +extern -proc tolower*(c: Int) -> Int; extern; -proc toupper*(c: Int) -> Int; extern; +proc isalnum*(c: Int) -> Int +extern + +proc isalpha*(c: Int) -> Int +extern + +proc isspace*(c: Int) -> Int +extern + +proc tolower*(c: Int) -> Int +extern + +proc toupper*(c: Int) -> Int +extern end. diff --git a/source/command_line_interface.elna b/source/command_line_interface.elna index 040fdeb..78e1cf5 100644 --- a/source/command_line_interface.elna +++ b/source/command_line_interface.elna @@ -5,9 +5,7 @@ (* Command line handling. *) -module; - -import cstdlib, cstring, common; +import cstdlib, cstring, common type CommandLine* = record @@ -15,14 +13,14 @@ type output: ^Char; lex: Bool; parse: Bool - end; + end -proc parse_command_line*(argc: Int, argv: ^^Char) -> ^CommandLine; +proc parse_command_line*(argc: Int, argv: ^^Char) -> ^CommandLine var - parameter: ^Char; - i: Int; - result: ^CommandLine; - parsed: Bool; + parameter: ^Char + i: Int + result: ^CommandLine + parsed: Bool begin i := 1; result := cast(malloc(#size(CommandLine)): ^CommandLine); @@ -88,6 +86,6 @@ begin end; return result -end; +end end. diff --git a/source/common.elna b/source/common.elna index e7b30ca..33a79b8 100644 --- a/source/common.elna +++ b/source/common.elna @@ -1,50 +1,50 @@ (* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. *) -module; -import cstring, cstdio; +import cstring, cstdio type - Identifier = [256]Char; + Identifier = [256]Char TextLocation* = record line: Word; column: Word - end; + end -proc write*(fd: Int, buf: Pointer, Word: Int) -> Int; extern; +proc write*(fd: Int, buf: Pointer, Word: Int) -> Int +extern -proc write_s*(value: String); +proc write_s*(value: String) begin (* fwrite(cast(value.ptr: Pointer), value.length, 1u, stdout) *) write(1, cast(value.ptr: Pointer), cast(value.length: Int)) -end; +end -proc write_z*(value: ^Char); +proc write_z*(value: ^Char) begin write(1, cast(value: Pointer), cast(strlen(value): Int)) -end; +end -proc write_b*(value: Bool); +proc write_b*(value: Bool) begin if value then write_s("true") else write_s("false") end -end; +end -proc write_c*(value: Char); +proc write_c*(value: Char) begin putchar(cast(value: Int)); fflush(nil) -end; +end -proc write_i*(value: Int); +proc write_i*(value: Int) var - digit: Int; - n: Word; - buffer: [10]Char; + digit: Int + n: Word + buffer: [10]Char begin n := 10u; @@ -62,11 +62,11 @@ begin n := n + 1u; write_c(buffer[n]) end -end; +end -proc write_u*(value: Word); +proc write_u*(value: Word) begin write_i(cast(value: Int)) -end; +end end. diff --git a/source/cstdio.elna b/source/cstdio.elna index c7507ff..b86014f 100644 --- a/source/cstdio.elna +++ b/source/cstdio.elna @@ -1,29 +1,46 @@ (* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. *) -module; type - FILE* = record end; + FILE* = record end var - stdin*: ^FILE := extern; - stdout*: ^FILE := extern; - stderr*: ^FILE := extern; + stdin*: ^FILE := extern + stdout*: ^FILE := extern + stderr*: ^FILE := 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 fflush*(stream: ^FILE) -> Int; extern; +proc fopen*(pathname: ^Char, mode: ^Char) -> ^FILE +extern -proc fread*(ptr: Pointer, size: Word, nmemb: Word, stream: ^FILE) -> Word; extern; -proc fwrite*(ptr: Pointer, size: Word, nitems: Word, stream: ^FILE) -> Word; extern; +proc fclose*(stream: ^FILE) -> Int +extern -proc perror(s: ^Char); extern; +proc fseek*(stream: ^FILE, off: Int, whence: Int) -> Int +extern -proc puts(s: ^Char) -> Int; extern; -proc putchar(c: Int) -> Int; extern; +proc rewind*(stream: ^FILE) +extern + +proc ftell*(stream: ^FILE) -> Int +extern + +proc fflush*(stream: ^FILE) -> Int +extern + +proc fread*(ptr: Pointer, size: Word, nmemb: Word, stream: ^FILE) -> Word +extern + +proc fwrite*(ptr: Pointer, size: Word, nitems: Word, stream: ^FILE) -> Word +extern + +proc perror(s: ^Char) +extern + +proc puts(s: ^Char) -> Int +extern + +proc putchar(c: Int) -> Int +extern end. diff --git a/source/cstdlib.elna b/source/cstdlib.elna index da2029c..3346440 100644 --- a/source/cstdlib.elna +++ b/source/cstdlib.elna @@ -1,15 +1,23 @@ (* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. *) -module; -proc malloc(size: Word) -> Pointer; extern; -proc free(ptr: Pointer); extern; -proc calloc(nmemb: Word, size: Word) -> Pointer; extern; -proc realloc(ptr: Pointer, size: Word) -> Pointer; extern; +proc malloc(size: Word) -> Pointer +extern -proc atoi(str: ^Char) -> Int; extern; +proc free(ptr: Pointer) +extern -proc exit(code: Int) -> !; extern; +proc calloc(nmemb: Word, size: Word) -> Pointer +extern + +proc realloc(ptr: Pointer, size: Word) -> Pointer +extern + +proc atoi(str: ^Char) -> Int +extern + +proc exit(code: Int) -> ! +extern end. diff --git a/source/cstring.elna b/source/cstring.elna index 24d852a..ef04e59 100644 --- a/source/cstring.elna +++ b/source/cstring.elna @@ -1,15 +1,26 @@ (* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. *) -module; -proc memset(ptr: Pointer, c: Int, n: Word) -> ^Char; extern; -proc memcpy(dst: Pointer, src: Pointer, n: Word); extern; +proc memset(ptr: Pointer, c: Int, n: Word) -> ^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 memcpy(dst: Pointer, src: Pointer, n: 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 end. diff --git a/source/lexer.elna b/source/lexer.elna index d5f529b..e6fc38c 100644 --- a/source/lexer.elna +++ b/source/lexer.elna @@ -1,12 +1,11 @@ (* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. *) -module; -import cstdio, cstring, cctype, cstdlib, common; +import cstdio, cstring, cctype, cstdlib, common const - CHUNK_SIZE := 85536u; + CHUNK_SIZE := 85536u type (* @@ -38,7 +37,7 @@ type greater, less, other - ); + ) TransitionState = ( start, colon, @@ -56,7 +55,7 @@ type leading_zero, decimal_suffix, finish - ); + ) LexerToken = record kind: LexerKind; value: union @@ -67,18 +66,18 @@ type end; start_location: TextLocation; end_location: TextLocation - end; - TransitionAction = proc(^Lexer, ^LexerToken); + end + TransitionAction = proc(^Lexer, ^LexerToken) Transition = record action: TransitionAction; next_state: TransitionState - end; - TransitionClasses = [22]Transition; + end + TransitionClasses = [22]Transition BufferPosition* = record iterator: ^Char; location: TextLocation - end; + end Lexer* = record input: ^FILE; buffer: ^Char; @@ -86,7 +85,7 @@ type length: Word; start: BufferPosition; current: BufferPosition - end; + end LexerKind* = ( unknown, identifier, @@ -153,15 +152,15 @@ type _program, _module, _import - ); + ) var - classification: [128]TransitionClass; - transitions: [16]TransitionClasses; + classification: [128]TransitionClass + transitions: [16]TransitionClasses -proc initialize_classification(); +proc initialize_classification() var - i: Word; + i: Word begin classification[1] := TransitionClass.eof; (* NUL *) classification[2] := TransitionClass.invalid; (* SOH *) @@ -297,13 +296,13 @@ begin classification[i] := TransitionClass.other; i := i + 1u end -end; +end -proc compare_keyword(keyword: String, token_start: BufferPosition, token_end: ^Char) -> Bool; +proc compare_keyword(keyword: String, token_start: BufferPosition, token_end: ^Char) -> Bool var - result: Bool; - index: Word; - continue: Bool; + result: Bool + index: Word + continue: Bool begin index := 0u; result := true; @@ -319,28 +318,28 @@ begin result := result & index = keyword.length; return result & (token_start.iterator = token_end) -end; +end (* Reached the end of file. *) -proc transition_action_eof(lexer: ^Lexer, token: ^LexerToken); +proc transition_action_eof(lexer: ^Lexer, token: ^LexerToken) begin token^.kind := LexerKind.unknown -end; +end -proc increment(position: ^BufferPosition); +proc increment(position: ^BufferPosition) begin position^.iterator := position^.iterator + 1 -end; +end (* Add the character to the token currently read and advance to the next character. *) -proc transition_action_accumulate(lexer: ^Lexer, token: ^LexerToken); +proc transition_action_accumulate(lexer: ^Lexer, token: ^LexerToken) begin increment(@lexer^.current) -end; +end (* The current character is not a part of the token. Finish the token already * read. Don't advance to the next character. *) -proc transition_action_finalize(lexer: ^Lexer, token: ^LexerToken); +proc transition_action_finalize(lexer: ^Lexer, token: ^LexerToken) begin if lexer^.start.iterator^ = ':' then token^.kind := LexerKind.colon @@ -360,10 +359,10 @@ begin if lexer^.start.iterator^ = '.' then token^.kind := LexerKind.dot end -end; +end (* An action for tokens containing multiple characters. *) -proc transition_action_composite(lexer: ^Lexer, token: ^LexerToken); +proc transition_action_composite(lexer: ^Lexer, token: ^LexerToken) begin if lexer^.start.iterator^ = '<' then if lexer^.current.iterator^ = '>' then @@ -383,10 +382,10 @@ begin token^.kind := LexerKind.arrow end; increment(@lexer^.current) -end; +end (* Skip a space. *) -proc transition_action_skip(lexer: ^Lexer, token: ^LexerToken); +proc transition_action_skip(lexer: ^Lexer, token: ^LexerToken) begin increment(@lexer^.start); @@ -395,12 +394,12 @@ begin lexer^.start.location.column := 1u end; lexer^.current := lexer^.start -end; +end (* Delimited string action. *) -proc transition_action_delimited(lexer: ^Lexer, token: ^LexerToken); +proc transition_action_delimited(lexer: ^Lexer, token: ^LexerToken) var - text_length: Word; + text_length: Word begin if lexer^.start.iterator^ = '(' then token^.kind := LexerKind.comment @@ -422,10 +421,10 @@ begin token^.kind := LexerKind.string end; increment(@lexer^.current) -end; +end (* Finalize keyword or identifier. *) -proc transition_action_key_id(lexer: ^Lexer, token: ^LexerToken); +proc transition_action_key_id(lexer: ^Lexer, token: ^LexerToken) begin token^.kind := LexerKind.identifier; @@ -515,11 +514,11 @@ begin token^.kind := LexerKind.boolean; token^.value.booleanKind := false end -end; +end (* Action for tokens containing only one character. The character cannot be * followed by other characters forming a composite token. *) -proc transition_action_single(lexer: ^Lexer, token: ^LexerToken); +proc transition_action_single(lexer: ^Lexer, token: ^LexerToken) begin if lexer^.current.iterator^ = '&' then token^.kind := LexerKind.and @@ -567,14 +566,14 @@ begin token^.kind := LexerKind.pipe end; increment(@lexer^.current) -end; +end (* Handle an integer literal. *) -proc transition_action_integer(lexer: ^Lexer, token: ^LexerToken); +proc transition_action_integer(lexer: ^Lexer, token: ^LexerToken) var - buffer: String; - integer_length: Word; - found: Bool; + buffer: String + integer_length: Word + found: Bool begin token^.kind := LexerKind.integer; @@ -584,12 +583,12 @@ begin token^.value.identifierKind[cast(token^.value.identifierKind[1]: Int) + 2] := '\0'; token^.value.integerKind := atoi(@token^.value.identifierKind[2]) -end; +end -proc set_default_transition(current_state: TransitionState, default_action: TransitionAction, next_state: TransitionState) -> Int; +proc set_default_transition(current_state: TransitionState, default_action: TransitionAction, next_state: TransitionState) -> Int var - default_transition: Transition; - state_index: Int; + default_transition: Transition + state_index: Int begin default_transition.action := default_action; default_transition.next_state := next_state; @@ -619,7 +618,7 @@ begin transitions[state_index][cast(TransitionClass.other: Int) + 1] := default_transition; return state_index -end; +end (* * The transition table describes transitions from one state to another, given @@ -637,9 +636,9 @@ end; * For the meaning of actions see labels in the lex_next function, which * handles each action. *) -proc initialize_transitions(); +proc initialize_transitions() var - state_index: Int; + state_index: Int begin (* Start state. *) state_index := cast(TransitionState.start: Int) + 1; @@ -877,9 +876,9 @@ begin transitions[state_index][cast(TransitionClass.x: Int) + 1].action := nil; transitions[state_index][cast(TransitionClass.x: Int) + 1].next_state := TransitionState.finish -end; +end -proc lexer_make*(lexer: ^Lexer, input: ^FILE); +proc lexer_make*(lexer: ^Lexer, input: ^FILE) begin lexer^.input := input; lexer^.length := 0u; @@ -887,17 +886,17 @@ begin lexer^.buffer := cast(malloc(CHUNK_SIZE): ^Char); memset(cast(lexer^.buffer: Pointer), 0, CHUNK_SIZE); lexer^.size := CHUNK_SIZE -end; +end (* Returns the last read token. *) -proc lexer_current*(lexer: ^Lexer) -> LexerToken; +proc lexer_current*(lexer: ^Lexer) -> LexerToken var - current_class: TransitionClass; - current_state: TransitionState; - current_transition: Transition; - result: LexerToken; - index1: Word; - index2: Word; + current_class: TransitionClass + current_state: TransitionState + current_transition: Transition + result: LexerToken + index1: Word + index2: Word begin lexer^.current := lexer^.start; current_state := TransitionState.start; @@ -919,12 +918,12 @@ begin result.end_location := lexer^.current.location; return result -end; +end (* Read and return the next token. *) -proc lexer_lex*(lexer: ^Lexer) -> LexerToken; +proc lexer_lex*(lexer: ^Lexer) -> LexerToken var - result: LexerToken; + result: LexerToken begin if lexer^.length = 0u then lexer^.length := fread(cast(lexer^.buffer: Pointer), CHUNK_SIZE, 1u, lexer^.input); @@ -936,17 +935,17 @@ begin result := lexer_current(lexer); return result -end; +end -proc lexer_destroy*(lexer: ^Lexer); +proc lexer_destroy*(lexer: ^Lexer) begin free(cast(lexer^.buffer: Pointer)) -end; +end -proc lexer_initialize(); +proc lexer_initialize() begin initialize_classification(); initialize_transitions() -end; +end end. diff --git a/source/main.elna b/source/main.elna index dae045b..e60f9ae 100644 --- a/source/main.elna +++ b/source/main.elna @@ -1,9 +1,8 @@ (* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. *) -program; -import cstdio, cctype, common, command_line_interface, lexer; +import cstdio, cstdlib, cstring, cctype, common, command_line_interface, lexer type SourceFile* = record @@ -11,12 +10,12 @@ type handle: ^FILE; size: Word; index: Word - end; + end StringBuffer* = record data: Pointer; size: Word; capacity: Word - end; + end SourceCode = record position: TextLocation; @@ -24,7 +23,7 @@ type empty: proc(Pointer) -> Bool; advance: proc(Pointer); head: proc(Pointer) -> Char - end; + end Token* = record kind: LexerKind; value: union @@ -33,49 +32,49 @@ type boolean_value: Bool; char_value: Char end - end; + end Tokenizer* = record length: Word; data: ^Token - end; + end (* Standard procedures. *) -proc reallocarray(ptr: Pointer, n: Word, size: Word) -> Pointer; +proc reallocarray(ptr: Pointer, n: Word, size: Word) -> Pointer return realloc(ptr, n * size) -end; +end -proc substring(string: String, start: Word, count: Word) -> String; +proc substring(string: String, start: Word, count: Word) -> String return String(string.ptr + start, count) -end; +end -proc open_substring(string: String, start: Word) -> String; +proc open_substring(string: String, start: Word) -> String return substring(string, start, string.length - start) -end; +end -proc string_dup(origin: String) -> String; +proc string_dup(origin: String) -> String var - copy: ^Char; + copy: ^Char begin copy := cast(malloc(origin.length): ^Char); strncpy(copy, origin.ptr, origin.length); return String(copy, origin.length) -end; +end -proc string_buffer_new() -> StringBuffer; +proc string_buffer_new() -> StringBuffer var - result: StringBuffer; + result: StringBuffer begin result.capacity := 64u; result.data := malloc(result.capacity); result.size := 0u; return result -end; +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; @@ -83,30 +82,30 @@ begin end; cast(buffer^.data + buffer^.size: ^Char)^ := cast(char: Char); buffer^.size := buffer^.size + 1u -end; +end -proc string_buffer_pop(buffer: ^StringBuffer, count: Word); +proc string_buffer_pop(buffer: ^StringBuffer, count: Word) begin buffer^.size := buffer^.size - count -end; +end -proc string_buffer_clear(buffer: ^StringBuffer) -> String; +proc string_buffer_clear(buffer: ^StringBuffer) -> String var - result: String; + result: String begin result := String(cast(buffer^.data: ^Char), buffer^.size); buffer^.size := 0u; return result -end; +end (* Source code stream procedures. *) -proc read_source(filename: ^Char) -> ^SourceFile; +proc read_source(filename: ^Char) -> ^SourceFile var - result: ^SourceFile; - file_handle: ^FILE; + result: ^SourceFile + file_handle: ^FILE begin file_handle := fopen(filename, "rb\0".ptr); @@ -117,11 +116,11 @@ begin result^.index := 1u end; return result -end; +end -proc source_file_empty(source_input: Pointer) -> Bool; +proc source_file_empty(source_input: Pointer) -> Bool var - source_file: ^SourceFile; + source_file: ^SourceFile begin source_file := cast(source_input: ^SourceFile); @@ -131,57 +130,57 @@ begin end; return source_file^.size = 0u -end; +end -proc source_file_head(source_input: Pointer) -> Char; +proc source_file_head(source_input: Pointer) -> Char var - source_file: ^SourceFile; + source_file: ^SourceFile begin source_file := cast(source_input: ^SourceFile); return source_file^.buffer[source_file^.index] -end; +end -proc source_file_advance(source_input: Pointer); +proc source_file_advance(source_input: Pointer) var - source_file: ^SourceFile; + source_file: ^SourceFile begin source_file := cast(source_input: ^SourceFile); source_file^.index := source_file^.index + 1u -end; +end -proc source_code_empty(source_code: ^SourceCode) -> Bool; +proc source_code_empty(source_code: ^SourceCode) -> Bool return source_code^.empty(source_code^.input) -end; +end -proc source_code_head(source_code: SourceCode) -> Char; +proc source_code_head(source_code: SourceCode) -> Char return source_code.head(source_code.input) -end; +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; +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; +end -proc source_code_expect(source_code: ^SourceCode, expected: Char) -> Bool; +proc source_code_expect(source_code: ^SourceCode, expected: Char) -> Bool return ~source_code_empty(source_code) & source_code_head(source_code^) = expected -end; +end (* Token procedures. *) -proc lexer_escape(escape: Char, result: ^Char) -> Bool; +proc lexer_escape(escape: Char, result: ^Char) -> Bool var - successful: Bool; + successful: Bool begin case escape of 'n': @@ -224,12 +223,12 @@ begin successful := false end; return successful -end; +end (* Skip spaces. *) -proc lexer_spaces(source_code: ^SourceCode); +proc lexer_spaces(source_code: ^SourceCode) var - current: Char; + current: Char begin while ~source_code_empty(source_code) & isspace(cast(source_code_head(source_code^): Int)) <> 0 do current := source_code_head(source_code^); @@ -239,26 +238,26 @@ begin end; source_code_advance(source_code) end -end; +end (* Checker whether the character is allowed in an identificator. *) -proc lexer_is_ident(char: Char) -> Bool; +proc lexer_is_ident(char: Char) -> Bool return isalnum(cast(char: Int)) <> 0 or char = '_' -end; +end -proc lexer_identifier(source_code: ^SourceCode, token_content: ^StringBuffer); +proc lexer_identifier(source_code: ^SourceCode, token_content: ^StringBuffer) var - content_length: Word; + content_length: Word begin while ~source_code_empty(source_code) & lexer_is_ident(source_code_head(source_code^)) do string_buffer_push(token_content, source_code_head(source_code^)); source_code_advance(source_code) end -end; +end -proc lexer_comment(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool; +proc lexer_comment(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool var - trailing: Word; + trailing: Word begin trailing := 0u; @@ -277,11 +276,11 @@ begin end; return trailing = 2u -end; +end -proc lexer_character(source_code: ^SourceCode, token_content: ^Char) -> Bool; +proc lexer_character(source_code: ^SourceCode, token_content: ^Char) -> Bool var - successful: Bool; + successful: Bool begin successful := ~source_code_empty(source_code); @@ -299,14 +298,14 @@ begin source_code_advance(source_code) end; return successful -end; +end -proc lexer_string(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool; +proc lexer_string(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool var - token_end, constructed_string: ^Char; - token_length: Word; - is_valid: Bool := true; - next_char: Char; + token_end, constructed_string: ^Char + token_length: Word + is_valid: Bool := true + next_char: Char begin while is_valid & ~source_code_empty(source_code) & source_code_head(source_code^) <> '"' do is_valid := lexer_character(source_code, @next_char); @@ -322,9 +321,9 @@ begin is_valid := false end; return is_valid -end; +end -proc lexer_number(source_code: ^SourceCode, token_content: ^Int); +proc lexer_number(source_code: ^SourceCode, token_content: ^Int) begin token_content^ := 0; @@ -333,12 +332,12 @@ begin source_code_advance(source_code) end -end; +end (* Categorize an identifier. *) -proc lexer_categorize(token_content: String) -> Token; +proc lexer_categorize(token_content: String) -> Token var - current_token: Token; + current_token: Token begin if token_content = "if" then current_token.kind := LexerKind._if @@ -402,23 +401,23 @@ begin end; return current_token -end; +end -proc lexer_add_token(lexer: ^Tokenizer, token: Token); +proc lexer_add_token(lexer: ^Tokenizer, token: Token) var - new_length: Word; + new_length: Word begin new_length := lexer^.length + 1u; lexer^.data := cast(reallocarray(cast(lexer^.data: Pointer), new_length, #size(Token)): ^Token); (lexer^.data + lexer^.length)^ := token; lexer^.length := new_length -end; +end (* Read the next token from the input. *) -proc lexer_next(source_code: SourceCode, token_buffer: ^StringBuffer) -> Token; +proc lexer_next(source_code: SourceCode, token_buffer: ^StringBuffer) -> Token var - current_token: Token; - first_char: Char; + current_token: Token + first_char: Char begin current_token.kind := LexerKind.unknown; @@ -587,14 +586,14 @@ begin end; return current_token -end; +end (* Split the source text into tokens. *) -proc lexer_text(source_code: SourceCode) -> Tokenizer; +proc lexer_text(source_code: SourceCode) -> Tokenizer var - current_token: Token; - token_buffer: StringBuffer; - lexer: Tokenizer; + current_token: Token + token_buffer: StringBuffer + lexer: Tokenizer begin lexer := Tokenizer(0u, nil); token_buffer := string_buffer_new(); @@ -615,16 +614,16 @@ begin end; return lexer -end; +end (* Parser. *) -proc parse(tokens: ^Token, tokens_size: Word); +proc parse(tokens: ^Token, tokens_size: Word) var - current_token: ^Token; - i: Word := 0u; + current_token: ^Token + i: Word := 0u begin while i < tokens_size do current_token := tokens + i; @@ -777,16 +776,16 @@ begin i := i + 1u end; write_c('\n') -end; +end (* Compilation entry. *) -proc compile_in_stages(command_line: ^CommandLine, source_code: SourceCode) -> Int; +proc compile_in_stages(command_line: ^CommandLine, source_code: SourceCode) -> Int var - return_code: Int := 0; - lexer: Tokenizer; + return_code: Int := 0 + lexer: Tokenizer begin if command_line^.lex or command_line^.parse then lexer := lexer_text(source_code) @@ -796,16 +795,16 @@ begin end; return return_code -end; +end -proc process(argc: Int, argv: ^^Char) -> Int; +proc process(argc: Int, argv: ^^Char) -> Int var - tokens: ^Token; - tokens_size: Word; - source_code: SourceCode; - command_line: ^CommandLine; - return_code: Int := 0; - source_file: ^SourceFile; + tokens: ^Token + tokens_size: Word + source_code: SourceCode + command_line: ^CommandLine + return_code: Int := 0 + source_file: ^SourceFile begin command_line := parse_command_line(argc, argv); if command_line = nil then @@ -835,7 +834,7 @@ begin return_code := compile_in_stages(command_line, source_code) end; return return_code -end; +end return process(count, parameters) end. |
