aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--frontend/ast.cc86
-rw-r--r--frontend/lexer.ll6
-rw-r--r--frontend/parser.yy97
-rw-r--r--frontend/semantic.cc88
-rw-r--r--gcc/README.md2
-rw-r--r--gcc/elna-generic.cc6
-rw-r--r--include/elna/frontend/ast.h49
-rw-r--r--include/elna/frontend/semantic.h6
-rw-r--r--include/elna/gcc/elna-generic.h2
-rw-r--r--rakelib/gcc.rake6
-rw-r--r--source/cctype.elna23
-rw-r--r--source/command_line_interface.elna18
-rw-r--r--source/common.elna40
-rw-r--r--source/cstdio.elna49
-rw-r--r--source/cstdlib.elna22
-rw-r--r--source/cstring.elna27
-rw-r--r--source/lexer.elna139
-rw-r--r--source/main.elna209
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.