diff options
| -rw-r--r-- | boot/ast.cc | 6 | ||||
| -rw-r--r-- | boot/materialization.cc | 14 | ||||
| -rw-r--r-- | boot/name_analysis.cc | 6 | ||||
| -rw-r--r-- | boot/parser.yy | 29 | ||||
| -rw-r--r-- | gcc/gcc/elna-module-loader.cc | 2 | ||||
| -rw-r--r-- | include/elna/boot/ast.h | 16 | ||||
| -rw-r--r-- | include/elna/boot/materialization.h | 4 | ||||
| -rw-r--r-- | source/ast.elna | 270 | ||||
| -rw-r--r-- | source/command_line_interface.elna | 89 | ||||
| -rw-r--r-- | source/common.elna | 88 | ||||
| -rw-r--r-- | source/diagnostic.elna | 241 | ||||
| -rw-r--r-- | source/lexer.elna | 815 | ||||
| -rw-r--r-- | source/main.elna | 138 | ||||
| -rw-r--r-- | source/name_analysis.elna | 539 | ||||
| -rw-r--r-- | source/parser.elna | 1162 | ||||
| -rw-r--r-- | source/qbe.elna | 635 | ||||
| -rw-r--r-- | source/symbol.elna | 200 | ||||
| -rw-r--r-- | source/sys/posix/cctype.elna | 24 | ||||
| -rw-r--r-- | source/sys/posix/cstdio.elna | 59 | ||||
| -rw-r--r-- | source/sys/posix/cstdlib.elna | 24 | ||||
| -rw-r--r-- | source/sys/posix/cstring.elna | 30 | ||||
| -rw-r--r-- | source/tac.elna | 1074 | ||||
| -rw-r--r-- | source/type_check.elna | 315 | ||||
| -rw-r--r-- | testsuite/compilable/generic_export.elna | 11 | ||||
| -rw-r--r-- | testsuite/fail_compilation/generic_variable.elna | 6 |
25 files changed, 65 insertions, 5732 deletions
diff --git a/boot/ast.cc b/boot/ast.cc index 456797a..b681695 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -597,8 +597,10 @@ namespace elna::boot } identifier_definition::identifier_definition(const std::string& name, - const source_position& position, const bool exported, std::vector<attribute>&& attributes) - : attributes(std::move(attributes)), m_identifier(name, position), m_exported(exported) + const source_position& position, const bool exported, + std::vector<identifier>&& parameters, std::vector<attribute>&& attributes) + : parameters(std::move(parameters)), attributes(std::move(attributes)), + m_identifier(name, position), m_exported(exported) { } diff --git a/boot/materialization.cc b/boot/materialization.cc index 6eea0d1..9e9d3ae 100644 --- a/boot/materialization.cc +++ b/boot/materialization.cc @@ -39,6 +39,10 @@ namespace elna::boot return "Local symbols cannot be extern"; case field_export: return "Record fields cannot be exported"; + case variable_generic: + return "Variables cannot have generic parameters"; + case field_generic: + return "Record fields cannot have generic parameters"; } __builtin_unreachable(); } @@ -78,6 +82,11 @@ namespace elna::boot add_error<materialization_error>(variable_identifier.id().position(), materialization_error::kind::local_export); } + if (!variable_identifier.parameters.empty()) + { + add_error<materialization_error>(variable_identifier.id().position(), + materialization_error::kind::variable_generic); + } } if (!this->in_global_scope && declaration->is_extern) { @@ -99,6 +108,11 @@ namespace elna::boot add_error<materialization_error>(field_identifier.id().position(), materialization_error::kind::field_export); } + if (!field_identifier.parameters.empty()) + { + add_error<materialization_error>(field_identifier.id().position(), + materialization_error::kind::field_generic); + } } } } diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc index c58b586..17e15f6 100644 --- a/boot/name_analysis.cc +++ b/boot/name_analysis.cc @@ -1409,13 +1409,13 @@ namespace elna::boot void declaration_visitor::visit(type_declaration *declaration) { - const bool is_generic = !declaration->parameters.empty(); + const bool is_generic = !declaration->identifier.parameters.empty(); std::vector<type> parameters; if (is_generic) { this->bag.enter(); - parameters = enter_parameters(declaration->parameters); + parameters = enter_parameters(declaration->identifier.parameters); } type underlying = resolve_type(declaration->underlying_type()); @@ -1514,7 +1514,7 @@ namespace elna::boot // parameters are visible in it, and it becomes the body's scope, which // is why the body sees them too. const std::shared_ptr<symbol_table> scope = this->bag.enter(); - const std::vector<type> type_parameters = enter_parameters(declaration->parameters); + const std::vector<type> type_parameters = enter_parameters(declaration->identifier.parameters); auto [heading, parameter_names, noreturn] = !declaration->body.has_value() ? build_procedure<attribute_kind::varargs, attribute_kind::noreturn>(declaration->heading()) : build_procedure<attribute_kind::noreturn>(declaration->heading()); diff --git a/boot/parser.yy b/boot/parser.yy index 65d3dba..855cc76 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -161,6 +161,7 @@ along with GCC; see the file COPYING3. If not see %type <std::unique_ptr<elna::boot::attribute>> attribute; %type <std::vector<elna::boot::attribute>> attributes; %type <std::pair<std::vector<std::string>, bool>> import_declaration; +%type <bool> export_marker; %type <std::vector<std::string>> import_path; %type <std::vector<elna::boot::identifier>> required_identifiers optional_identifiers generic_parameters; %type <std::unique_ptr<elna::boot::enumeration_type_expression::member_declaration>> enumeration_member; @@ -244,9 +245,15 @@ optional_begin_statements: | statements { $$ = $1; } identifier: IDENTIFIER { $$ = std::make_unique<boot::identifier>($1, boot::make_position(@1)); } +export_marker: + "*" { $$ = true; } + | %empty { $$ = false; } identifier_definition: - IDENTIFIER "*" { $$ = std::make_unique<boot::identifier_definition>($1, boot::make_position(@1), true); } - | IDENTIFIER { $$ = std::make_unique<boot::identifier_definition>($1, boot::make_position(@1), false); } + IDENTIFIER generic_parameters export_marker + { + $$ = std::make_unique<boot::identifier_definition>($1, boot::make_position(@1), + $3, std::move($2)); + } attribute: "#{" IDENTIFIER optional_expressions "}" { @@ -282,16 +289,14 @@ procedure_heading: $$->attributes = $4; } procedure_declaration: - "proc" identifier_definition generic_parameters procedure_heading procedure_body + "proc" identifier_definition procedure_heading procedure_body { $$ = new boot::procedure_declaration(boot::make_position(@$), - std::move(*$2), $4, std::move(*$5)); - $$->parameters = $3; + std::move(*$2), $3, std::move(*$4)); } - | "proc" identifier_definition generic_parameters procedure_heading "extern" + | "proc" identifier_definition procedure_heading "extern" { - $$ = new boot::procedure_declaration(boot::make_position(@$), std::move(*$2), $4); - $$->parameters = $3; + $$ = new boot::procedure_declaration(boot::make_position(@$), std::move(*$2), $3); } call_expression: designator_expression actual_parameter_list @@ -764,16 +769,14 @@ import_declarations: new boot::import_declaration(boot::make_position(@$), std::move(segments), exported)); } type_declaration: - identifier_definition generic_parameters "=" type_expression + identifier_definition "=" type_expression { - $$ = new boot::type_declaration(boot::make_position(@$), std::move(*$1), $4); - $$->parameters = $2; + $$ = new boot::type_declaration(boot::make_position(@$), std::move(*$1), $3); } - | identifier_definition generic_parameters "=" "extern" + | identifier_definition "=" "extern" { $$ = new boot::type_declaration(boot::make_position(@$), std::move(*$1), new boot::extern_type_expression(boot::make_position(@$))); - $$->parameters = $2; } type_declarations: type_declaration type_declarations diff --git a/gcc/gcc/elna-module-loader.cc b/gcc/gcc/elna-module-loader.cc index c32b614..656e1a4 100644 --- a/gcc/gcc/elna-module-loader.cc +++ b/gcc/gcc/elna-module-loader.cc @@ -169,7 +169,7 @@ namespace elna::gcc } else if (elna_deps_options.only_dependencies) { - fputs(buffer.str().c_str(), stdout); + std::cout << buffer.str(); } else { diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index 06e5d41..e7a77ac 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -395,7 +395,8 @@ namespace elna::boot struct identifier_definition { identifier_definition(const std::string& name, const source_position& position, - const bool exported, std::vector<attribute>&& attributes = std::vector<attribute>{}); + const bool exported, std::vector<identifier>&& parameters = {}, + std::vector<attribute>&& attributes = {}); identifier_definition(const identifier_definition&) = delete; identifier_definition(identifier_definition&&) noexcept = default; @@ -406,6 +407,10 @@ namespace elna::boot const identifier& id() const; bool exported() const; /** + * \return Type parameters bound by this declaration. + */ + std::vector<identifier> parameters; + /** * \return Attributes attached to the identifier. */ std::vector<attribute> attributes; @@ -721,12 +726,6 @@ namespace elna::boot const identifier_definition identifier; std::optional<procedure_body> body; - /** - * Type parameters bound by this declaration. Empty for a plain - * procedure. - */ - std::vector<elna::boot::identifier> parameters; - procedure_declaration(const source_position position, identifier_definition identifier, procedure_type_expression *heading, procedure_body&& body); procedure_declaration(const source_position position, identifier_definition identifier, @@ -748,9 +747,6 @@ namespace elna::boot public: const identifier_definition identifier; - /// Type parameters bound by this declaration. Empty for a plain type. - std::vector<elna::boot::identifier> parameters; - type_declaration(const source_position position, identifier_definition identifier, type_expression *underlying_type); ~type_declaration() override; diff --git a/include/elna/boot/materialization.h b/include/elna/boot/materialization.h index b239836..c4abb11 100644 --- a/include/elna/boot/materialization.h +++ b/include/elna/boot/materialization.h @@ -30,7 +30,9 @@ namespace elna::boot real_overflow, local_export, local_extern, - field_export + field_export, + variable_generic, + field_generic }; materialization_error(const source_position position, kind error_kind); diff --git a/source/ast.elna b/source/ast.elna deleted file mode 100644 index ddae997..0000000 --- a/source/ast.elna +++ /dev/null @@ -1,270 +0,0 @@ -(* 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 common, lexer - -type - ElnaListNode* = record - next: ^ElnaListNode - end - ElnaList* = record - first: ^ElnaListNode; - last: ^ElnaListNode - end - - (* Type representation. *) - ElnaTypeKind* = (primitive, enumeration, _record, pointer, array, alias, procedure) - ElnaType* = record - kind: ElnaTypeKind; - size: Word; - alignment: Word - end - ElnaTypeAlias* = record(ElnaType) - base: ^ElnaType - end - ElnaTypeEnumeration* = record(ElnaType) - members: ^[]const Word8; - length: Word - end - ElnaTypeField* = record - name: []const Word8; - field_type: ^ElnaType - end - ElnaTypeRecord* = record(ElnaType) - members: ^ElnaTypeField; - length: Word - end - ElnaTypePointer* = record(ElnaType) - base: ^ElnaType - end - ElnaTypeArray* = record(ElnaType) - base: ^ElnaType; - length: Word - end - ElnaTypeProcedure* = record(ElnaType) - return_type: ^ElnaType - end - - (* Abstract syntax tree nodes. *) - ElnaTreeKind* = ( - integer_literal, - string_literal, - character_literal, - boolean_literal, - variable_expression, - field_access_expression, - dereference_expression, - unary_expression, - binary_expression, - call, - call_statement, - goto_statement, - label_declaration, - return_statement, - assign_statement, - if_statement, - procedure_declaration, - variable_declaration, - enumeration_type_expression, - named_type_expression, - type_declaration, - module_declaration, - record_type_expression, - pointer_type_expression, - array_type_expression, - null, - trait_expression, - array_access_expression, - _cast - ) - ElnaTreeNode* = record - kind: ElnaTreeKind; - position: ElnaPosition - end - ElnaTreeTypeExpression* = record(ElnaTreeNode) - end - ElnaTreeExpression* = record(ElnaTreeNode) - type_decoration: ^ElnaType - end - ElnaTreeIntegerLiteral* = record(ElnaTreeExpression) - value: Word - end - ElnaTreeCharacterLiteral* = record(ElnaTreeExpression) - value: Word8 - end - ElnaTreeNilLiteral* = record(ElnaTreeExpression) - end - ElnaTreeBooleanLiteral* = record(ElnaTreeExpression) - value: Bool - end - ElnaTreeStringLiteral* = record(ElnaTreeExpression) - value: []const Word8 - end - ElnaTreeVariableExpression* = record(ElnaTreeExpression) - name: []const Word8 - end - ElnaTreeCastExpression* = record(ElnaTreeExpression) - expression: ^ElnaTreeExpression; - type_expression: ^ElnaTreeTypeExpression - end - ElnaTreeDereferenceExpression* = record(ElnaTreeExpression) - pointer: ^ElnaTreeExpression - end - ElnaTreeBinaryExpression* = record(ElnaTreeExpression) - lhs: ^ElnaTreeExpression; - rhs: ^ElnaTreeExpression; - operator: ElnaLexerKind - end - ElnaTreeUnaryExpression* = record(ElnaTreeExpression) - operand: ^ElnaTreeExpression; - operator: ElnaLexerKind - end - ElnaTreeFieldAccessExpression* = record(ElnaTreeExpression) - aggregate: ^ElnaTreeExpression; - field: []const Word8 - end - ElnaTreeArrayAccessExpression* = record(ElnaTreeExpression) - array: ^ElnaTreeExpression; - index: ^ElnaTreeExpression - end - ElnaTreeTraitExpression* = record(ElnaTreeExpression) - name: []const Word8; - argument: ^ElnaTreeTypeExpression - end - ElnaTreeExpressionList* = record - expression: ^ElnaTreeExpression; - next: ^ElnaTreeExpressionList - end - ElnaTreeCall* = record(ElnaTreeExpression) - callee: ^ElnaTreeVariableExpression; - arguments: ^ElnaTreeExpressionList; - count: Word - end - - (* Statements. *) - ElnaTreeStatement* = record(ElnaTreeNode) - next: ^ElnaTreeStatement - end - ElnaTreeConditionalStatements* = record - condition: ^ElnaTreeExpression; - statements: ^ElnaTreeStatement; - next: ^ElnaTreeConditionalStatements - end - ElnaTreeIfStatement* = record(ElnaTreeStatement) - conditionals: ^ElnaTreeConditionalStatements; - _else: ^ElnaTreeStatement - end - ElnaTreeGotoStatement* = record(ElnaTreeStatement) - label: []const Word8 - end - ElnaTreeAssignStatement* = record(ElnaTreeStatement) - assignee: ^ElnaTreeExpression; - assignment: ^ElnaTreeExpression - end - ElnaTreeReturnStatement* = record(ElnaTreeStatement) - returned: ^ElnaTreeExpression - end - ElnaTreeLabelDeclaration* = record(ElnaTreeStatement) - label: []const Word8 - end - ElnaTreeCallStatement* = record(ElnaTreeStatement) - call: ^ElnaTreeCall - end - - (* Type expressions. *) - ElnaTreeEnumeration* = record - name: []const Word8; - next: ^ElnaTreeEnumeration - end - ElnaTreeEnumerationTypeExpression* = record(ElnaTreeTypeExpression) - members: ^ElnaTreeEnumeration; - length: Word - end - ElnaTreeField* = record - name: []const Word8; - type_expression: ^ElnaTreeTypeExpression; - next: ^ElnaTreeField - end - ElnaTreeRecordTypeExpression* = record(ElnaTreeTypeExpression) - members: ^ElnaTreeField; - length: Word; - parent: []const Word8 - end - ElnaTreeNamedTypeExpression* = record(ElnaTreeTypeExpression) - name: []const Word8 - end - ElnaTreePointerTypeExpression* = record(ElnaTreeTypeExpression) - base: ^ElnaTreeTypeExpression - end - ElnaTreeArrayTypeExpression* = record(ElnaTreeTypeExpression) - base: ^ElnaTreeTypeExpression; - length: ^ElnaTreeExpression - end - - (* Declarations. *) - ElnaTreeDeclaration* = record(ElnaTreeNode) - next: ^ElnaTreeDeclaration; - name: []const Word8 - end - ElnaTreeVariableDeclaration* = record(ElnaTreeDeclaration) - type_expression: ^ElnaTreeTypeExpression - end - ElnaTreeProcedureDeclaration* = record(ElnaTreeDeclaration) - body: ^ElnaTreeStatement; - temporaries: ^ElnaTreeVariableDeclaration; - parameters: ^ElnaTreeVariableDeclaration; - return_type: ^ElnaTreeTypeExpression; - is_extern: Bool - end - ElnaTreeTypeDeclaration* = record(ElnaTreeDeclaration) - type_expression: ^ElnaTreeTypeExpression - end - ElnaTreeModuleDeclaration* = record(ElnaTreeNode) - types: ^ElnaTreeDeclaration; - globals: ^ElnaTreeVariableDeclaration; - procedures: ^ElnaTreeProcedureDeclaration; - body: ^ElnaTreeStatement - end - -proc elna_list_initialize*(list: ^ElnaList) -begin - list^.first := nil; - list^.last := nil -return - -proc elna_list_append*(list: ^ElnaList; element: ^ElnaListNode) -> ^ElnaListNode -begin - if element <> nil then - if list^.first = nil then - list^.first := element - else - list^.last^.next := element - end; - list^.last := element - end -return element - -proc elna_list_prepend*(list: ^ElnaList; element: ^ElnaListNode) -begin - element^.next := list^.first; - list^.first := element; - if list^.last = nil then - list^.last := element - end -return - -proc elna_list_insert*(list: ^ElnaList; existing, new: ^ElnaListNode) -begin - if existing^.next = nil then - list^.last := new - else - new^.next := existing^.next - end; - existing^.next := new -return - -proc elna_list_empty*(list: ^ElnaList) -> Bool -return list^.first = nil - -end. diff --git a/source/command_line_interface.elna b/source/command_line_interface.elna deleted file mode 100644 index 4c3c1a6..0000000 --- a/source/command_line_interface.elna +++ /dev/null @@ -1,89 +0,0 @@ -(* 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/. *) -(* - Command line handling. -*) -module -import sys.posix.cstdlib, sys.posix.cstring, common - -type - CommandLine* = record - input: ^Word8; - output: ^Word8; - lex: Bool; - parse: Bool - end - -proc parse_command_line*(argc: Int; argv: ^^Word8) -> ^CommandLine -var - parameter: ^Word8 - i: Int - result: ^CommandLine - parsed: Bool -begin - i := 1; - result := malloc#[CommandLine](#size(CommandLine)); - result^.lex := false; - result^.parse := false; - result^.input := nil; - result^.output := nil; - - while i < argc & result <> nil do - parameter := (argv + i)^; - parsed := false; - - if strcmp(parameter, "--lex\0".ptr) = 0 then - parsed := true; - result^.lex := true - end; - if strcmp(parameter, "--parse\0".ptr) = 0 then - parsed := true; - result^.parse := true - end; - if strcmp(parameter, "-o\0".ptr) = 0 then - i := i + 1; - - if i = argc then - write_s("Fatal error: expecting a file name following -o."); - result := nil - end; - if i < argc then - parameter := (argv + i)^; - result^.output := parameter - end; - parsed := true - end; - if (parameter^ <> '-') & ~parsed then - parsed := true; - - if result^.input <> nil then - write_s("Fatal error: only one source file can be compiled at once. First given \""); - write_z(result^.input); - write_s("\", then \""); - write_z(parameter); - write_s("\".\n"); - result := nil - end; - if result <> nil then - result^.input := parameter - end - end; - if ~parsed then - write_s("Fatal error: unknown command line options: "); - - write_z(parameter); - write_s(".\n"); - - result := nil - end; - - i := i + 1 - end; - if result <> nil & result^.input = nil then - write_s("Fatal error: no input files.\n"); - result := nil - end -return result - -end. diff --git a/source/common.elna b/source/common.elna deleted file mode 100644 index 93b4363..0000000 --- a/source/common.elna +++ /dev/null @@ -1,88 +0,0 @@ -(* 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 sys.posix.cstring, sys.posix.cstdio, sys.posix.cstdlib - -type - ElnaLocation* = record - line: Word; - column: Word - end - ElnaPosition* = record - start_location: ElnaLocation; - end_location: ElnaLocation - end - -proc write*#[T](fd: Int; buf: ^const T; size: Word) -> Int -extern - -proc write_s*(value: []const Word8) - write(1, value.ptr, value.length) -return - -proc write_z*(value: ^Word8) - write(1, value, strlen(value)) -return - -proc write_b*(value: Bool) - if value then - write_s("true") - else - write_s("false") - end -return - -proc write_c*(value: Word8) - putchar(cast(value: Int)); - fflush(nil) -return - -proc write_i*(value: Int) -var - digit: Int - n: Word - buffer: [10]Word8 -begin - n := 10u; - - if value = 0 then - write_c('0') - end; - while value <> 0 do - digit := value % 10; - value := value / 10; - - buffer[n] := cast(cast('0': Int) + digit: Word8); - n := n - 1u - end; - while n < 10u do - n := n + 1u; - write_c(buffer[n]) - end -return - -proc write_u*(value: Word) - write_i(cast(value: Int)) -return - -(* Returns true or false depending whether two strings are equal. *) -proc string_compare*(lhs_pointer: ^Word8; lhs_length: Word; rhs_pointer: []const Word8) -> Bool -var - result: Bool -begin - if lhs_length = rhs_pointer.length then - result := memcmp(lhs_pointer, rhs_pointer.ptr, lhs_length) = 0 - else - result := false - end -return result - -proc free_and_nil*#[T](ptr: ^T) -> ^T -begin - if ptr <> nil then - free(ptr) - end -return nil - -end. diff --git a/source/diagnostic.elna b/source/diagnostic.elna deleted file mode 100644 index 2356544..0000000 --- a/source/diagnostic.elna +++ /dev/null @@ -1,241 +0,0 @@ -(* 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 common, sys.posix.cstdio, sys.posix.cstdlib, lexer, ast - -type - ElnaErrorKind* = ( - unexpected_token, - undefined_symbol, - undefined_member, - duplicate_declaration - ) - ElnaError* = record(ElnaListNode) - kind: ElnaErrorKind; - position: ElnaPosition - end - ElnaErrorUnexpectedToken* = record(ElnaError) - expected: [16]ElnaLexerKind; - possibilities: Word; - got: ElnaLexerKind - end - ElnaErrorUndefinedSymbol* = record(ElnaError) - symbol_name: []const Word8 - end - ElnaErrorUndefinedMember* = record(ElnaError) - aggregate_name: []const Word8; - member_name: []const Word8 - end - ElnaErrorDuplicateDeclaration* = record(ElnaError) - symbol_name: []const Word8 - end - -proc elna_error_unexpected_token_create*(cursor: ^ElnaLexerCursor; number_of_expected: Word) -> ^ElnaErrorUnexpectedToken -var - parser_error: ^ElnaErrorUnexpectedToken -begin - parser_error := malloc#[ElnaErrorUnexpectedToken](#size(ElnaErrorUnexpectedToken)); - parser_error^.next := nil; - parser_error^.kind := ElnaErrorKind.unexpected_token; - parser_error^.position := cursor^.position; - parser_error^.possibilities := number_of_expected; - parser_error^.got := cursor^.token^.kind -return parser_error - -proc elna_error_duplicate_declaration_create*(position: ElnaPosition; symbol_name: []const Word8) -> ^ElnaErrorDuplicateDeclaration -var - declaration_error: ^ElnaErrorDuplicateDeclaration -begin - declaration_error := malloc#[ElnaErrorDuplicateDeclaration](#size(ElnaErrorDuplicateDeclaration)); - declaration_error^.next := nil; - declaration_error^.kind := ElnaErrorKind.duplicate_declaration; - declaration_error^.position := position; - declaration_error^.symbol_name := symbol_name -return declaration_error - -proc elna_error_undefined_symbol_create*(position: ElnaPosition; symbol_name: []const Word8) -> ^ElnaErrorUndefinedSymbol -var - result: ^ElnaErrorUndefinedSymbol -begin - result := malloc#[ElnaErrorUndefinedSymbol](#size(ElnaErrorUndefinedSymbol)); - result^.next := nil; - result^.kind := ElnaErrorKind.undefined_symbol; - result^.position := position; - result^.symbol_name := symbol_name -return result - -proc elna_error_undefined_member_create*(position: ElnaPosition; aggregate, member: []const Word8) -> ^ElnaErrorUndefinedMember -var - result: ^ElnaErrorUndefinedMember -begin - result := malloc#[ElnaErrorUndefinedMember](#size(ElnaErrorUndefinedMember)); - result^.next := nil; - result^.kind := ElnaErrorKind.undefined_member; - result^.position := position; - result^.aggregate_name := aggregate; - result^.member_name := member -return result - -proc elna_error_print_token*(kind: ElnaLexerKind) -begin - case kind of - ElnaLexerKind._const: - write_s("\"const\"") - | ElnaLexerKind._var: - write_s("\"var\"") - | ElnaLexerKind._proc: - write_s("\"proc\"") - | ElnaLexerKind._type: - write_s("\"type\"") - | ElnaLexerKind._begin: - write_s("\"begin\"") - | ElnaLexerKind._end: - write_s("\"end\"") - | ElnaLexerKind._if: - write_s("\"if\"") - | ElnaLexerKind._then: - write_s("\"then\"") - | ElnaLexerKind._else: - write_s("\"else\"") - | ElnaLexerKind._elsif: - write_s("\"elsif\"") - | ElnaLexerKind._extern: - write_s("\"extern\"") - | ElnaLexerKind._record: - write_s("\"record\"") - | ElnaLexerKind.boolean: - write_s("BOOLEAN") - | ElnaLexerKind.null: - write_s("NIL") - | ElnaLexerKind.and: - write_s("\"&\"") - | ElnaLexerKind._or: - write_s("\"or\"") - | ElnaLexerKind._xor: - write_s("\"xor\"") - | ElnaLexerKind.not: - write_s("\"~\"") - | ElnaLexerKind._return: - write_s("\"return\"") - | ElnaLexerKind._cast: - write_s("\"cast\"") - | ElnaLexerKind.trait: - write_s("TRAIT") - | ElnaLexerKind.left_paren: - write_s("\"(\"") - | ElnaLexerKind.right_paren: - write_s("\")\"") - | ElnaLexerKind.left_square: - write_s("\"[\"") - | ElnaLexerKind.right_square: - write_s("\"]\"") - | ElnaLexerKind.greater_equal: - write_s("\">=\"") - | ElnaLexerKind.less_equal: - write_s("\"<=\"") - | ElnaLexerKind.greater_than: - write_s("\">\"") - | ElnaLexerKind.less_than: - write_s("\"<\"") - | ElnaLexerKind.not_equal: - write_s("\"<>\"") - | ElnaLexerKind.equals: - write_s("\"=\"") - | ElnaLexerKind.semicolon: - write_s("\";\"") - | ElnaLexerKind.dot: - write_s("\".\"") - | ElnaLexerKind.comma: - write_s("\",\"") - | ElnaLexerKind.plus: - write_s("\"+\"") - | ElnaLexerKind.arrow: - write_s("\"->\"") - | ElnaLexerKind.minus: - write_s("\"-\"") - | ElnaLexerKind.multiplication: - write_s("\"*\"") - | ElnaLexerKind.division: - write_s("\"/\"") - | ElnaLexerKind.remainder: - write_s("\"%\"") - | ElnaLexerKind.assignment: - write_s("\":=\"") - | ElnaLexerKind.colon: - write_s("\":\"") - | ElnaLexerKind.hat: - write_s("\"^\"") - | ElnaLexerKind.at: - write_s("\"@\"") - | ElnaLexerKind.comment: - write_s("COMMENT") - | ElnaLexerKind.string: - write_s("STRING") - | ElnaLexerKind.character: - write_s("CHARACTER") - | ElnaLexerKind.integer: - write_s("INTEGER") - | ElnaLexerKind.word: - write_s("WORD") - | ElnaLexerKind.eof: - write_s("EOF") - else - write_s("UNKNOWN") - end -return - -proc elna_error_print_unexpected_token*(current_error: ^ElnaErrorUnexpectedToken) -begin - write_s("Parse error: Expecting token "); - elna_error_print_token(current_error^.expected[1]); - write_s("; got "); - elna_error_print_token(current_error^.got); - write_s(". ") -return - -proc elna_error_print_undefined_member*(current_error: ^ElnaErrorUndefinedMember) -begin - write_s("Semantic error: Member \""); - write_s(current_error^.member_name); - write_s("\" is not accessible on \""); - write_s(current_error^.aggregate_name); - write_s("\". ") -return - -proc elna_error_print_undefined_symbol*(current_error: ^ElnaErrorUndefinedSymbol) -begin - write_s("Semantic error: Undefined symbol \""); - write_s(current_error^.symbol_name); - write_s("\". ") -return - -proc elna_error_print_duplicate_declaration*(current_error: ^ElnaErrorDuplicateDeclaration) -begin - write_s("Semantic error: Duplicate declaration \""); - write_s(current_error^.symbol_name); - write_s("\". ") -return - -proc elna_error_print*(current_error: ^ElnaError) -begin - case current_error^.kind of - ElnaErrorKind.unexpected_token: - elna_error_print_unexpected_token(cast(current_error: ^ElnaErrorUnexpectedToken)) - | ElnaErrorKind.undefined_symbol: - elna_error_print_undefined_symbol(cast(current_error: ^ElnaErrorUndefinedSymbol)) - | ElnaErrorKind.undefined_member: - elna_error_print_undefined_member(cast(current_error: ^ElnaErrorUndefinedMember)) - | ElnaErrorKind.duplicate_declaration: - elna_error_print_duplicate_declaration(cast(current_error: ^ElnaErrorDuplicateDeclaration)) - else - write_s("Unknown error. ") - end; - write_s("Line "); - write_u(current_error^.position.start_location.line); - write_s(", column "); - write_u(current_error^.position.start_location.column); - write_s(".\n") -return - -end. diff --git a/source/lexer.elna b/source/lexer.elna deleted file mode 100644 index 71e76a7..0000000 --- a/source/lexer.elna +++ /dev/null @@ -1,815 +0,0 @@ -(* 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 sys.posix.cstdio, common, sys.posix.cstdlib - -type - ElnaLexerState* = ( - start, - colon, - identifier, - decimal, - leading_zero, - greater, - minus, - left_paren, - less, - dot, - comment, - closing_comment, - character, - character_escape, - string, - string_escape, - number_sign, - trait, - finish - ) - ElnaLexerToken* = record - kind: ElnaLexerKind; - start: []const Word8; - position: ElnaPosition - end - ElnaLexerBooleanToken* = record(ElnaLexerToken) - value: Bool - end - ElnaLexerCharacterToken* = record(ElnaLexerToken) - value: Word8 - end - ElnaLexerStringToken* = record(ElnaLexerToken) - value: []const Word8 - end - ElnaLexerIntegerToken* = record(ElnaLexerToken) - value: Int - end - - TransitionAction = proc(lexer: ^Lexer; token: ^ElnaLexerToken) - ElnaLexerAction = (none, accumulate, skip, single, eof, finalize, composite, key_id, integer, delimited) - - ElnaLexerTransition = record - action: ElnaLexerAction; - next_state: ElnaLexerState - end - - ElnaLexerCursor* = record - state: ElnaLexerState; - start: ^Word8; - finish: ^Word8; - token: ^ElnaLexerToken; - position: ElnaPosition - end - - BufferPosition* = record - iterator: ^Word8; - location: ElnaLocation - end - Lexer* = record - input: ^FILE; - buffer: ^Word8; - size: Word; - length: Word; - start: BufferPosition; - current: BufferPosition - end - ElnaLexerKind* = ( - identifier, - _const, - _var, - _proc, - _type, - _begin, - _end, - _if, - _then, - _else, - _elsif, - _extern, - _record, - boolean, - null, - and, - _or, - _xor, - not, - _return, - _cast, - trait, - left_paren, - right_paren, - left_square, - right_square, - left_brace, - right_brace, - greater_equal, - less_equal, - greater_than, - less_than, - not_equal, - equals, - semicolon, - dot, - comma, - plus, - _import, - minus, - multiplication, - division, - remainder, - assignment, - colon, - hat, - at, - comment, - string, - character, - integer, - word, - _while, - _defer, - exclamation, - shift_right, - shift_left, - pipe, - _case, - _do, - _of, - arrow, - eof - ) - (** - * Classification table assigns each possible character to a group (class). All - * characters of the same group a handled equivalently. - *) - ElnaLexerClass = ( - invalid, - digit, - alpha, - space, - colon, - equals, - left_paren, - right_paren, - asterisk, - backslash, - single, - hex, - zero, - x, - eof, - dot, - minus, - single_quote, - double_quote, - greater, - less, - other, - number_sign - ) - -var - classification: [256]ElnaLexerClass - transition_table: [19][23]ElnaLexerTransition - -proc elna_lexer_classifications1() -begin - classification[1] := ElnaLexerClass.eof; - classification[10] := ElnaLexerClass.space; - classification[11] := ElnaLexerClass.space; - classification[14] := ElnaLexerClass.space; - classification[33] := ElnaLexerClass.space; - classification[34] := ElnaLexerClass.single -return - -proc elna_lexer_classifications2() -begin - classification[35] := ElnaLexerClass.double_quote; - classification[36] := ElnaLexerClass.number_sign; - classification[37] := ElnaLexerClass.other; - classification[38] := ElnaLexerClass.single; - classification[39] := ElnaLexerClass.single; - classification[40] := ElnaLexerClass.single_quote; - classification[41] := ElnaLexerClass.left_paren; - classification[42] := ElnaLexerClass.right_paren; - classification[43] := ElnaLexerClass.asterisk; - classification[44] := ElnaLexerClass.single; - classification[45] := ElnaLexerClass.single; - classification[46] := ElnaLexerClass.minus; - classification[47] := ElnaLexerClass.dot; - classification[48] := ElnaLexerClass.single; - classification[49] := ElnaLexerClass.zero; - classification[50] := ElnaLexerClass.digit; - classification[51] := ElnaLexerClass.digit; - classification[52] := ElnaLexerClass.digit; - classification[53] := ElnaLexerClass.digit; - classification[54] := ElnaLexerClass.digit; - classification[55] := ElnaLexerClass.digit; - classification[56] := ElnaLexerClass.digit; - classification[57] := ElnaLexerClass.digit; - classification[58] := ElnaLexerClass.digit; - classification[59] := ElnaLexerClass.colon; - classification[60] := ElnaLexerClass.single; - classification[61] := ElnaLexerClass.less; - classification[62] := ElnaLexerClass.equals; - classification[63] := ElnaLexerClass.greater; - classification[64] := ElnaLexerClass.other -return - -proc elna_lexer_classifications3() -begin - classification[65] := ElnaLexerClass.single; - classification[66] := ElnaLexerClass.alpha; - classification[67] := ElnaLexerClass.alpha; - classification[68] := ElnaLexerClass.alpha; - classification[69] := ElnaLexerClass.alpha; - classification[70] := ElnaLexerClass.alpha; - classification[71] := ElnaLexerClass.alpha; - classification[72] := ElnaLexerClass.alpha; - classification[73] := ElnaLexerClass.alpha; - classification[74] := ElnaLexerClass.alpha; - classification[75] := ElnaLexerClass.alpha; - classification[76] := ElnaLexerClass.alpha; - classification[77] := ElnaLexerClass.alpha; - classification[78] := ElnaLexerClass.alpha; - classification[79] := ElnaLexerClass.alpha; - classification[80] := ElnaLexerClass.alpha; - classification[81] := ElnaLexerClass.alpha; - classification[82] := ElnaLexerClass.alpha; - classification[83] := ElnaLexerClass.alpha; - classification[84] := ElnaLexerClass.alpha; - classification[85] := ElnaLexerClass.alpha; - classification[86] := ElnaLexerClass.alpha; - classification[87] := ElnaLexerClass.alpha; - classification[88] := ElnaLexerClass.alpha; - classification[89] := ElnaLexerClass.alpha; - classification[90] := ElnaLexerClass.alpha; - classification[91] := ElnaLexerClass.alpha; - classification[92] := ElnaLexerClass.single; - classification[93] := ElnaLexerClass.backslash; - classification[94] := ElnaLexerClass.single; - classification[95] := ElnaLexerClass.single; - classification[96] := ElnaLexerClass.alpha; - classification[97] := ElnaLexerClass.other; - classification[98] := ElnaLexerClass.hex -return - -proc elna_lexer_classifications4() -begin - classification[99] := ElnaLexerClass.hex; - classification[100] := ElnaLexerClass.hex; - classification[101] := ElnaLexerClass.hex; - classification[102] := ElnaLexerClass.hex; - classification[103] := ElnaLexerClass.hex; - classification[104] := ElnaLexerClass.alpha; - classification[105] := ElnaLexerClass.alpha; - classification[106] := ElnaLexerClass.alpha; - classification[107] := ElnaLexerClass.alpha; - classification[108] := ElnaLexerClass.alpha; - classification[109] := ElnaLexerClass.alpha; - classification[110] := ElnaLexerClass.alpha; - classification[111] := ElnaLexerClass.alpha; - classification[112] := ElnaLexerClass.alpha; - classification[113] := ElnaLexerClass.alpha; - classification[114] := ElnaLexerClass.alpha; - classification[115] := ElnaLexerClass.alpha; - classification[116] := ElnaLexerClass.alpha; - classification[117] := ElnaLexerClass.alpha; - classification[118] := ElnaLexerClass.alpha; - classification[119] := ElnaLexerClass.alpha; - classification[120] := ElnaLexerClass.alpha; - classification[121] := ElnaLexerClass.x; - classification[122] := ElnaLexerClass.alpha; - classification[123] := ElnaLexerClass.alpha; - classification[124] := ElnaLexerClass.other; - classification[125] := ElnaLexerClass.single; - classification[126] := ElnaLexerClass.other; - classification[127] := ElnaLexerClass.single -return - -(** - * Initializes the array with character classes. - *) -proc elna_lexer_classifications() -var - code: Word -begin - code := 1u; - - (* Set everything by default to invalid. *) - while code < 129u do - classification[code] := ElnaLexerClass.invalid; - code := code + 1u - end; - - elna_lexer_classifications1(); - elna_lexer_classifications2(); - elna_lexer_classifications3(); - elna_lexer_classifications4(); - - (* Set the remaining 129 - 256 bytes to transitionClassOther. *) - while code < 257u do - classification[code] := ElnaLexerClass.other; - code := code + 1u - end -return - -proc elna_lexer_get_transition(current_state: ElnaLexerState; character_class: ElnaLexerClass) -> ^ElnaLexerTransition - (* Each state is 8 bytes long (2 words: action and next state). - There are 23 character classes, so a transition row 8 * 23 = 184 bytes long. *) -return @transition_table[cast(current_state: Word)][cast(character_class: Word)] - -(** - * Parameters: - * current_state - First index into transitions table. - * character_class - Second index into transitions table. - * action - Action to assign. - * next_state - Next state to assign. - *) -proc elna_lexer_set_transition(current_state: ElnaLexerState; character_class: ElnaLexerClass; - action: ElnaLexerAction; next_state: ElnaLexerState) -var - transition: ^ElnaLexerTransition -begin - transition := elna_lexer_get_transition(current_state, character_class); - - transition^.action := action; - transition^.next_state := next_state -return - -(** - * Sets same action and state transition for all character classes in one transition row. - * - * Parameters: - * current_state - Current state (Transition state enumeration). - * default_action - Default action (Callback). - * next_state - Next state (Transition state enumeration). - *) -proc elna_lexer_default_transition(current_state: ElnaLexerState; default_action: ElnaLexerAction; - next_state: ElnaLexerState) -begin - elna_lexer_set_transition(current_state, ElnaLexerClass.invalid, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.digit, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.alpha, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.space, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.colon, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.equals, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.left_paren, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.right_paren, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.asterisk, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.backslash, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.single, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.hex, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.zero, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.x, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.eof, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.dot, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.minus, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.single_quote, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.double_quote, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.greater, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.less, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.other, default_action, next_state); - elna_lexer_set_transition(current_state, ElnaLexerClass.number_sign, default_action, next_state) -return - -(** - * The transition table describes transitions from one state to another, given - * a symbol (character class). - * - * The table has m rows and n columns, where m is the amount of states and n is - * the amount of classes. So given the current state and a classified character - * the table can be used to look up the next state. - *) -proc elna_lexer_transitions() -begin - (* Start state. *) - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.invalid, ElnaLexerAction.none, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.digit, ElnaLexerAction.accumulate, ElnaLexerState.decimal); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.alpha, ElnaLexerAction.accumulate, ElnaLexerState.identifier); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.space, ElnaLexerAction.skip, ElnaLexerState.start); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.colon, ElnaLexerAction.accumulate, ElnaLexerState.colon); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.equals, ElnaLexerAction.single, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.left_paren, ElnaLexerAction.accumulate, ElnaLexerState.left_paren); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.right_paren, ElnaLexerAction.single, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.asterisk, ElnaLexerAction.single, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.backslash, ElnaLexerAction.none, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.single, ElnaLexerAction.single, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.hex, ElnaLexerAction.accumulate, ElnaLexerState.identifier); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.zero, ElnaLexerAction.accumulate, ElnaLexerState.leading_zero); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.x, ElnaLexerAction.accumulate, ElnaLexerState.identifier); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.eof, ElnaLexerAction.eof, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.dot, ElnaLexerAction.single, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.minus, ElnaLexerAction.accumulate, ElnaLexerState.minus); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.single_quote, ElnaLexerAction.accumulate, ElnaLexerState.character); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.double_quote, ElnaLexerAction.accumulate, ElnaLexerState.string); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.greater, ElnaLexerAction.accumulate, ElnaLexerState.greater); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.less, ElnaLexerAction.accumulate, ElnaLexerState.less); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.other, ElnaLexerAction.none, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.number_sign, ElnaLexerAction.accumulate, ElnaLexerState.number_sign); - - (* Colon state. *) - elna_lexer_default_transition(ElnaLexerState.colon, ElnaLexerAction.finalize, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.colon, ElnaLexerClass.equals, ElnaLexerAction.composite, ElnaLexerState.finish); - - (* Identifier state. *) - elna_lexer_default_transition(ElnaLexerState.identifier, ElnaLexerAction.key_id, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.identifier, ElnaLexerClass.digit, ElnaLexerAction.accumulate, ElnaLexerState.identifier); - elna_lexer_set_transition(ElnaLexerState.identifier, ElnaLexerClass.alpha, ElnaLexerAction.accumulate, ElnaLexerState.identifier); - elna_lexer_set_transition(ElnaLexerState.identifier, ElnaLexerClass.hex, ElnaLexerAction.accumulate, ElnaLexerState.identifier); - elna_lexer_set_transition(ElnaLexerState.identifier, ElnaLexerClass.zero, ElnaLexerAction.accumulate, ElnaLexerState.identifier); - elna_lexer_set_transition(ElnaLexerState.identifier, ElnaLexerClass.x, ElnaLexerAction.accumulate, ElnaLexerState.identifier); - - (* Decimal state. *) - elna_lexer_default_transition(ElnaLexerState.decimal, ElnaLexerAction.integer, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.decimal, ElnaLexerClass.digit, ElnaLexerAction.accumulate, ElnaLexerState.decimal); - elna_lexer_set_transition(ElnaLexerState.decimal, ElnaLexerClass.alpha, ElnaLexerAction.none, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.decimal, ElnaLexerClass.hex, ElnaLexerAction.none, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.decimal, ElnaLexerClass.zero, ElnaLexerAction.accumulate, ElnaLexerState.decimal); - elna_lexer_set_transition(ElnaLexerState.decimal, ElnaLexerClass.x, ElnaLexerAction.none, ElnaLexerState.finish); - - (* Leading zero. *) - elna_lexer_default_transition(ElnaLexerState.leading_zero, ElnaLexerAction.integer, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.leading_zero, ElnaLexerClass.digit, ElnaLexerAction.none, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.leading_zero, ElnaLexerClass.alpha, ElnaLexerAction.none, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.leading_zero, ElnaLexerClass.hex, ElnaLexerAction.none, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.leading_zero, ElnaLexerClass.zero, ElnaLexerAction.none, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.leading_zero, ElnaLexerClass.x, ElnaLexerAction.none, ElnaLexerState.dot); - - (* Greater state. *) - elna_lexer_default_transition(ElnaLexerState.greater, ElnaLexerAction.finalize, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.greater, ElnaLexerClass.equals, ElnaLexerAction.composite, ElnaLexerState.finish); - - (* Minus state. *) - elna_lexer_default_transition(ElnaLexerState.minus, ElnaLexerAction.finalize, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.minus, ElnaLexerClass.greater, ElnaLexerAction.composite, ElnaLexerState.finish); - - (* Left paren state. *) - elna_lexer_default_transition(ElnaLexerState.left_paren, ElnaLexerAction.finalize, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.left_paren, ElnaLexerClass.asterisk, ElnaLexerAction.accumulate, ElnaLexerState.comment); - - (* Less state. *) - elna_lexer_default_transition(ElnaLexerState.less, ElnaLexerAction.finalize, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.less, ElnaLexerClass.equals, ElnaLexerAction.composite, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.less, ElnaLexerClass.greater, ElnaLexerAction.composite, ElnaLexerState.finish); - - (* Hexadecimal after 0x. *) - elna_lexer_default_transition(ElnaLexerState.dot, ElnaLexerAction.finalize, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.dot, ElnaLexerClass.dot, ElnaLexerAction.composite, ElnaLexerState.finish); - - (* Comment. *) - elna_lexer_default_transition(ElnaLexerState.comment, ElnaLexerAction.accumulate, ElnaLexerState.comment); - elna_lexer_set_transition(ElnaLexerState.comment, ElnaLexerClass.asterisk, ElnaLexerAction.accumulate, ElnaLexerState.closing_comment); - elna_lexer_set_transition(ElnaLexerState.comment, ElnaLexerClass.eof, ElnaLexerAction.none, ElnaLexerState.finish); - - (* Closing comment. *) - elna_lexer_default_transition(ElnaLexerState.closing_comment, ElnaLexerAction.accumulate, ElnaLexerState.comment); - elna_lexer_set_transition(ElnaLexerState.closing_comment, ElnaLexerClass.invalid, ElnaLexerAction.none, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.closing_comment, ElnaLexerClass.right_paren, ElnaLexerAction.delimited, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.closing_comment, ElnaLexerClass.asterisk, ElnaLexerAction.accumulate, ElnaLexerState.closing_comment); - elna_lexer_set_transition(ElnaLexerState.closing_comment, ElnaLexerClass.eof, ElnaLexerAction.none, ElnaLexerState.finish); - - (* Character. *) - elna_lexer_default_transition(ElnaLexerState.character, ElnaLexerAction.accumulate, ElnaLexerState.character); - elna_lexer_set_transition(ElnaLexerState.character, ElnaLexerClass.invalid, ElnaLexerAction.none, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.character, ElnaLexerClass.eof, ElnaLexerAction.none, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.character, ElnaLexerClass.single_quote, ElnaLexerAction.delimited, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.character, ElnaLexerClass.backslash, ElnaLexerAction.accumulate, ElnaLexerState.character_escape); - - (* Escape sequence in a character. *) - elna_lexer_default_transition(ElnaLexerState.character_escape, ElnaLexerAction.accumulate, ElnaLexerState.character); - elna_lexer_set_transition(ElnaLexerState.character_escape, ElnaLexerClass.invalid, ElnaLexerAction.none, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.character_escape, ElnaLexerClass.eof, ElnaLexerAction.none, ElnaLexerState.finish); - - (* String. *) - elna_lexer_default_transition(ElnaLexerState.string, ElnaLexerAction.accumulate, ElnaLexerState.string); - elna_lexer_set_transition(ElnaLexerState.string, ElnaLexerClass.invalid, ElnaLexerAction.none, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.string, ElnaLexerClass.eof, ElnaLexerAction.none, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.string, ElnaLexerClass.double_quote, ElnaLexerAction.delimited, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.string, ElnaLexerClass.backslash, ElnaLexerAction.accumulate, ElnaLexerState.string_escape); - - (* Escape sequence in a string. *) - elna_lexer_default_transition(ElnaLexerState.string_escape, ElnaLexerAction.accumulate, ElnaLexerState.string); - elna_lexer_set_transition(ElnaLexerState.string_escape, ElnaLexerClass.invalid, ElnaLexerAction.none, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.string_escape, ElnaLexerClass.eof, ElnaLexerAction.none, ElnaLexerState.finish); - - (* Number sign state. *) - elna_lexer_default_transition(ElnaLexerState.number_sign, ElnaLexerAction.key_id, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.number_sign, ElnaLexerClass.alpha, ElnaLexerAction.accumulate, ElnaLexerState.trait); - elna_lexer_set_transition(ElnaLexerState.number_sign, ElnaLexerClass.hex, ElnaLexerAction.accumulate, ElnaLexerState.trait); - elna_lexer_set_transition(ElnaLexerState.number_sign, ElnaLexerClass.x, ElnaLexerAction.accumulate, ElnaLexerState.trait); - - (* Trait state. *) - elna_lexer_default_transition(ElnaLexerState.trait, ElnaLexerAction.key_id, ElnaLexerState.finish); - elna_lexer_set_transition(ElnaLexerState.trait, ElnaLexerClass.digit, ElnaLexerAction.accumulate, ElnaLexerState.trait); - elna_lexer_set_transition(ElnaLexerState.trait, ElnaLexerClass.alpha, ElnaLexerAction.accumulate, ElnaLexerState.trait); - elna_lexer_set_transition(ElnaLexerState.trait, ElnaLexerClass.hex, ElnaLexerAction.accumulate, ElnaLexerState.trait); - elna_lexer_set_transition(ElnaLexerState.trait, ElnaLexerClass.zero, ElnaLexerAction.accumulate, ElnaLexerState.trait); - elna_lexer_set_transition(ElnaLexerState.trait, ElnaLexerClass.x, ElnaLexerAction.accumulate, ElnaLexerState.trait) -return - -proc elna_lexer_advance(cursor: ^ElnaLexerCursor) -begin - cursor^.finish := cursor^.finish + 1; - cursor^.position.end_location.column := cursor^.position.end_location.column + 1u -return - -proc elna_lexer_classify_space(start_position: ^Word8; location: ^ElnaLocation) -begin - if start_position^ = '\n' then - location^.line := location^.line + 1u; - location^.column := 1u - else - location^.column := location^.column + 1u - end -return - -proc elna_lexer_token_create(kind: ElnaLexerKind; position: ^ElnaPosition) -> ^ElnaLexerToken -var - result: ^ElnaLexerToken -begin - result := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - result^.kind := kind; - result^.position := position^ -return result - -proc elna_lexer_classify_keyword(position_start, position_end: ^Word8; position: ^ElnaPosition) -> ^ElnaLexerToken -var - result: ^ElnaLexerToken - result_length: Word -begin - result_length := cast(position_end - position_start: Word); - - result := elna_lexer_token_create(ElnaLexerKind.identifier, position); - result^.start := position_start[1 to result_length]; - - if position_start^ = '#' then - result^.kind := ElnaLexerKind.trait - elsif string_compare(position_start, result_length, "const") then - result^.kind := ElnaLexerKind._const - elsif string_compare(position_start, result_length, "var") then - result^.kind := ElnaLexerKind._var - elsif string_compare(position_start, result_length, "proc") then - result^.kind := ElnaLexerKind._proc - elsif string_compare(position_start, result_length, "type") then - result^.kind := ElnaLexerKind._type - elsif string_compare(position_start, result_length, "begin") then - result^.kind := ElnaLexerKind._begin - elsif string_compare(position_start, result_length, "end") then - result^.kind := ElnaLexerKind._end - elsif string_compare(position_start, result_length, "return") then - result^.kind := ElnaLexerKind._return - elsif string_compare(position_start, result_length, "defer") then - result^.kind := ElnaLexerKind._defer - elsif string_compare(position_start, result_length, "if") then - result^.kind := ElnaLexerKind._if - elsif string_compare(position_start, result_length, "extern") then - result^.kind := ElnaLexerKind._extern - elsif string_compare(position_start, result_length, "then") then - result^.kind := ElnaLexerKind._then - elsif string_compare(position_start, result_length, "else") then - result^.kind := ElnaLexerKind._else - elsif string_compare(position_start, result_length, "elsif") then - result^.kind := ElnaLexerKind._elsif - elsif string_compare(position_start, result_length, "record") then - result^.kind := ElnaLexerKind._record - elsif string_compare(position_start, result_length, "or") then - result^.kind := ElnaLexerKind._or - elsif string_compare(position_start, result_length, "xor") then - result^.kind := ElnaLexerKind._xor - elsif string_compare(position_start, result_length, "nil") then - result^.kind := ElnaLexerKind.null - elsif string_compare(position_start, result_length, "true") then - result^.kind := ElnaLexerKind.boolean - elsif string_compare(position_start, result_length, "false") then - result^.kind := ElnaLexerKind.boolean - elsif string_compare(position_start, result_length, "cast") then - result^.kind := ElnaLexerKind._cast - end -return result - -proc elna_lexer_classify_delimited(start_position, end_position: ^Word8; position: ^ElnaPosition) -> ^ElnaLexerToken -var - delimiter: Word8 - result: ^ElnaLexerToken -begin - delimiter := start_position^; - - if delimiter = '(' then - result := elna_lexer_token_create(ElnaLexerKind.comment, position) - elsif delimiter = '\'' then - result := elna_lexer_token_create(ElnaLexerKind.character, position) - elsif delimiter = '"' then - result := elna_lexer_token_create(ElnaLexerKind.string, position) - end; - result^.start := start_position[1 to cast(end_position - start_position: Word)] -return result - -proc elna_lexer_classify_integer(start_position, end_position: ^Word8; position: ^ElnaPosition) -> ^ElnaLexerToken -var - result: ^ElnaLexerToken -begin - result := elna_lexer_token_create(ElnaLexerKind.integer, position); - result^.start := start_position[1 to cast(end_position - start_position: Word)] -return result - -proc elna_lexer_classify_finalize(start_position: ^Word8; position: ^ElnaPosition) -> ^ElnaLexerToken -var - character: Word8 - result: ^ElnaLexerToken -begin - character := start_position^; - - if character = ':' then - result := elna_lexer_token_create(ElnaLexerKind.colon, position) - elsif character = '.' then - result := elna_lexer_token_create(ElnaLexerKind.dot, position) - elsif character = '(' then - result := elna_lexer_token_create(ElnaLexerKind.left_paren, position) - elsif character = '-' then - result := elna_lexer_token_create(ElnaLexerKind.minus, position) - elsif character = '<' then - result := elna_lexer_token_create(ElnaLexerKind.less_than, position) - elsif character = '>' then - result := elna_lexer_token_create(ElnaLexerKind.greater_than, position) - end -return result - -proc elna_lexer_classify_single(start_position: ^Word8; position: ^ElnaPosition) -> ^ElnaLexerToken -var - character: Word8 - result: ^ElnaLexerToken -begin - result := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - character := start_position^; - - if character = ';' then - result := elna_lexer_token_create(ElnaLexerKind.semicolon, position) - elsif character = ',' then - result := elna_lexer_token_create(ElnaLexerKind.comma, position) - elsif character = ')' then - result := elna_lexer_token_create(ElnaLexerKind.right_paren, position) - elsif character = '@' then - result := elna_lexer_token_create(ElnaLexerKind.at, position) - elsif character = '~' then - result := elna_lexer_token_create(ElnaLexerKind.not, position) - elsif character = '&' then - result := elna_lexer_token_create(ElnaLexerKind.and, position) - elsif character = '+' then - result := elna_lexer_token_create(ElnaLexerKind.plus, position) - elsif character = '*' then - result := elna_lexer_token_create(ElnaLexerKind.multiplication, position) - elsif character = '=' then - result := elna_lexer_token_create(ElnaLexerKind.equals, position) - elsif character = '%' then - result := elna_lexer_token_create(ElnaLexerKind.remainder, position) - elsif character = '/' then - result := elna_lexer_token_create(ElnaLexerKind.division, position) - elsif character = '.' then - result := elna_lexer_token_create(ElnaLexerKind.dot, position) - elsif character = '^' then - result := elna_lexer_token_create(ElnaLexerKind.hat, position) - elsif character = '[' then - result := elna_lexer_token_create(ElnaLexerKind.left_square, position) - elsif character = ']' then - result := elna_lexer_token_create(ElnaLexerKind.right_square, position) - end -return result - -proc elna_lexer_classify_composite(start_position, one_before_last: ^Word8; position: ^ElnaPosition) -> ^ElnaLexerToken -var - first_character: Word8 - last_character: Word8 - result: ^ElnaLexerToken -begin - first_character := start_position^; - last_character := one_before_last^; - - if first_character = ':' then - result := elna_lexer_token_create(ElnaLexerKind.assignment, position) - elsif first_character = '<' then - if last_character = '=' then - result := elna_lexer_token_create(ElnaLexerKind.less_equal, position) - elsif last_character = '>' then - result := elna_lexer_token_create(ElnaLexerKind.not_equal, position) - end - elsif first_character = '>' then - if last_character = '=' then - result := elna_lexer_token_create(ElnaLexerKind.greater_equal, position) - end - elsif first_character = '-' then - if last_character = '>' then - result := elna_lexer_token_create(ElnaLexerKind.arrow, position) - end - end -return result - -proc elna_lexer_execute_action(cursor: ^ElnaLexerCursor; action_to_perform: ElnaLexerAction) -> ^ElnaLexerToken -var - token: ^ElnaLexerToken -begin - token := nil; - - if action_to_perform = ElnaLexerAction.none then - elsif action_to_perform = ElnaLexerAction.accumulate then - elna_lexer_advance(cursor) - elsif action_to_perform = ElnaLexerAction.skip then - elna_lexer_classify_space(cursor^.start, @cursor^.position.end_location); - cursor^.start := cursor^.start + 1; - cursor^.finish := cursor^.finish + 1 - elsif action_to_perform = ElnaLexerAction.single then - elna_lexer_advance(cursor); - - token := elna_lexer_classify_single(cursor^.start, @cursor^.position) - elsif action_to_perform = ElnaLexerAction.eof then - token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - token^.kind := ElnaLexerKind.eof - elsif action_to_perform = ElnaLexerAction.finalize then - token := elna_lexer_classify_finalize(cursor^.start, @cursor^.position) - elsif action_to_perform = ElnaLexerAction.composite then - token := elna_lexer_classify_composite(cursor^.start, cursor^.finish, @cursor^.position); - - elna_lexer_advance(cursor) - elsif action_to_perform = ElnaLexerAction.key_id then - token := elna_lexer_classify_keyword(cursor^.start, cursor^.finish, @cursor^.position) - elsif action_to_perform = ElnaLexerAction.integer then - token := elna_lexer_classify_integer(cursor^.start, cursor^.finish, @cursor^.position) - elsif action_to_perform = ElnaLexerAction.delimited then - elna_lexer_advance(cursor); - - token := elna_lexer_classify_delimited(cursor^.start, cursor^.finish, @cursor^.position) - end -return token - -proc elna_lexer_execute_transition(cursor: ^ElnaLexerCursor) -> ^ElnaLexerToken -var - next_transition: ^ElnaLexerTransition - current_character: Word8 -begin - current_character := cursor^.finish^; - next_transition := elna_lexer_get_transition(cursor^.state, - classification[cast(current_character: Word) + 1u]); - cursor^.state := next_transition^.next_state -return elna_lexer_execute_action(cursor, next_transition^.action) - -(** - * One time lexer initialization. - *) -proc elna_lexer_initialize*(cursor: ^ElnaLexerCursor; code_pointer: ^Word8) -begin - elna_lexer_classifications(); - elna_lexer_transitions(); - - cursor^.start := code_pointer; - cursor^.finish := code_pointer; - cursor^.token := nil; - cursor^.position.start_location := { ElnaLocation; line: 1u, column: 1u }; - cursor^.position.end_location := { ElnaLocation; line: 1u, column: 1u } -return - -(** - * Reads the next token and writes its type into the address in the kind parameter. - * Resets the lexer state for reading the next token. - *) -proc elna_lexer_peek*(cursor: ^ElnaLexerCursor) -> ^ElnaLexerToken -var - token: ^ElnaLexerToken -begin - if cursor^.token = nil then - cursor^.state := ElnaLexerState.start; - - while cursor^.state <> ElnaLexerState.finish do - token := elna_lexer_execute_transition(cursor) - end; - cursor^.token := token - end -return cursor^.token - -(** - * Reads the token and advance the lexer. - *) -proc elna_lexer_read*(cursor: ^ElnaLexerCursor) -> ^ElnaLexerToken -var - token: ^ElnaLexerToken -begin - token := elna_lexer_peek(cursor); - cursor^.token := nil; - cursor^.start := cursor^.finish; - cursor^.position.start_location := cursor^.position.end_location -return token - -(** - * Skips comments. - *) -proc elna_lexer_skip_empty_lines*(cursor: ^ElnaLexerCursor) -var - token: ^ElnaLexerToken -begin - token := elna_lexer_peek(cursor); - - while token^.kind = ElnaLexerKind.comment do - elna_lexer_read(cursor); - token := elna_lexer_peek(cursor) - end -return - -end. diff --git a/source/main.elna b/source/main.elna index 3b78651..b45b283 100644 --- a/source/main.elna +++ b/source/main.elna @@ -1,142 +1,6 @@ (* 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() -program(parameters) -import - sys.posix.cstdio, sys.posix.cstdlib, sys.posix.cstring, common, command_line_interface, - lexer, ast, diagnostic, symbol, parser, name_analysis, type_check, tac, qbe - -proc read_file_to_buffer(filename: ^Word8) -> []const Word8 -var - file_handle: ^FILE - file_size: Int - buffer: ^Word8 - bytes_read: Word - result: []const Word8 -begin - file_handle := fopen(filename, "rb\0".ptr); - if file_handle = nil then - perror(filename); - exit(3) - end; - fseek(file_handle, 0, 2); - file_size := ftell(file_handle); - rewind(file_handle); - - buffer := malloc#[Word8](cast(file_size: Word) + 1u); - bytes_read := fread#[Word8](buffer, 1u, cast(file_size: Word), file_handle); - (buffer + bytes_read)^ := cast(0: Word8); - fclose(file_handle); - - result := buffer[1u to bytes_read] -return result - -proc print_errors(error_list: ^ElnaList) -var - node: ^ElnaListNode -begin - node := error_list^.first; - while node <> nil do - elna_error_print(cast(node: ^ElnaError)); - node := node^.next - end -return - -proc compile_file(command_line: ^CommandLine) -> Int -var - source_text: []const Word8 - lexer_cursor: ElnaLexerCursor - error_list: ElnaList - parser_node: ^ElnaTreeModuleDeclaration - tac_module: ^ElnaInstructionModule - out_file: ^FILE := stdout - token: ^ElnaLexerToken - return_code: Int := 0 -begin - source_text := read_file_to_buffer(command_line^.input); - - if command_line^.lex then - elna_lexer_initialize(@lexer_cursor, cast(source_text.ptr: ^Word8)); - token := elna_lexer_read(@lexer_cursor); - while token^.kind <> ElnaLexerKind.eof do - token := elna_lexer_read(@lexer_cursor) - end - else - elna_list_initialize(@error_list); - elna_symbol_table_build(); - - elna_lexer_initialize(@lexer_cursor, cast(source_text.ptr: ^Word8)); - parser_node := elna_parser_module_declaration(@lexer_cursor, @error_list); - - if ~elna_list_empty(@error_list) then - print_errors(@error_list); - return_code := 1 - elsif ~command_line^.parse then - elna_declaration_module_declaration(parser_node, @error_list); - if ~elna_list_empty(@error_list) then - print_errors(@error_list); - return_code := 1 - else - elna_name_module_declaration(parser_node, @error_list); - if ~elna_list_empty(@error_list) then - print_errors(@error_list); - return_code := 1 - else - elna_type_module_declaration(parser_node, @error_list); - if ~elna_list_empty(@error_list) then - print_errors(@error_list); - return_code := 1 - else - tac_module := elna_tac_module_declaration(parser_node); - - if command_line^.output <> nil then - out_file := fopen(command_line^.output, "wb\0".ptr); - if out_file = nil then - perror(command_line^.output); - return_code := 3 - end - end; - - if return_code = 0 then - elna_qbe_emit(tac_module, out_file); - - if command_line^.output <> nil & out_file <> stdout then - fclose(out_file) - end - end - end - end - end - end - end -return return_code - -proc initialize_global_state() -begin - stdin := fdopen(0, "r\0".ptr); - stdout := fdopen(1, "w\0".ptr); - stderr := fdopen(2, "w\0".ptr) -return - -proc process(argc: Int; argv: ^^Word8) -> Int -var - command_line: ^CommandLine - return_code: Int := 0 -begin - command_line := parse_command_line(argc, argv); - if command_line = nil then - return_code := 2 - elsif command_line^.input = nil then - write_s("Fatal error: no input file provided.\n"); - return_code := 2 - else - return_code := compile_file(command_line) - end -return return_code - -begin - initialize_global_state(); - - exit(process(cast(parameters.length: Int), parameters.ptr)) end. diff --git a/source/name_analysis.elna b/source/name_analysis.elna deleted file mode 100644 index cbb27c0..0000000 --- a/source/name_analysis.elna +++ /dev/null @@ -1,539 +0,0 @@ -(* 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 common, sys.posix.cstdlib, lexer, ast, symbol, diagnostic - -proc elna_name_type_expression*(parser_node: ^ElnaTreeTypeExpression; error_list: ^ElnaList) -> ^ElnaType -var - result: ^ElnaType := nil -begin - if parser_node <> nil then - case parser_node^.kind of - ElnaTreeKind.named_type_expression: - result := elna_name_named_type_expression(cast(parser_node: ^ElnaTreeNamedTypeExpression), error_list) - | ElnaTreeKind.enumeration_type_expression: - result := malloc#[ElnaType](#size(ElnaTypeEnumeration)); - result^.kind := ElnaTypeKind.enumeration; - elna_name_enumeration_type_expression(cast(parser_node: ^ElnaTreeEnumerationTypeExpression), error_list, cast(result: ^ElnaTypeEnumeration)) - | ElnaTreeKind.record_type_expression: - result := malloc#[ElnaType](#size(ElnaTypeRecord)); - result^.kind := ElnaTypeKind._record; - elna_name_record_type_expression(cast(parser_node: ^ElnaTreeRecordTypeExpression), error_list, cast(result: ^ElnaTypeRecord)) - | ElnaTreeKind.pointer_type_expression: - result := malloc#[ElnaType](#size(ElnaTypePointer)); - result^.kind := ElnaTypeKind.pointer; - elna_name_pointer_type_expression(cast(parser_node: ^ElnaTreePointerTypeExpression), error_list, cast(result: ^ElnaTypePointer)) - | ElnaTreeKind.array_type_expression: - result := malloc#[ElnaType](#size(ElnaTypeArray)); - result^.kind := ElnaTypeKind.array; - elna_name_array_type_expression(cast(parser_node: ^ElnaTreeArrayTypeExpression), error_list, cast(result: ^ElnaTypeArray)) - else - end - end -return result - -proc elna_name_named_type_expression*(parser_node: ^ElnaTreeNamedTypeExpression; error_list: ^ElnaList) -> ^ElnaType -var - symbol_info: ^ElnaSymbolInfo - type_info: ^ElnaSymbolTypeInfo - undefined_symbol: ^ElnaErrorUndefinedSymbol - result: ^ElnaType := nil -begin - symbol_info := elna_symbol_table_lookup(symbol_table_global, parser_node^.name); - if symbol_info <> nil then - type_info := cast(symbol_info: ^ElnaSymbolTypeInfo); - result := type_info^._type - else - undefined_symbol := elna_error_undefined_symbol_create(parser_node^.position, parser_node^.name); - elna_list_append(error_list, cast(undefined_symbol: ^ElnaListNode)) - end -return result - -proc elna_name_alias_type_expression*(parser_node: ^ElnaTreeNamedTypeExpression; - error_list: ^ElnaList; result: ^ElnaTypeAlias) -var - base: ^ElnaType -begin - base := elna_name_named_type_expression(parser_node, error_list); - if base <> nil then - result^.size := base^.size; - result^.alignment := base^.alignment; - result^.base := base - end -return - -proc elna_name_enumeration_type_expression*(parser_node: ^ElnaTreeEnumerationTypeExpression; - error_list: ^ElnaList; result: ^ElnaTypeEnumeration) -var - tree_member: ^ElnaTreeEnumeration - i: Word := 0u -begin - result^.size := 8u; - result^.alignment := 8u; - result^.length := parser_node^.length; - result^.members := malloc#[[]const Word8](parser_node^.length * #size([]const Word8)); - - tree_member := parser_node^.members; - while i < parser_node^.length & tree_member <> nil do - (result^.members + i)^ := tree_member^.name; - tree_member := tree_member^.next; - i := i + 1u - end -return - -proc elna_name_pointer_type_expression*(parser_node: ^ElnaTreePointerTypeExpression; - error_list: ^ElnaList; result: ^ElnaTypePointer) -begin - result^.size := 8u; - result^.alignment := 8u; - result^.base := elna_name_type_expression(parser_node^.base, error_list) -return - -proc elna_name_array_type_expression*(parser_node: ^ElnaTreeArrayTypeExpression; - error_list: ^ElnaList; result: ^ElnaTypeArray) -var - base: ^ElnaType - len_lit: ^ElnaTreeIntegerLiteral -begin - base := elna_name_type_expression(parser_node^.base, error_list); - len_lit := cast(parser_node^.length: ^ElnaTreeIntegerLiteral); - if base <> nil & len_lit <> nil then - result^.size := base^.size * len_lit^.value; - result^.alignment := base^.alignment; - result^.base := base; - result^.length := len_lit^.value - end -return - -proc elna_name_record_type_expression*(parser_node: ^ElnaTreeRecordTypeExpression; - error_list: ^ElnaList; result: ^ElnaTypeRecord) -var - tree_field: ^ElnaTreeField - member_array_current: ^ElnaTypeField - field_type: ^ElnaType -begin - result^.size := 0u; - result^.alignment := 0u; - result^.length := 0u; - result^.members := malloc#[ElnaTypeField](parser_node^.length * #size(ElnaTypeField)); - - tree_field := parser_node^.members; - member_array_current := result^.members; - - while result^.length < parser_node^.length & tree_field <> nil do - member_array_current^.name := tree_field^.name; - field_type := elna_name_type_expression(tree_field^.type_expression, error_list); - if field_type <> nil then - result^.size := result^.size + field_type^.size; - if field_type^.alignment > result^.alignment then - result^.alignment := field_type^.alignment - end; - member_array_current^.field_type := field_type; - member_array_current := member_array_current + 1u; - tree_field := tree_field^.next; - result^.length := result^.length + 1u - else - tree_field := nil - end - end -return - -proc elna_name_procedure_temporary*(parser_node: ^ElnaTreeVariableDeclaration; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -var - info: ^ElnaSymbolTemporaryInfo - variable_type: ^ElnaType - declaration_error: ^ElnaErrorDuplicateDeclaration -begin - info := cast(elna_symbol_table_lookup(symbol_table, parser_node^.name): ^ElnaSymbolTemporaryInfo); - if info = nil then - variable_type := elna_name_type_expression(parser_node^.type_expression, error_list); - info := elna_symbol_temporary_info_create(0u, variable_type); - elna_symbol_table_enter(symbol_table, parser_node^.name, cast(info: ^ElnaSymbolInfo)) - else - declaration_error := elna_error_duplicate_declaration_create(parser_node^.position, parser_node^.name); - elna_list_append(error_list, cast(declaration_error: ^ElnaListNode)) - end -return - -proc elna_name_procedure_temporaries*(parser_node: ^ElnaTreeVariableDeclaration; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -var - current: ^ElnaTreeVariableDeclaration -begin - current := parser_node; - while current <> nil do - elna_name_procedure_temporary(current, symbol_table, error_list); - current := cast(current^.next: ^ElnaTreeVariableDeclaration) - end -return - -proc elna_name_type_declaration*(parser_node: ^ElnaTreeTypeDeclaration; error_list: ^ElnaList) -var - type_info: ^ElnaSymbolTypeInfo - type_stub: ^ElnaType - type_expression: ^ElnaTreeTypeExpression -begin - type_info := cast(elna_symbol_table_lookup(symbol_table_global, parser_node^.name): ^ElnaSymbolTypeInfo); - if type_info <> nil then - type_stub := type_info^._type; - type_expression := parser_node^.type_expression; - - if type_stub^.kind = ElnaTypeKind.alias then - elna_name_alias_type_expression(cast(type_expression: ^ElnaTreeNamedTypeExpression), error_list, cast(type_stub: ^ElnaTypeAlias)) - elsif type_stub^.kind = ElnaTypeKind.enumeration then - elna_name_enumeration_type_expression(cast(type_expression: ^ElnaTreeEnumerationTypeExpression), error_list, cast(type_stub: ^ElnaTypeEnumeration)) - elsif type_stub^.kind = ElnaTypeKind._record then - elna_name_record_type_expression(cast(type_expression: ^ElnaTreeRecordTypeExpression), error_list, cast(type_stub: ^ElnaTypeRecord)) - elsif type_stub^.kind = ElnaTypeKind.pointer then - elna_name_pointer_type_expression(cast(type_expression: ^ElnaTreePointerTypeExpression), error_list, cast(type_stub: ^ElnaTypePointer)) - elsif type_stub^.kind = ElnaTypeKind.array then - elna_name_array_type_expression(cast(type_expression: ^ElnaTreeArrayTypeExpression), error_list, cast(type_stub: ^ElnaTypeArray)) - end - end -return - -proc elna_name_variable_expression*(parser_node: ^ElnaTreeVariableExpression; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -var - symbol_info: ^ElnaSymbolInfo - undefined_symbol: ^ElnaErrorUndefinedSymbol -begin - symbol_info := elna_symbol_table_lookup(symbol_table, parser_node^.name); - if symbol_info = nil then - undefined_symbol := elna_error_undefined_symbol_create(parser_node^.position, parser_node^.name); - elna_list_append(error_list, cast(undefined_symbol: ^ElnaListNode)) - end -return - -proc elna_name_cast_expression*(parser_node: ^ElnaTreeCastExpression; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -begin - elna_name_binary_expression(parser_node^.expression, symbol_table, error_list); - parser_node^.type_decoration := elna_name_type_expression(parser_node^.type_expression, error_list) -return - -proc elna_name_simple_expression*(parser_node: ^ElnaTreeExpression; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -begin - if parser_node^.kind = ElnaTreeKind._cast then - elna_name_cast_expression(cast(parser_node: ^ElnaTreeCastExpression), symbol_table, error_list) - elsif parser_node^.kind = ElnaTreeKind.variable_expression then - elna_name_variable_expression(cast(parser_node: ^ElnaTreeVariableExpression), symbol_table, error_list) - end -return - -proc elna_name_call*(parser_node: ^ElnaTreeCall; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) -var - argument_tree: ^ElnaTreeExpressionList -begin - elna_name_variable_expression(parser_node^.callee, symbol_table, error_list); - argument_tree := parser_node^.arguments; - while argument_tree <> nil do - elna_name_binary_expression(argument_tree^.expression, symbol_table, error_list); - argument_tree := argument_tree^.next - end -return - -proc elna_name_dereference_expression*(parser_node: ^ElnaTreeDereferenceExpression; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -begin - elna_name_designator(parser_node^.pointer, symbol_table, error_list) -return - -proc elna_name_field_access_expression*(parser_node: ^ElnaTreeFieldAccessExpression; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -var - variable_expression: ^ElnaTreeVariableExpression - identifier_symbol: ^ElnaSymbolInfo - type_info: ^ElnaSymbolTypeInfo - undefined_member_error: ^ElnaErrorUndefinedMember - enumeration_type: ^ElnaTypeEnumeration - member_count: Word - current_member: ^[]const Word8 - found: Bool := false -begin - if parser_node^.aggregate^.kind = ElnaTreeKind.variable_expression then - variable_expression := cast(parser_node^.aggregate: ^ElnaTreeVariableExpression); - identifier_symbol := elna_symbol_table_lookup(symbol_table, variable_expression^.name); - - if identifier_symbol <> nil & identifier_symbol^.kind = ElnaSymbolInfoKind.type_info then - type_info := cast(identifier_symbol: ^ElnaSymbolTypeInfo); - if type_info^._type^.kind = ElnaTypeKind.enumeration then - enumeration_type := cast(type_info^._type: ^ElnaTypeEnumeration); - current_member := enumeration_type^.members; - member_count := enumeration_type^.length; - - while member_count > 0u & ~found do - if current_member^ = parser_node^.field then - found := true - end; - member_count := member_count - 1u; - current_member := current_member + 1u - end - end; - if ~found then - undefined_member_error := elna_error_undefined_member_create(variable_expression^.position, - variable_expression^.name, parser_node^.field); - elna_list_append(error_list, cast(undefined_member_error: ^ElnaListNode)) - end - else - elna_name_designator(cast(variable_expression: ^ElnaTreeExpression), symbol_table, error_list) - end - else - elna_name_designator(parser_node^.aggregate, symbol_table, error_list) - end -return - -proc elna_name_array_access_expression*(parser_node: ^ElnaTreeArrayAccessExpression; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -begin - elna_name_designator(parser_node^.array, symbol_table, error_list); - elna_name_binary_expression(parser_node^.index, symbol_table, error_list) -return - -proc elna_name_designator*(parser_node: ^ElnaTreeExpression; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) -begin - if parser_node^.kind = ElnaTreeKind.dereference_expression then - elna_name_dereference_expression(cast(parser_node: ^ElnaTreeDereferenceExpression), symbol_table, error_list) - elsif parser_node^.kind = ElnaTreeKind.field_access_expression then - elna_name_field_access_expression(cast(parser_node: ^ElnaTreeFieldAccessExpression), symbol_table, error_list) - elsif parser_node^.kind = ElnaTreeKind.array_access_expression then - elna_name_array_access_expression(cast(parser_node: ^ElnaTreeArrayAccessExpression), symbol_table, error_list) - elsif parser_node^.kind = ElnaTreeKind.call then - elna_name_call(cast(parser_node: ^ElnaTreeCall), symbol_table, error_list) - else - elna_name_simple_expression(parser_node, symbol_table, error_list) - end -return - -proc elna_name_unary_expression*(parser_node: ^ElnaTreeExpression; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -var - unary_node: ^ElnaTreeUnaryExpression -begin - if parser_node^.kind = ElnaTreeKind.unary_expression then - unary_node := cast(parser_node: ^ElnaTreeUnaryExpression); - elna_name_designator(unary_node^.operand, symbol_table, error_list) - else - elna_name_designator(parser_node, symbol_table, error_list) - end -return - -proc elna_name_binary_expression*(parser_node: ^ElnaTreeExpression; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -var - bin_node: ^ElnaTreeBinaryExpression -begin - if parser_node^.kind = ElnaTreeKind.binary_expression then - bin_node := cast(parser_node: ^ElnaTreeBinaryExpression); - elna_name_unary_expression(bin_node^.lhs, symbol_table, error_list); - elna_name_unary_expression(bin_node^.rhs, symbol_table, error_list) - else - elna_name_unary_expression(parser_node, symbol_table, error_list) - end -return - -proc elna_name_conditional_statements*(parser_node: ^ElnaTreeConditionalStatements; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -var - current: ^ElnaTreeConditionalStatements -begin - current := parser_node; - while current <> nil do - elna_name_binary_expression(current^.condition, symbol_table, error_list); - elna_name_statements(current^.statements, symbol_table, error_list); - current := current^.next - end -return - -proc elna_name_if_statement*(parser_node: ^ElnaTreeIfStatement; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -begin - elna_name_conditional_statements(parser_node^.conditionals, symbol_table, error_list); - if parser_node^._else <> nil then - elna_name_statements(parser_node^._else, symbol_table, error_list) - end -return - -proc elna_name_return_statement*(parser_node: ^ElnaTreeReturnStatement; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -begin - elna_name_binary_expression(parser_node^.returned, symbol_table, error_list) -return - -proc elna_name_assign_statement*(parser_node: ^ElnaTreeAssignStatement; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -begin - elna_name_designator(parser_node^.assignee, symbol_table, error_list); - elna_name_binary_expression(parser_node^.assignment, symbol_table, error_list) -return - -proc elna_name_statement*(parser_node: ^ElnaTreeStatement; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) -var - call_statement: ^ElnaTreeCallStatement -begin - if parser_node^.kind = ElnaTreeKind.if_statement then - elna_name_if_statement(cast(parser_node: ^ElnaTreeIfStatement), symbol_table, error_list) - elsif parser_node^.kind = ElnaTreeKind.return_statement then - elna_name_return_statement(cast(parser_node: ^ElnaTreeReturnStatement), symbol_table, error_list) - elsif parser_node^.kind = ElnaTreeKind.call_statement then - call_statement := cast(parser_node: ^ElnaTreeCallStatement); - elna_name_call(call_statement^.call, symbol_table, error_list) - elsif parser_node^.kind = ElnaTreeKind.assign_statement then - elna_name_assign_statement(cast(parser_node: ^ElnaTreeAssignStatement), symbol_table, error_list) - end -return - -proc elna_name_statements*(parser_node: ^ElnaTreeStatement; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -var - current: ^ElnaTreeStatement -begin - current := parser_node; - while current <> nil do - elna_name_statement(current, symbol_table, error_list); - current := current^.next - end -return - -proc elna_name_procedure_declaration*(parser_node: ^ElnaTreeProcedureDeclaration; error_list: ^ElnaList) -var - new_symbol_table: ^ElnaSymbolTable - symbol_info: ^ElnaSymbolProcedureInfo - proc_type: ^ElnaTypeProcedure -begin - symbol_info := cast(elna_symbol_table_lookup(symbol_table_global, parser_node^.name): ^ElnaSymbolProcedureInfo); - - proc_type := malloc#[ElnaTypeProcedure](#size(ElnaTypeProcedure)); - proc_type^.kind := ElnaTypeKind.procedure; - proc_type^.size := 8u; - proc_type^.alignment := 8u; - if parser_node^.return_type = nil then - proc_type^.return_type := nil - else - proc_type^.return_type := elna_name_type_expression(parser_node^.return_type, error_list) - end; - symbol_info^.procedure_type := proc_type; - - if ~symbol_info^.is_extern then - new_symbol_table := elna_symbol_table_create(symbol_table_global); - symbol_info^.symbol_table := new_symbol_table; - - elna_name_procedure_temporaries(parser_node^.parameters, new_symbol_table, error_list); - elna_name_procedure_temporaries(parser_node^.temporaries, new_symbol_table, error_list); - elna_name_statements(parser_node^.body, new_symbol_table, error_list) - end -return - -proc elna_name_program_body*(parser_node: ^ElnaTreeStatement) -var - symbol_info: ^ElnaSymbolProcedureInfo -begin - symbol_info := elna_symbol_procedure_info_create(false); - symbol_info^.symbol_table := elna_symbol_table_create(symbol_table_global); - elna_symbol_table_enter(symbol_table_global, "main", cast(symbol_info: ^ElnaSymbolInfo)) -return - -proc elna_declaration_type_declaration*(parser_node: ^ElnaTreeTypeDeclaration; error_list: ^ElnaList) -var - type_info: ^ElnaSymbolTypeInfo - result: ^ElnaType := nil - type_expression: ^ElnaTreeTypeExpression - declaration_error: ^ElnaErrorDuplicateDeclaration -begin - type_info := cast(elna_symbol_table_lookup(symbol_table_global, parser_node^.name): ^ElnaSymbolTypeInfo); - - if type_info = nil then - type_expression := parser_node^.type_expression; - - if type_expression^.kind = ElnaTreeKind.named_type_expression then - result := malloc#[ElnaType](#size(ElnaTypeAlias)); - result^.kind := ElnaTypeKind.alias - elsif type_expression^.kind = ElnaTreeKind.enumeration_type_expression then - result := malloc#[ElnaType](#size(ElnaTypeEnumeration)); - result^.kind := ElnaTypeKind.enumeration - elsif type_expression^.kind = ElnaTreeKind.record_type_expression then - result := malloc#[ElnaType](#size(ElnaTypeRecord)); - result^.kind := ElnaTypeKind._record - elsif type_expression^.kind = ElnaTreeKind.pointer_type_expression then - result := malloc#[ElnaType](#size(ElnaTypePointer)); - result^.kind := ElnaTypeKind.pointer - elsif type_expression^.kind = ElnaTreeKind.array_type_expression then - result := malloc#[ElnaType](#size(ElnaTypeArray)); - result^.kind := ElnaTypeKind.array - end; - type_info := elna_symbol_type_info_create(result); - elna_symbol_table_enter(symbol_table_global, parser_node^.name, cast(type_info: ^ElnaSymbolInfo)) - else - declaration_error := elna_error_duplicate_declaration_create(parser_node^.position, parser_node^.name); - elna_list_append(error_list, cast(declaration_error: ^ElnaListNode)) - end -return - -proc elna_declaration_procedure_declaration*(parser_node: ^ElnaTreeProcedureDeclaration; error_list: ^ElnaList) -var - symbol_info: ^ElnaSymbolProcedureInfo - declaration_error: ^ElnaErrorDuplicateDeclaration -begin - symbol_info := cast(elna_symbol_table_lookup(symbol_table_global, parser_node^.name): ^ElnaSymbolProcedureInfo); - - if symbol_info = nil then - symbol_info := elna_symbol_procedure_info_create(parser_node^.is_extern); - symbol_info^.symbol_table := elna_symbol_table_create(symbol_table_global); - elna_symbol_table_enter(symbol_table_global, parser_node^.name, cast(symbol_info: ^ElnaSymbolInfo)) - else - declaration_error := elna_error_duplicate_declaration_create(parser_node^.position, parser_node^.name); - elna_list_append(error_list, cast(declaration_error: ^ElnaListNode)) - end -return - -proc elna_declaration_module_declaration*(parser_node: ^ElnaTreeModuleDeclaration; error_list: ^ElnaList) -var - current_type: ^ElnaTreeDeclaration - current_proc: ^ElnaTreeDeclaration -begin - current_type := parser_node^.types; - while current_type <> nil do - elna_declaration_type_declaration(cast(current_type: ^ElnaTreeTypeDeclaration), error_list); - current_type := current_type^.next - end; - - current_proc := cast(parser_node^.procedures: ^ElnaTreeDeclaration); - while current_proc <> nil do - elna_declaration_procedure_declaration(cast(current_proc: ^ElnaTreeProcedureDeclaration), error_list); - current_proc := current_proc^.next - end -return - -proc elna_name_module_declaration*(parser_node: ^ElnaTreeModuleDeclaration; error_list: ^ElnaList) -var - current_type: ^ElnaTreeDeclaration - current_global: ^ElnaTreeVariableDeclaration - current_proc: ^ElnaTreeProcedureDeclaration -begin - current_type := parser_node^.types; - while current_type <> nil do - elna_name_type_declaration(cast(current_type: ^ElnaTreeTypeDeclaration), error_list); - current_type := current_type^.next - end; - - current_global := parser_node^.globals; - while current_global <> nil do - elna_name_procedure_temporary(current_global, symbol_table_global, error_list); - current_global := cast(current_global^.next: ^ElnaTreeVariableDeclaration) - end; - - current_proc := parser_node^.procedures; - while current_proc <> nil do - elna_name_procedure_declaration(current_proc, error_list); - current_proc := cast(current_proc^.next: ^ElnaTreeProcedureDeclaration) - end; - - if parser_node^.body <> nil then - elna_name_program_body(parser_node^.body) - end -return - -end. diff --git a/source/parser.elna b/source/parser.elna deleted file mode 100644 index 3912b65..0000000 --- a/source/parser.elna +++ /dev/null @@ -1,1162 +0,0 @@ -(* 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 common, sys.posix.cstdlib, lexer, ast, diagnostic - -proc elna_parser_expect*(cursor: ^ElnaLexerCursor; expected: ElnaLexerKind; error_list: ^ElnaList) -> ^ElnaLexerToken -var - token: ^ElnaLexerToken - parser_error: ^ElnaErrorUnexpectedToken -begin - elna_lexer_skip_empty_lines(cursor); - token := elna_lexer_peek(cursor); - - if token^.kind = expected then - token := elna_lexer_read(cursor) - else - token := nil; - parser_error := elna_error_unexpected_token_create(cursor, 1u); - parser_error^.expected[1] := expected; - elna_list_append(error_list, cast(parser_error: ^ElnaListNode)) - end -return token - -proc elna_parser_escape*(current_position: ^const Word8; result: ^Word8) -> Word -var - parsed_length: Word - next_character: Word8 - pos: ^const Word8 -begin - pos := current_position; - next_character := pos^; - - if next_character = '\\' then - parsed_length := 2u; - pos := pos + 1u; - next_character := pos^; - - if next_character = '\\' then - result^ := 92u8 - elsif next_character = 'n' then - result^ := 10u8 - elsif next_character = 't' then - result^ := 9u8 - elsif next_character = 'f' then - result^ := 12u8 - elsif next_character = 'r' then - result^ := 13u8 - elsif next_character = 'v' then - result^ := 11u8 - elsif next_character = '"' then - result^ := 34u8 - elsif next_character = '\'' then - result^ := 39u8 - elsif next_character = '0' then - result^ := 0u8 - else - result^ := next_character - end - else - parsed_length := 1u; - result^ := next_character - end -return parsed_length - -proc elna_parser_integer_literal*(cursor: ^ElnaLexerCursor) -> ^ElnaTreeIntegerLiteral -var - token: ^ElnaLexerToken - result: ^ElnaTreeIntegerLiteral - i: Word := 1u - val: Word := 0u -begin - result := malloc#[ElnaTreeIntegerLiteral](#size(ElnaTreeIntegerLiteral)); - token := elna_lexer_read(cursor); - result^.kind := ElnaTreeKind.integer_literal; - result^.type_decoration := nil; - result^.position := token^.position; - - while i <= token^.start.length do - val := val * 10u + cast(token^.start[i] - '0': Word); - i := i + 1u - end; - result^.value := val -return result - -proc elna_parser_boolean_literal*(cursor: ^ElnaLexerCursor) -> ^ElnaTreeBooleanLiteral -var - token: ^ElnaLexerToken - result: ^ElnaTreeBooleanLiteral -begin - token := elna_lexer_read(cursor); - result := malloc#[ElnaTreeBooleanLiteral](#size(ElnaTreeBooleanLiteral)); - result^.kind := ElnaTreeKind.boolean_literal; - result^.value := token^.start = "true"; - result^.type_decoration := nil; - result^.position := token^.position -return result - -proc elna_parser_nil_literal*(cursor: ^ElnaLexerCursor) -> ^ElnaTreeNilLiteral -var - token: ^ElnaLexerToken - result: ^ElnaTreeNilLiteral -begin - token := elna_lexer_read(cursor); - result := malloc#[ElnaTreeNilLiteral](#size(ElnaTreeNilLiteral)); - result^.kind := ElnaTreeKind.null; - result^.type_decoration := nil; - result^.position := token^.position -return result - -proc elna_parser_character_literal*(cursor: ^ElnaLexerCursor) -> ^ElnaTreeCharacterLiteral -var - result: ^ElnaTreeCharacterLiteral - token: ^ElnaLexerToken -begin - result := malloc#[ElnaTreeCharacterLiteral](#size(ElnaTreeCharacterLiteral)); - token := elna_lexer_read(cursor); - result^.kind := ElnaTreeKind.character_literal; - result^.position := token^.position; - result^.type_decoration := nil; - elna_parser_escape(token^.start.ptr + 1u, @result^.value) -return result - -proc elna_parser_variable_expression*(cursor: ^ElnaLexerCursor) -> ^ElnaTreeVariableExpression -var - result: ^ElnaTreeVariableExpression - token: ^ElnaLexerToken -begin - result := malloc#[ElnaTreeVariableExpression](#size(ElnaTreeVariableExpression)); - token := elna_lexer_read(cursor); - result^.kind := ElnaTreeKind.variable_expression; - result^.name := token^.start; - result^.position := token^.position; - result^.type_decoration := nil -return result - -proc elna_parser_string_literal*(cursor: ^ElnaLexerCursor) -> ^ElnaTreeStringLiteral -var - result: ^ElnaTreeStringLiteral - token: ^ElnaLexerToken - current_position: ^const Word8 - parsed_length: Word - parsed_total: Word - target_start, target_position: ^Word8 -begin - result := malloc#[ElnaTreeStringLiteral](#size(ElnaTreeStringLiteral)); - token := elna_lexer_read(cursor); - target_start := malloc#[Word8](token^.start.length); - target_position := target_start; - current_position := token^.start.ptr + 1u; - parsed_total := 2u; - - result^.kind := ElnaTreeKind.string_literal; - result^.position := token^.position; - result^.type_decoration := nil; - - while parsed_total < token^.start.length do - parsed_length := elna_parser_escape(current_position, target_position); - current_position := current_position + parsed_length; - parsed_total := parsed_total + parsed_length; - target_position := target_position + 1u - end; - result^.value := target_start[1 to cast(target_position - target_start: Word)] -return result - -proc elna_parser_trait_expression*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeTraitExpression -var - result: ^ElnaTreeTraitExpression - token: ^ElnaLexerToken -begin - result := malloc#[ElnaTreeTraitExpression](#size(ElnaTreeTraitExpression)); - result^.kind := ElnaTreeKind.trait_expression; - token := elna_lexer_read(cursor); - result^.name := token^.start; - result^.position := token^.position; - - if elna_parser_expect(cursor, ElnaLexerKind.left_paren, error_list) <> nil then - result^.argument := elna_parser_type_expression(cursor, error_list); - if result^.argument = nil then - result := free_and_nil(result) - elsif elna_parser_expect(cursor, ElnaLexerKind.right_paren, error_list) = nil then - result := free_and_nil(result) - end - else - result := free_and_nil(result) - end -return result - -proc elna_parser_cast_expression*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeCastExpression -var - result: ^ElnaTreeCastExpression := nil - token: ^ElnaLexerToken - start_location: ElnaLocation -begin - token := elna_lexer_read(cursor); - start_location := token^.position.start_location; - - if elna_parser_expect(cursor, ElnaLexerKind.left_paren, error_list) <> nil then - result := malloc#[ElnaTreeCastExpression](#size(ElnaTreeCastExpression)); - result^.kind := ElnaTreeKind._cast; - result^.position.start_location := start_location; - result^.type_decoration := nil; - result^.expression := elna_parser_binary_expression(cursor, error_list); - if result^.expression = nil then - result := free_and_nil(result) - elsif elna_parser_expect(cursor, ElnaLexerKind.colon, error_list) = nil then - result := free_and_nil(result) - else - result^.type_expression := elna_parser_type_expression(cursor, error_list); - if result^.type_expression = nil then - result := free_and_nil(result) - else - token := elna_parser_expect(cursor, ElnaLexerKind.right_paren, error_list); - if token = nil then - result := free_and_nil(result) - else - result^.position.end_location := token^.position.end_location - end - end - end - end -return result - -proc elna_parser_simple_expression*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeExpression -var - token: ^ElnaLexerToken - result: ^ElnaTreeExpression := nil -begin - token := elna_lexer_peek(cursor); - case token^.kind of - ElnaLexerKind.character: - result := cast(elna_parser_character_literal(cursor): ^ElnaTreeExpression) - | ElnaLexerKind.integer: - result := cast(elna_parser_integer_literal(cursor): ^ElnaTreeExpression) - | ElnaLexerKind.string: - result := cast(elna_parser_string_literal(cursor): ^ElnaTreeExpression) - | ElnaLexerKind.boolean: - result := cast(elna_parser_boolean_literal(cursor): ^ElnaTreeExpression) - | ElnaLexerKind.null: - result := cast(elna_parser_nil_literal(cursor): ^ElnaTreeExpression) - | ElnaLexerKind._cast: - result := cast(elna_parser_cast_expression(cursor, error_list): ^ElnaTreeExpression) - | ElnaLexerKind.trait: - result := cast(elna_parser_trait_expression(cursor, error_list): ^ElnaTreeExpression) - | ElnaLexerKind.identifier: - result := cast(elna_parser_variable_expression(cursor): ^ElnaTreeExpression) - else - end -return result - -proc elna_parser_dereference_expression*(cursor: ^ElnaLexerCursor; - simple_expression: ^ElnaTreeExpression) -> ^ElnaTreeDereferenceExpression -var - result: ^ElnaTreeDereferenceExpression - token: ^ElnaLexerToken -begin - token := elna_lexer_read(cursor); - result := malloc#[ElnaTreeDereferenceExpression](#size(ElnaTreeDereferenceExpression)); - result^.kind := ElnaTreeKind.dereference_expression; - result^.pointer := simple_expression; - result^.type_decoration := nil; - result^.position := token^.position -return result - -proc elna_parser_field_access_expression*(cursor: ^ElnaLexerCursor; - aggregate: ^ElnaTreeExpression) -> ^ElnaTreeFieldAccessExpression -var - result: ^ElnaTreeFieldAccessExpression - token: ^ElnaLexerToken -begin - token := elna_lexer_read(cursor); - result := malloc#[ElnaTreeFieldAccessExpression](#size(ElnaTreeFieldAccessExpression)); - result^.kind := ElnaTreeKind.field_access_expression; - result^.type_decoration := nil; - result^.aggregate := aggregate; - result^.position.start_location := token^.position.start_location; - - token := elna_lexer_read(cursor); - result^.field := token^.start; - result^.position.end_location := token^.position.end_location -return result - -proc elna_parser_array_access_expression*(cursor: ^ElnaLexerCursor; - array: ^ElnaTreeExpression; error_list: ^ElnaList) -> ^ElnaTreeArrayAccessExpression -var - result: ^ElnaTreeArrayAccessExpression - token: ^ElnaLexerToken -begin - token := elna_lexer_read(cursor); - result := malloc#[ElnaTreeArrayAccessExpression](#size(ElnaTreeArrayAccessExpression)); - result^.kind := ElnaTreeKind.array_access_expression; - result^.type_decoration := nil; - result^.array := array; - result^.position.start_location := token^.position.start_location; - - result^.index := elna_parser_binary_expression(cursor, error_list); - if result^.index = nil then - result := free_and_nil(result) - else - token := elna_parser_expect(cursor, ElnaLexerKind.right_square, error_list); - if token = nil then - result := free_and_nil(result) - else - result^.position.end_location := token^.position.end_location - end - end -return result - -proc elna_parser_call*(cursor: ^ElnaLexerCursor; callee: ^ElnaTreeExpression; error_list: ^ElnaList) -> ^ElnaTreeCall -var - result: ^ElnaTreeCall - argument_entry: ^ElnaTreeExpressionList - token: ^ElnaLexerToken - parser_error: ^ElnaErrorUnexpectedToken - reading_args: Bool := true -begin - result := malloc#[ElnaTreeCall](#size(ElnaTreeCall)); - result^.kind := ElnaTreeKind.call; - result^.type_decoration := nil; - result^.arguments := nil; - result^.count := 0u; - result^.callee := cast(callee: ^ElnaTreeVariableExpression); - - token := elna_lexer_read(cursor); - result^.position.start_location := token^.position.start_location; - token := elna_lexer_peek(cursor); - - if token^.kind = ElnaLexerKind.right_paren then - token := elna_lexer_read(cursor); - result^.position.end_location := token^.position.end_location - else - while reading_args do - if result^.arguments = nil then - result^.arguments := malloc#[ElnaTreeExpressionList](#size(ElnaTreeExpressionList)); - argument_entry := result^.arguments - else - argument_entry^.next := malloc#[ElnaTreeExpressionList](#size(ElnaTreeExpressionList)); - argument_entry := argument_entry^.next - end; - argument_entry^.next := nil; - argument_entry^.expression := elna_parser_binary_expression(cursor, error_list); - if argument_entry^.expression = nil then - result := free_and_nil(result); - reading_args := false - else - result^.count := result^.count + 1u; - token := elna_lexer_peek(cursor); - if token^.kind = ElnaLexerKind.comma then - elna_lexer_read(cursor) - elsif token^.kind = ElnaLexerKind.right_paren then - token := elna_lexer_read(cursor); - result^.position.end_location := token^.position.end_location; - reading_args := false - else - parser_error := elna_error_unexpected_token_create(cursor, 2u); - parser_error^.expected[1] := ElnaLexerKind.comma; - parser_error^.expected[2] := ElnaLexerKind.right_paren; - elna_list_append(error_list, cast(parser_error: ^ElnaListNode)); - result := free_and_nil(result); - reading_args := false - end - end - end - end -return result - -proc elna_parser_designator*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeExpression -var - simple_expression: ^ElnaTreeExpression - token: ^ElnaLexerToken - continue_loop: Bool := true -begin - simple_expression := elna_parser_simple_expression(cursor, error_list); - if simple_expression <> nil then - while continue_loop do - token := elna_lexer_peek(cursor); - if token^.kind = ElnaLexerKind.hat then - simple_expression := cast(elna_parser_dereference_expression(cursor, simple_expression): ^ElnaTreeExpression) - elsif token^.kind = ElnaLexerKind.dot then - simple_expression := cast(elna_parser_field_access_expression(cursor, simple_expression): ^ElnaTreeExpression) - elsif token^.kind = ElnaLexerKind.left_square then - simple_expression := cast(elna_parser_array_access_expression(cursor, simple_expression, error_list): ^ElnaTreeExpression); - if simple_expression = nil then - continue_loop := false - end - elsif token^.kind = ElnaLexerKind.left_paren then - simple_expression := cast(elna_parser_call(cursor, simple_expression, error_list): ^ElnaTreeExpression); - if simple_expression = nil then - continue_loop := false - end - else - continue_loop := false - end - end - end -return simple_expression - -proc elna_parser_unary_expression*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeExpression -var - unary_result: ^ElnaTreeUnaryExpression - result: ^ElnaTreeExpression - op_kind: ElnaLexerKind - has_op: Bool := false - token: ^ElnaLexerToken -begin - token := elna_lexer_peek(cursor); - if token^.kind = ElnaLexerKind.at or token^.kind = ElnaLexerKind.minus or token^.kind = ElnaLexerKind.not then - op_kind := token^.kind; - has_op := true; - elna_lexer_read(cursor) - end; - result := elna_parser_designator(cursor, error_list); - if result <> nil & has_op then - unary_result := malloc#[ElnaTreeUnaryExpression](#size(ElnaTreeUnaryExpression)); - unary_result^.kind := ElnaTreeKind.unary_expression; - unary_result^.operand := result; - unary_result^.operator := op_kind; - unary_result^.position := token^.position; - unary_result^.type_decoration := nil; - result := cast(unary_result: ^ElnaTreeExpression) - end -return result - -proc elna_parser_binary_expression*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeExpression -var - lhs_node: ^ElnaTreeExpression - rhs_node: ^ElnaTreeExpression := nil - bin_result: ^ElnaTreeBinaryExpression - token: ^ElnaLexerToken -begin - lhs_node := elna_parser_unary_expression(cursor, error_list); - token := elna_lexer_peek(cursor); - - case token^.kind of - ElnaLexerKind.plus, - ElnaLexerKind.minus, - ElnaLexerKind.multiplication, - ElnaLexerKind.and, - ElnaLexerKind._or, - ElnaLexerKind._xor, - ElnaLexerKind.equals, - ElnaLexerKind.remainder, - ElnaLexerKind.division, - ElnaLexerKind.less_than, - ElnaLexerKind.greater_than, - ElnaLexerKind.less_equal, - ElnaLexerKind.not_equal, - ElnaLexerKind.greater_equal: - elna_lexer_read(cursor); - rhs_node := elna_parser_unary_expression(cursor, error_list) - else - end; - - if rhs_node <> nil then - bin_result := malloc#[ElnaTreeBinaryExpression](#size(ElnaTreeBinaryExpression)); - bin_result^.kind := ElnaTreeKind.binary_expression; - bin_result^.lhs := lhs_node; - bin_result^.rhs := rhs_node; - bin_result^.operator := token^.kind; - bin_result^.position := token^.position; - bin_result^.type_decoration := nil; - lhs_node := cast(bin_result: ^ElnaTreeExpression) - end -return lhs_node - -proc elna_parser_label_declaration*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeLabelDeclaration -var - result: ^ElnaTreeLabelDeclaration - token: ^ElnaLexerToken -begin - token := elna_lexer_read(cursor); - result := malloc#[ElnaTreeLabelDeclaration](#size(ElnaTreeLabelDeclaration)); - result^.kind := ElnaTreeKind.label_declaration; - result^.next := nil; - result^.position.start_location := token^.position.start_location; - - token := elna_parser_expect(cursor, ElnaLexerKind.identifier, error_list); - if token <> nil then - result^.label := token^.start; - result^.position.end_location := token^.position.end_location - else - result := free_and_nil(result) - end -return result - -proc elna_parser_assign_statement*(cursor: ^ElnaLexerCursor; assignee: ^ElnaTreeExpression; error_list: ^ElnaList) -> ^ElnaTreeAssignStatement -var - token: ^ElnaLexerToken - result: ^ElnaTreeAssignStatement -begin - result := malloc#[ElnaTreeAssignStatement](#size(ElnaTreeAssignStatement)); - result^.kind := ElnaTreeKind.assign_statement; - result^.next := nil; - result^.assignee := assignee; - result^.assignment := nil; - - token := elna_parser_expect(cursor, ElnaLexerKind.assignment, error_list); - if token <> nil then - result^.position := token^.position; - result^.assignment := elna_parser_binary_expression(cursor, error_list) - end; - if result^.assignment = nil then - result := free_and_nil(result) - end -return result - -proc elna_parser_return_statement*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeReturnStatement -var - token: ^ElnaLexerToken - result: ^ElnaTreeReturnStatement -begin - token := elna_lexer_read(cursor); - result := malloc#[ElnaTreeReturnStatement](#size(ElnaTreeReturnStatement)); - result^.kind := ElnaTreeKind.return_statement; - result^.next := nil; - result^.position := token^.position; - result^.returned := elna_parser_binary_expression(cursor, error_list); - if result^.returned = nil then - result := free_and_nil(result) - end -return result - -proc elna_parser_conditional_statements*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList; - block_keyword: ElnaLexerKind) -> ^ElnaTreeConditionalStatements -var - result: ^ElnaTreeConditionalStatements -begin - result := malloc#[ElnaTreeConditionalStatements](#size(ElnaTreeConditionalStatements)); - elna_lexer_read(cursor); - result^.condition := elna_parser_binary_expression(cursor, error_list); - if result^.condition = nil then - result := free_and_nil(result) - else - if elna_parser_expect(cursor, block_keyword, error_list) <> nil then - result^.statements := elna_parser_statements(cursor, error_list) - end; - if elna_list_empty(error_list) then - result^.next := nil - else - result := free_and_nil(result) - end - end -return result - -proc elna_parser_if_statement*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeIfStatement -var - result: ^ElnaTreeIfStatement - previous_conditional: ^ElnaTreeConditionalStatements - next_conditional: ^ElnaTreeConditionalStatements - token: ^ElnaLexerToken - reading_elsif: Bool := true -begin - token := elna_lexer_peek(cursor); - result := malloc#[ElnaTreeIfStatement](#size(ElnaTreeIfStatement)); - result^.kind := ElnaTreeKind.if_statement; - result^.position := token^.position; - result^.next := nil; - - previous_conditional := elna_parser_conditional_statements(cursor, error_list, ElnaLexerKind._then); - result^.conditionals := previous_conditional; - - while reading_elsif do - token := elna_lexer_peek(cursor); - if token^.kind = ElnaLexerKind._elsif then - next_conditional := elna_parser_conditional_statements(cursor, error_list, ElnaLexerKind._then); - previous_conditional^.next := next_conditional; - previous_conditional := next_conditional - elsif token^.kind = ElnaLexerKind._else then - elna_lexer_read(cursor); - result^._else := elna_parser_statements(cursor, error_list); - reading_elsif := false - else - result^._else := nil; - reading_elsif := false - end - end; - elna_parser_expect(cursor, ElnaLexerKind._end, error_list) -return result - -proc elna_parser_statement*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeStatement -var - result: ^ElnaTreeStatement := nil - call_result: ^ElnaTreeCallStatement - designator: ^ElnaTreeExpression - token: ^ElnaLexerToken -begin - token := elna_lexer_peek(cursor); - if token^.kind = ElnaLexerKind._if then - result := cast(elna_parser_if_statement(cursor, error_list): ^ElnaTreeStatement) - elsif token^.kind = ElnaLexerKind._return then - result := cast(elna_parser_return_statement(cursor, error_list): ^ElnaTreeStatement) - elsif token^.kind = ElnaLexerKind.dot then - result := cast(elna_parser_label_declaration(cursor, error_list): ^ElnaTreeStatement) - elsif token^.kind = ElnaLexerKind.identifier then - designator := elna_parser_designator(cursor, error_list); - if designator <> nil then - if designator^.kind <> ElnaTreeKind.call then - result := cast(elna_parser_assign_statement(cursor, designator, error_list): ^ElnaTreeStatement) - else - call_result := malloc#[ElnaTreeCallStatement](#size(ElnaTreeCallStatement)); - call_result^.kind := ElnaTreeKind.call_statement; - call_result^.next := nil; - call_result^.call := cast(designator: ^ElnaTreeCall); - call_result^.position := designator^.position; - result := cast(call_result: ^ElnaTreeStatement) - end - end - end -return result - -proc elna_parser_statements*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeStatement -var - previous_statement: ^ElnaTreeStatement - next_statement: ^ElnaTreeStatement - first_statement: ^ElnaTreeStatement - token: ^ElnaLexerToken -begin - elna_lexer_skip_empty_lines(cursor); - first_statement := elna_parser_statement(cursor, error_list); - previous_statement := first_statement; - if previous_statement <> nil then - token := elna_lexer_peek(cursor); - while token^.kind = ElnaLexerKind.semicolon & elna_list_empty(error_list) do - elna_lexer_read(cursor); - elna_lexer_skip_empty_lines(cursor); - next_statement := elna_parser_statement(cursor, error_list); - previous_statement^.next := next_statement; - previous_statement := next_statement; - token := elna_lexer_peek(cursor) - end - end; - elna_lexer_skip_empty_lines(cursor) -return first_statement - -proc elna_parser_named_type_expression*(cursor: ^ElnaLexerCursor) -> ^ElnaTreeNamedTypeExpression -var - result: ^ElnaTreeNamedTypeExpression - token: ^ElnaLexerToken -begin - result := malloc#[ElnaTreeNamedTypeExpression](#size(ElnaTreeNamedTypeExpression)); - token := elna_lexer_read(cursor); - result^.kind := ElnaTreeKind.named_type_expression; - result^.name := token^.start; - result^.position := token^.position -return result - -proc elna_parser_pointer_type_expression*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreePointerTypeExpression -var - result: ^ElnaTreePointerTypeExpression - token: ^ElnaLexerToken -begin - token := elna_lexer_read(cursor); - result := malloc#[ElnaTreePointerTypeExpression](#size(ElnaTreePointerTypeExpression)); - result^.kind := ElnaTreeKind.pointer_type_expression; - result^.base := elna_parser_type_expression(cursor, error_list); - result^.position := token^.position; - if result^.base = nil then - result := free_and_nil(result) - end -return result - -proc elna_parser_array_type_expression*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeArrayTypeExpression -var - result: ^ElnaTreeArrayTypeExpression - token: ^ElnaLexerToken -begin - token := elna_lexer_read(cursor); - result := malloc#[ElnaTreeArrayTypeExpression](#size(ElnaTreeArrayTypeExpression)); - result^.kind := ElnaTreeKind.array_type_expression; - result^.position.start_location := token^.position.start_location; - - result^.length := elna_parser_binary_expression(cursor, error_list); - if result^.length = nil then - result := free_and_nil(result) - else - token := elna_parser_expect(cursor, ElnaLexerKind.right_square, error_list); - if token = nil then - result := free_and_nil(result) - else - result^.base := elna_parser_type_expression(cursor, error_list); - if result^.base = nil then - result := free_and_nil(result) - else - result^.position.end_location := token^.position.end_location - end - end - end -return result - -proc elna_parser_record_type_expression*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeRecordTypeExpression -var - entry: ^ElnaTreeField - result: ^ElnaTreeRecordTypeExpression - previous_entry: ^ElnaTreeField - token: ^ElnaLexerToken - parser_error: ^ElnaErrorUnexpectedToken - reading_members: Bool := true -begin - token := elna_lexer_read(cursor); - result := malloc#[ElnaTreeRecordTypeExpression](#size(ElnaTreeRecordTypeExpression)); - result^.kind := ElnaTreeKind.record_type_expression; - result^.members := nil; - result^.length := 0u; - result^.position := token^.position; - - token := elna_lexer_peek(cursor); - if token^.kind = ElnaLexerKind.left_paren then - elna_lexer_read(cursor); - token := elna_parser_expect(cursor, ElnaLexerKind.identifier, error_list); - if token = nil then - result := free_and_nil(result); - reading_members := false - else - result^.parent := token^.start; - if elna_parser_expect(cursor, ElnaLexerKind.right_paren, error_list) = nil then - result := free_and_nil(result); - reading_members := false - end - end - end; - - while reading_members & result <> nil do - token := elna_lexer_read(cursor); - if token^.kind = ElnaLexerKind._end then - reading_members := false - elsif token^.kind <> ElnaLexerKind.identifier then - parser_error := elna_error_unexpected_token_create(cursor, 2u); - parser_error^.expected[1] := ElnaLexerKind._end; - parser_error^.expected[2] := ElnaLexerKind.identifier; - elna_list_append(error_list, cast(parser_error: ^ElnaListNode)); - result := free_and_nil(result); - reading_members := false - else - entry := malloc#[ElnaTreeField](#size(ElnaTreeField)); - result^.length := result^.length + 1u; - entry^.name := token^.start; - if elna_parser_expect(cursor, ElnaLexerKind.colon, error_list) = nil then - result := free_and_nil(result); - reading_members := false - else - entry^.type_expression := elna_parser_type_expression(cursor, error_list); - if entry^.type_expression = nil then - result := free_and_nil(result); - reading_members := false - else - entry^.next := nil; - if result^.members = nil then - result^.members := entry - else - previous_entry^.next := entry - end; - previous_entry := entry; - - token := elna_lexer_read(cursor); - if token^.kind = ElnaLexerKind.semicolon then - (* continue *) - elsif token^.kind = ElnaLexerKind._end then - reading_members := false - else - parser_error := elna_error_unexpected_token_create(cursor, 2u); - parser_error^.expected[1] := ElnaLexerKind._end; - parser_error^.expected[2] := ElnaLexerKind.semicolon; - elna_list_append(error_list, cast(parser_error: ^ElnaListNode)); - reading_members := false - end - end - end - end - end -return result - -proc elna_parser_enumeration_type_expression*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeEnumerationTypeExpression -var - result: ^ElnaTreeEnumerationTypeExpression - entry: ^ElnaTreeEnumeration - previous_entry: ^ElnaTreeEnumeration - token: ^ElnaLexerToken - parser_error: ^ElnaErrorUnexpectedToken - reading_members: Bool := true -begin - token := elna_lexer_read(cursor); - result := malloc#[ElnaTreeEnumerationTypeExpression](#size(ElnaTreeEnumerationTypeExpression)); - result^.kind := ElnaTreeKind.enumeration_type_expression; - result^.members := nil; - result^.length := 0u; - result^.position.start_location := token^.position.start_location; - - while reading_members & result <> nil do - token := elna_parser_expect(cursor, ElnaLexerKind.identifier, error_list); - if token = nil then - result := free_and_nil(result); - reading_members := false - else - entry := malloc#[ElnaTreeEnumeration](#size(ElnaTreeEnumeration)); - result^.length := result^.length + 1u; - entry^.name := token^.start; - entry^.next := nil; - if result^.members = nil then - result^.members := entry - else - previous_entry^.next := entry - end; - previous_entry := entry; - - token := elna_lexer_peek(cursor); - if token^.kind = ElnaLexerKind.comma then - elna_lexer_read(cursor) - elsif token^.kind = ElnaLexerKind.right_paren then - token := elna_lexer_read(cursor); - result^.position.end_location := token^.position.end_location; - reading_members := false - else - parser_error := elna_error_unexpected_token_create(cursor, 2u); - parser_error^.expected[1] := ElnaLexerKind.comma; - parser_error^.expected[2] := ElnaLexerKind.right_paren; - elna_list_append(error_list, cast(parser_error: ^ElnaListNode)); - result := free_and_nil(result); - reading_members := false - end - end - end -return result - -proc elna_parser_type_expression*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeTypeExpression -var - result: ^ElnaTreeTypeExpression := nil - token: ^ElnaLexerToken - parser_error: ^ElnaErrorUnexpectedToken -begin - token := elna_lexer_peek(cursor); - if token^.kind = ElnaLexerKind.identifier then - result := cast(elna_parser_named_type_expression(cursor): ^ElnaTreeTypeExpression) - elsif token^.kind = ElnaLexerKind.left_paren then - result := cast(elna_parser_enumeration_type_expression(cursor, error_list): ^ElnaTreeTypeExpression) - elsif token^.kind = ElnaLexerKind._record then - result := cast(elna_parser_record_type_expression(cursor, error_list): ^ElnaTreeTypeExpression) - elsif token^.kind = ElnaLexerKind.hat then - result := cast(elna_parser_pointer_type_expression(cursor, error_list): ^ElnaTreeTypeExpression) - elsif token^.kind = ElnaLexerKind.left_square then - result := cast(elna_parser_array_type_expression(cursor, error_list): ^ElnaTreeTypeExpression) - else - parser_error := elna_error_unexpected_token_create(cursor, 5u); - parser_error^.expected[1] := ElnaLexerKind.identifier; - parser_error^.expected[2] := ElnaLexerKind.left_paren; - parser_error^.expected[3] := ElnaLexerKind._record; - parser_error^.expected[4] := ElnaLexerKind.hat; - parser_error^.expected[5] := ElnaLexerKind.left_square; - elna_list_append(error_list, cast(parser_error: ^ElnaListNode)) - end -return result - -proc elna_parser_variable_declaration*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeVariableDeclaration -var - var_type: ^ElnaTreeTypeExpression - result: ^ElnaTreeVariableDeclaration := nil - token: ^ElnaLexerToken -begin - token := elna_parser_expect(cursor, ElnaLexerKind.identifier, error_list); - if token <> nil then - if elna_parser_expect(cursor, ElnaLexerKind.colon, error_list) <> nil then - var_type := elna_parser_type_expression(cursor, error_list); - if var_type <> nil then - result := malloc#[ElnaTreeVariableDeclaration](#size(ElnaTreeVariableDeclaration)); - result^.kind := ElnaTreeKind.variable_declaration; - result^.next := nil; - result^.name := token^.start; - result^.type_expression := var_type; - result^.position := token^.position - end - end - end -return result - -proc elna_parser_parameters*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeVariableDeclaration -var - parameters: ^ElnaTreeVariableDeclaration := nil - token: ^ElnaLexerToken - current_declaration: ^ElnaTreeVariableDeclaration - next_declaration: ^ElnaTreeVariableDeclaration - reading: Bool := true -begin - token := elna_lexer_peek(cursor); - if token^.kind <> ElnaLexerKind.right_paren then - while reading do - next_declaration := elna_parser_variable_declaration(cursor, error_list); - if next_declaration = nil then - parameters := free_and_nil(parameters); - reading := false - else - if parameters = nil then - parameters := next_declaration - else - current_declaration^.next := cast(next_declaration: ^ElnaTreeDeclaration) - end; - current_declaration := next_declaration; - - token := elna_lexer_peek(cursor); - if token^.kind = ElnaLexerKind.comma or token^.kind = ElnaLexerKind.semicolon then - elna_lexer_read(cursor) - else - reading := false - end - end - end - end -return parameters - -proc elna_parser_procedure_declaration*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeProcedureDeclaration -var - result: ^ElnaTreeProcedureDeclaration - token: ^ElnaLexerToken -begin - token := elna_lexer_read(cursor); - result := malloc#[ElnaTreeProcedureDeclaration](#size(ElnaTreeProcedureDeclaration)); - result^.kind := ElnaTreeKind.procedure_declaration; - result^.next := nil; - result^.position := token^.position; - - token := elna_parser_expect(cursor, ElnaLexerKind.identifier, error_list); - if token = nil then - result := free_and_nil(result) - else - result^.name := token^.start; - - if elna_parser_expect(cursor, ElnaLexerKind.left_paren, error_list) = nil then - result := free_and_nil(result) - else - result^.parameters := elna_parser_parameters(cursor, error_list); - if elna_list_empty(error_list) = false then - result := free_and_nil(result) - elsif elna_parser_expect(cursor, ElnaLexerKind.right_paren, error_list) = nil then - result := free_and_nil(result) - else - token := elna_lexer_peek(cursor); - if token^.kind = ElnaLexerKind.arrow then - elna_lexer_read(cursor); - result^.return_type := elna_parser_type_expression(cursor, error_list); - if result^.return_type = nil then - result := free_and_nil(result) - end - else - result^.return_type := nil - end; - - if result <> nil then - token := elna_lexer_peek(cursor); - result^.is_extern := token^.kind = ElnaLexerKind._extern; - if result^.is_extern then - elna_lexer_read(cursor); - result^.temporaries := nil; - result^.body := nil - else - result^.temporaries := elna_parser_var_part(cursor, error_list); - if elna_list_empty(error_list) = false then - result := free_and_nil(result) - else - token := elna_lexer_peek(cursor); - if token^.kind = ElnaLexerKind._begin then - elna_lexer_read(cursor); - result^.body := elna_parser_statements(cursor, error_list); - if elna_list_empty(error_list) = false then - result := free_and_nil(result) - elsif elna_parser_expect(cursor, ElnaLexerKind._end, error_list) = nil then - result := free_and_nil(result) - end - elsif token^.kind = ElnaLexerKind._return then - result^.body := cast(elna_parser_return_statement(cursor, error_list): ^ElnaTreeStatement); - if result^.body = nil then - result := free_and_nil(result) - end - end - end - end - end - end - end - end -return result - -proc elna_parser_procedures*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeProcedureDeclaration -var - parser_node: ^ElnaTreeProcedureDeclaration - result: ^ElnaTreeProcedureDeclaration := nil - current_declaration: ^ElnaTreeProcedureDeclaration - token: ^ElnaLexerToken - reading: Bool := true -begin - while reading do - elna_lexer_skip_empty_lines(cursor); - token := elna_lexer_peek(cursor); - if token^.kind = ElnaLexerKind._proc then - parser_node := elna_parser_procedure_declaration(cursor, error_list); - if parser_node <> nil then - if result = nil then - result := parser_node - else - current_declaration^.next := cast(parser_node: ^ElnaTreeDeclaration) - end; - current_declaration := parser_node - else - reading := false - end - else - reading := false - end - end -return result - -proc elna_parser_type_declaration*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeTypeDeclaration -var - result: ^ElnaTreeTypeDeclaration - token: ^ElnaLexerToken -begin - token := elna_lexer_read(cursor); - result := malloc#[ElnaTreeTypeDeclaration](#size(ElnaTreeTypeDeclaration)); - result^.kind := ElnaTreeKind.type_declaration; - result^.next := nil; - result^.name := token^.start; - result^.position := token^.position; - - if elna_parser_expect(cursor, ElnaLexerKind.equals, error_list) <> nil then - result^.type_expression := elna_parser_type_expression(cursor, error_list) - else - result := free_and_nil(result) - end -return result - -proc elna_parser_type_part*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeDeclaration -var - parser_node: ^ElnaTreeDeclaration - result: ^ElnaTreeDeclaration := nil - current_declaration: ^ElnaTreeDeclaration - token: ^ElnaLexerToken - reading: Bool := true -begin - elna_lexer_skip_empty_lines(cursor); - token := elna_lexer_peek(cursor); - if token^.kind = ElnaLexerKind._type then - elna_lexer_read(cursor); - while reading do - elna_lexer_skip_empty_lines(cursor); - token := elna_lexer_peek(cursor); - if token^.kind = ElnaLexerKind.identifier then - parser_node := cast(elna_parser_type_declaration(cursor, error_list): ^ElnaTreeDeclaration); - if parser_node <> nil then - if result = nil then - result := parser_node - else - current_declaration^.next := parser_node - end; - current_declaration := parser_node; - token := elna_lexer_peek(cursor); - if token^.kind = ElnaLexerKind.semicolon then - elna_lexer_read(cursor) - end - else - reading := false - end - else - reading := false - end - end - end -return result - -proc elna_parser_var_part*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeVariableDeclaration -var - result: ^ElnaTreeVariableDeclaration := nil - variable_node: ^ElnaTreeVariableDeclaration - current_declaration: ^ElnaTreeVariableDeclaration - token: ^ElnaLexerToken - reading: Bool := true -begin - token := elna_lexer_peek(cursor); - if token^.kind = ElnaLexerKind._var then - elna_lexer_read(cursor); - while reading do - elna_lexer_skip_empty_lines(cursor); - token := elna_lexer_peek(cursor); - if token^.kind = ElnaLexerKind.identifier then - variable_node := elna_parser_variable_declaration(cursor, error_list); - if variable_node <> nil then - if result = nil then - result := variable_node - else - current_declaration^.next := cast(variable_node: ^ElnaTreeDeclaration) - end; - current_declaration := variable_node; - token := elna_lexer_peek(cursor); - if token^.kind = ElnaLexerKind.semicolon then - elna_lexer_read(cursor) - end - else - reading := false - end - else - reading := false - end - end - end -return result - -proc elna_parser_program_body*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeStatement -var - result: ^ElnaTreeStatement := nil - token: ^ElnaLexerToken -begin - elna_lexer_skip_empty_lines(cursor); - token := elna_lexer_peek(cursor); - if token^.kind = ElnaLexerKind._begin then - elna_lexer_read(cursor); - result := elna_parser_statements(cursor, error_list); - if elna_parser_expect(cursor, ElnaLexerKind._end, error_list) = nil then - result := free_and_nil(result) - elsif elna_parser_expect(cursor, ElnaLexerKind.dot, error_list) = nil then - result := free_and_nil(result) - end - elsif token^.kind = ElnaLexerKind._end then - elna_lexer_read(cursor); - if elna_parser_expect(cursor, ElnaLexerKind.dot, error_list) = nil then - result := free_and_nil(result) - end - end -return result - -proc elna_parser_module_declaration*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeModuleDeclaration -var - result: ^ElnaTreeModuleDeclaration -begin - result := malloc#[ElnaTreeModuleDeclaration](#size(ElnaTreeModuleDeclaration)); - result^.kind := ElnaTreeKind.module_declaration; - result^.position.start_location := { ElnaLocation; line: 1u, column: 1u }; - result^.position.end_location := result^.position.start_location; - - result^.types := elna_parser_type_part(cursor, error_list); - if elna_list_empty(error_list) = false then - result := free_and_nil(result) - end; - - if result <> nil then - result^.globals := elna_parser_var_part(cursor, error_list); - if elna_list_empty(error_list) = false then - result := free_and_nil(result) - end - end; - - if result <> nil then - result^.procedures := elna_parser_procedures(cursor, error_list); - if elna_list_empty(error_list) = false then - result := free_and_nil(result) - end - end; - - if result <> nil then - result^.body := elna_parser_program_body(cursor, error_list); - if elna_list_empty(error_list) = false then - result := free_and_nil(result) - end - end -return result - -end. diff --git a/source/qbe.elna b/source/qbe.elna deleted file mode 100644 index 47eac88..0000000 --- a/source/qbe.elna +++ /dev/null @@ -1,635 +0,0 @@ -(* 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 common, sys.posix.cstdlib, sys.posix.cstdio, sys.posix.cstring, lexer, ast, symbol, tac - -var - qbe_unique_id: Word := 0u - -proc qbe_write_slice(file: ^FILE; text: []const Word8) -begin - fwrite#[Word8](text.ptr, 1u, text.length, file) -return - -proc qbe_write_str(file: ^FILE; str: ^const Word8) -begin - fwrite#[Word8](str, 1u, strlen(str), file) -return - -proc qbe_write_word(file: ^FILE; val: Word) -var - buf: [32]Word8 - len: Int -begin - len := sprintf(@buf[1], "%u\0".ptr, val); - fwrite#[Word8](@buf[1], 1u, cast(len: Word), file) -return - -proc is_global(globals: ^ElnaTacStaticVariable; name: []const Word8) -> Bool -var - current: ^ElnaTacStaticVariable - found: Bool := false -begin - current := globals; - while current <> nil & ~found do - if current^.name = name then - found := true - else - current := current^.next - end - end -return found - -proc is_string_constant(strings: ^ElnaTacStringConstant; name: []const Word8) -> Bool -var - current: ^ElnaTacStringConstant - found: Bool := false -begin - current := strings; - while current <> nil & ~found do - if current^.name = name then - found := true - else - current := current^.next - end - end -return found - -proc is_pointer_type(_type: ^ElnaType) -> Bool -var - result: Bool := false -begin - if _type <> nil then - if _type^.kind = ElnaTypeKind.pointer then - result := true - elsif _type = pointer_type then - result := true - end - end -return result - -proc get_procedure_return_type(proc_name: []const Word8) -> ^ElnaType -var - symbol_info: ^ElnaSymbolInfo - procedure_info: ^ElnaSymbolProcedureInfo - result: ^ElnaType := nil -begin - symbol_info := elna_symbol_table_lookup(symbol_table_global, proc_name); - if symbol_info <> nil & symbol_info^.kind = ElnaSymbolInfoKind.procedure_info then - procedure_info := cast(symbol_info: ^ElnaSymbolProcedureInfo); - if procedure_info^.procedure_type <> nil then - result := procedure_info^.procedure_type^.return_type - end - end -return result - -proc get_param_type(sym_table: ^ElnaSymbolTable; param_name: []const Word8) -> ^ElnaType -var - symbol_info: ^ElnaSymbolInfo - temp_info: ^ElnaSymbolTemporaryInfo - result: ^ElnaType := nil -begin - symbol_info := elna_symbol_table_lookup(sym_table, param_name); - if symbol_info <> nil & symbol_info^.kind = ElnaSymbolInfoKind.temporary_info then - temp_info := cast(symbol_info: ^ElnaSymbolTemporaryInfo); - result := temp_info^.variable_type - end -return result - -proc is_pointer_operand(op: ^ElnaTacOperand; sym_table: ^ElnaSymbolTable; - globals: ^ElnaTacStaticVariable; strings: ^ElnaTacStringConstant) -> Bool -var - var_type: ^ElnaType - result: Bool := false -begin - if op^.kind = ElnaTacKind.variable then - if is_global(globals, op^.name) or is_string_constant(strings, op^.name) then - result := true - else - var_type := get_param_type(sym_table, op^.name); - if is_pointer_type(var_type) then - result := true - end - end - end -return result - -proc qbe_emit_operand(file: ^FILE; op: ^ElnaTacOperand; - globals: ^ElnaTacStaticVariable; strings: ^ElnaTacStringConstant) -begin - case op^.kind of - ElnaTacKind.constant: - qbe_write_word(file, op^.constant) - | ElnaTacKind.variable: - if is_global(globals, op^.name) or is_string_constant(strings, op^.name) then - qbe_write_str(file, "$\0".ptr) - else - qbe_write_str(file, "%\0".ptr) - end; - qbe_write_slice(file, op^.name) - | ElnaTacKind.label: - qbe_write_str(file, "@\0".ptr); - qbe_write_slice(file, op^.name) - else - end -return - -proc var_needs_stack_alloc(instructions: ^ElnaList; sym_table: ^ElnaSymbolTable; name: []const Word8) -> Bool -var - node: ^ElnaListNode - inst: ^ElnaTacInstruction - var_type: ^ElnaType - result: Bool := false -begin - var_type := get_param_type(sym_table, name); - if var_type <> nil then - if var_type^.kind = ElnaTypeKind._record or var_type^.kind = ElnaTypeKind.array then - result := true - end - end; - - node := instructions^.first; - while node <> nil & ~result do - inst := cast(node: ^ElnaTacInstruction); - if inst^.operator = ElnaTacOperator.get_address & inst^.operands[1].name = name then - result := true - elsif inst^.operator = ElnaTacOperator.copy_to_offset & inst^.operands[2].name = name then - result := true - elsif inst^.operator = ElnaTacOperator.copy_from_offset & inst^.operands[1].name = name then - result := true - end; - node := node^.next - end -return result - -proc qbe_emit_procedure(file: ^FILE; proc_node: ^ElnaTacProcedure; - globals: ^ElnaTacStaticVariable; strings: ^ElnaTacStringConstant) -var - node: ^ElnaListNode - inst: ^ElnaTacInstruction - ret_type: ^ElnaType - param_idx: Word := 0u - param_name: []const Word8 - param_type: ^ElnaType - entry: ^ElnaSymbolEntry - temp_info: ^ElnaSymbolTemporaryInfo - sym_idx: Word := 0u - alloc_size: Word - last_operator: ElnaTacOperator := ElnaTacOperator.nop - tid: Word - arg_i: Word - arg_op: ^ElnaTacOperand - callee_ret: ^ElnaType - scaled: Word -begin - qbe_write_str(file, "export function \0".ptr); - ret_type := get_procedure_return_type(proc_node^.name); - - if proc_node^.name = "main" then - qbe_write_str(file, "w \0".ptr) - elsif ret_type <> nil then - if ret_type = bool_type then - qbe_write_str(file, "w \0".ptr) - else - qbe_write_str(file, "l \0".ptr) - end - end; - - qbe_write_str(file, "$\0".ptr); - qbe_write_slice(file, proc_node^.name); - qbe_write_str(file, "(\0".ptr); - - while param_idx < proc_node^.count do - param_name := (proc_node^.parameters + param_idx)^; - param_type := get_param_type(proc_node^.symbol_table, param_name); - if param_type = bool_type then - qbe_write_str(file, "w %\0".ptr) - else - qbe_write_str(file, "l %\0".ptr) - end; - qbe_write_slice(file, param_name); - if param_idx + 1u < proc_node^.count then - qbe_write_str(file, ", \0".ptr) - end; - param_idx := param_idx + 1u - end; - - qbe_write_str(file, ") {\n@start\n\0".ptr); - - (* Stack allocate variables needing memory address *) - if proc_node^.symbol_table <> nil then - while sym_idx < proc_node^.symbol_table^.count do - entry := proc_node^.symbol_table^.symbols + sym_idx; - if entry^.name.length > 0u & entry^.symbol_info <> nil then - if entry^.symbol_info^.kind = ElnaSymbolInfoKind.temporary_info then - temp_info := cast(entry^.symbol_info: ^ElnaSymbolTemporaryInfo); - if var_needs_stack_alloc(@proc_node^.body, proc_node^.symbol_table, entry^.name) then - alloc_size := 8u; - if temp_info^.variable_type <> nil & temp_info^.variable_type^.size > 8u then - alloc_size := (temp_info^.variable_type^.size + 7u) / 8u * 8u - end; - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, entry^.name); - qbe_write_str(file, " =l alloc8 \0".ptr); - qbe_write_word(file, alloc_size); - qbe_write_str(file, "\n\0".ptr) - end - end - end; - sym_idx := sym_idx + 1u - end - end; - - (* Emit TAC instructions *) - node := proc_node^.body.first; - while node <> nil do - inst := cast(node: ^ElnaTacInstruction); - last_operator := inst^.operator; - - case inst^.operator of - ElnaTacOperator.get_address: - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[2].name); - qbe_write_str(file, " =l copy \0".ptr); - if is_global(globals, inst^.operands[1].name) or is_string_constant(strings, inst^.operands[1].name) then - qbe_write_str(file, "$\0".ptr) - else - qbe_write_str(file, "%\0".ptr) - end; - qbe_write_slice(file, inst^.operands[1].name); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator.copy: - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[2].name); - qbe_write_str(file, " =l copy \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator.add: - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[3].name); - qbe_write_str(file, " =l add \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", \0".ptr); - qbe_emit_operand(file, @inst^.operands[2], globals, strings); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator.subtract: - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[3].name); - qbe_write_str(file, " =l sub \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", \0".ptr); - qbe_emit_operand(file, @inst^.operands[2], globals, strings); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator.multiply: - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[3].name); - qbe_write_str(file, " =l mul \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", \0".ptr); - qbe_emit_operand(file, @inst^.operands[2], globals, strings); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator.divide: - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[3].name); - qbe_write_str(file, " =l div \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", \0".ptr); - qbe_emit_operand(file, @inst^.operands[2], globals, strings); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator.remainder: - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[3].name); - qbe_write_str(file, " =l rem \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", \0".ptr); - qbe_emit_operand(file, @inst^.operands[2], globals, strings); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator._or: - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[3].name); - qbe_write_str(file, " =l or \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", \0".ptr); - qbe_emit_operand(file, @inst^.operands[2], globals, strings); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator._xor: - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[3].name); - qbe_write_str(file, " =l xor \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", \0".ptr); - qbe_emit_operand(file, @inst^.operands[2], globals, strings); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator.and: - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[3].name); - qbe_write_str(file, " =l and \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", \0".ptr); - qbe_emit_operand(file, @inst^.operands[2], globals, strings); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator.equal: - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[3].name); - qbe_write_str(file, " =w ceql \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", \0".ptr); - qbe_emit_operand(file, @inst^.operands[2], globals, strings); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator.not_equal: - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[3].name); - qbe_write_str(file, " =w cnew \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", \0".ptr); - qbe_emit_operand(file, @inst^.operands[2], globals, strings); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator.less_than: - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[3].name); - qbe_write_str(file, " =w csltl \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", \0".ptr); - qbe_emit_operand(file, @inst^.operands[2], globals, strings); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator.greater_than: - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[3].name); - qbe_write_str(file, " =w csgtl \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", \0".ptr); - qbe_emit_operand(file, @inst^.operands[2], globals, strings); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator.less_or_equal: - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[3].name); - qbe_write_str(file, " =w cslel \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", \0".ptr); - qbe_emit_operand(file, @inst^.operands[2], globals, strings); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator.greater_or_equal: - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[3].name); - qbe_write_str(file, " =w csgel \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", \0".ptr); - qbe_emit_operand(file, @inst^.operands[2], globals, strings); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator.negate: - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[2].name); - qbe_write_str(file, " =l neg \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator.complement: - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[2].name); - qbe_write_str(file, " =l xor \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", -1\n\0".ptr) - | ElnaTacOperator.load: - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[2].name); - qbe_write_str(file, " =l loadl \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator.store: - qbe_write_str(file, "\tstorel \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", \0".ptr); - qbe_emit_operand(file, @inst^.operands[2], globals, strings); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator.copy_to_offset: - if inst^.operands[3].constant = 0u then - qbe_write_str(file, "\tstorel \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", \0".ptr); - qbe_emit_operand(file, @inst^.operands[2], globals, strings); - qbe_write_str(file, "\n\0".ptr) - else - qbe_unique_id := qbe_unique_id + 1u; - tid := qbe_unique_id; - qbe_write_str(file, "\t%qbe_off_\0".ptr); - qbe_write_word(file, tid); - qbe_write_str(file, " =l add \0".ptr); - qbe_emit_operand(file, @inst^.operands[2], globals, strings); - qbe_write_str(file, ", \0".ptr); - qbe_write_word(file, inst^.operands[3].constant); - qbe_write_str(file, "\n\tstorel \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", %qbe_off_\0".ptr); - qbe_write_word(file, tid); - qbe_write_str(file, "\n\0".ptr) - end - | ElnaTacOperator.copy_from_offset: - if inst^.operands[2].constant = 0u then - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[3].name); - qbe_write_str(file, " =l loadl \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, "\n\0".ptr) - else - qbe_unique_id := qbe_unique_id + 1u; - tid := qbe_unique_id; - qbe_write_str(file, "\t%qbe_off_\0".ptr); - qbe_write_word(file, tid); - qbe_write_str(file, " =l add \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", \0".ptr); - qbe_write_word(file, inst^.operands[2].constant); - qbe_write_str(file, "\n\t%\0".ptr); - qbe_write_slice(file, inst^.operands[3].name); - qbe_write_str(file, " =l loadl %qbe_off_\0".ptr); - qbe_write_word(file, tid); - qbe_write_str(file, "\n\0".ptr) - end - | ElnaTacOperator.add_ptr: - qbe_unique_id := qbe_unique_id + 1u; - tid := qbe_unique_id; - if inst^.operands[2].kind = ElnaTacKind.constant then - if inst^.operands[3].constant = 1u then - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[4].name); - qbe_write_str(file, " =l add \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", \0".ptr); - qbe_write_word(file, inst^.operands[2].constant); - qbe_write_str(file, "\n\0".ptr) - else - scaled := inst^.operands[2].constant * inst^.operands[3].constant; - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[4].name); - qbe_write_str(file, " =l add \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", \0".ptr); - qbe_write_word(file, scaled); - qbe_write_str(file, "\n\0".ptr) - end - else - qbe_write_str(file, "\t%qbe_ext_\0".ptr); - qbe_write_word(file, tid); - qbe_write_str(file, " =l extuw \0".ptr); - qbe_emit_operand(file, @inst^.operands[2], globals, strings); - qbe_write_str(file, "\n\0".ptr); - - if inst^.operands[3].constant = 1u then - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[4].name); - qbe_write_str(file, " =l add \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", %qbe_ext_\0".ptr); - qbe_write_word(file, tid); - qbe_write_str(file, "\n\0".ptr) - else - qbe_write_str(file, "\t%qbe_s_\0".ptr); - qbe_write_word(file, tid); - qbe_write_str(file, " =l mul %qbe_ext_\0".ptr); - qbe_write_word(file, tid); - qbe_write_str(file, ", \0".ptr); - qbe_write_word(file, inst^.operands[3].constant); - qbe_write_str(file, "\n\t%\0".ptr); - qbe_write_slice(file, inst^.operands[4].name); - qbe_write_str(file, " =l add \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", %qbe_s_\0".ptr); - qbe_write_word(file, tid); - qbe_write_str(file, "\n\0".ptr) - end - end - | ElnaTacOperator.proc_call: - callee_ret := get_procedure_return_type(inst^.operands[1].name); - if inst^.operands[3].kind = ElnaTacKind.ignore then - qbe_write_str(file, "\tcall $\0".ptr) - else - qbe_write_str(file, "\t%\0".ptr); - qbe_write_slice(file, inst^.operands[3].name); - if callee_ret = bool_type then - qbe_write_str(file, " =w call $\0".ptr) - else - qbe_write_str(file, " =l call $\0".ptr) - end - end; - qbe_write_slice(file, inst^.operands[1].name); - qbe_write_str(file, "(\0".ptr); - - arg_i := 0u; - while arg_i < inst^.operands[2].length do - arg_op := inst^.operands[2].list_operands + arg_i; - qbe_write_str(file, "l \0".ptr); - qbe_emit_operand(file, arg_op, globals, strings); - if arg_i + 1u < inst^.operands[2].length then - qbe_write_str(file, ", \0".ptr) - end; - arg_i := arg_i + 1u - end; - qbe_write_str(file, ")\n\0".ptr) - | ElnaTacOperator.jump: - qbe_write_str(file, "\tjmp @\0".ptr); - qbe_write_slice(file, inst^.operands[1].name); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator.jump_if_zero: - qbe_unique_id := qbe_unique_id + 1u; - tid := qbe_unique_id; - qbe_write_str(file, "\tjnz \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", @qbe_ft_\0".ptr); - qbe_write_word(file, tid); - qbe_write_str(file, ", @\0".ptr); - qbe_write_slice(file, inst^.operands[2].name); - qbe_write_str(file, "\n@qbe_ft_\0".ptr); - qbe_write_word(file, tid); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator.jump_if_not_zero: - qbe_unique_id := qbe_unique_id + 1u; - tid := qbe_unique_id; - qbe_write_str(file, "\tjnz \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, ", @\0".ptr); - qbe_write_slice(file, inst^.operands[2].name); - qbe_write_str(file, ", @qbe_ft_\0".ptr); - qbe_write_word(file, tid); - qbe_write_str(file, "\n@qbe_ft_\0".ptr); - qbe_write_word(file, tid); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator.label: - qbe_write_str(file, "@\0".ptr); - qbe_write_slice(file, inst^.operands[1].name); - qbe_write_str(file, "\n\0".ptr) - | ElnaTacOperator._return: - if inst^.operands[1].kind = ElnaTacKind.ignore then - qbe_write_str(file, "\tret\n\0".ptr) - else - qbe_write_str(file, "\tret \0".ptr); - qbe_emit_operand(file, @inst^.operands[1], globals, strings); - qbe_write_str(file, "\n\0".ptr) - end - else - end; - node := node^.next - end; - - (* Function terminator if not terminated *) - if last_operator <> ElnaTacOperator._return & last_operator <> ElnaTacOperator.jump then - if proc_node^.name = "main" then - qbe_write_str(file, "\tret 0\n\0".ptr) - elsif ret_type = nil then - qbe_write_str(file, "\tret\n\0".ptr) - else - qbe_write_str(file, "\tret 0\n\0".ptr) - end - end; - - qbe_write_str(file, "}\n\n\0".ptr) -return - -proc elna_qbe_emit*(instruction_module: ^ElnaInstructionModule; out_file: ^FILE) -var - current_string: ^ElnaTacStringConstant - current_global: ^ElnaTacStaticVariable - current_proc: ^ElnaTacProcedure - i: Word - byte_val: Word -begin - (* Emit strings *) - current_string := instruction_module^.strings; - while current_string <> nil do - qbe_write_str(out_file, "data $\0".ptr); - qbe_write_slice(out_file, current_string^.name); - qbe_write_str(out_file, " = { \0".ptr); - - i := 0u; - while i < current_string^.value.length do - qbe_write_str(out_file, "b \0".ptr); - byte_val := cast((current_string^.value.ptr + i)^: Word); - qbe_write_word(out_file, byte_val); - qbe_write_str(out_file, ", \0".ptr); - i := i + 1u - end; - qbe_write_str(out_file, "b 0 }\n\0".ptr); - - current_string := current_string^.next - end; - - (* Emit global data *) - current_global := instruction_module^.data; - while current_global <> nil do - qbe_write_str(out_file, "export data $\0".ptr); - qbe_write_slice(out_file, current_global^.name); - qbe_write_str(out_file, " = { z \0".ptr); - qbe_write_word(out_file, current_global^.size); - qbe_write_str(out_file, " }\n\0".ptr); - - current_global := current_global^.next - end; - - (* Emit procedures *) - current_proc := instruction_module^.code; - while current_proc <> nil do - qbe_emit_procedure(out_file, current_proc, instruction_module^.data, instruction_module^.strings); - current_proc := current_proc^.next - end -return - -end. diff --git a/source/symbol.elna b/source/symbol.elna deleted file mode 100644 index a07a9f3..0000000 --- a/source/symbol.elna +++ /dev/null @@ -1,200 +0,0 @@ -(* 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 sys.posix.cstdlib, common, ast - -type - ElnaSymbolInfoKind* = (type_info, temporary_info, procedure_info) - ElnaSymbolInfo* = record - kind: ElnaSymbolInfoKind - end - ElnaSymbolTypeInfo* = record(ElnaSymbolInfo) - _type: ^ElnaType - end - ElnaSymbolTemporaryInfo* = record(ElnaSymbolInfo) - attr: Word; - variable_type: ^ElnaType - end - ElnaSymbolProcedureInfo* = record(ElnaSymbolInfo) - symbol_table: ^ElnaSymbolTable; - procedure_type: ^ElnaTypeProcedure; - is_extern: Bool - end - - ElnaSymbolEntry* = record - name: []const Word8; - symbol_info: ^ElnaSymbolInfo - end - ElnaSymbolTable* = record - count: Word; - capacity: Word; - parent: ^ElnaSymbolTable; - symbols: ^ElnaSymbolEntry - end - -var - symbol_table_global*: ^ElnaSymbolTable - word_type*: ^ElnaType - int_type*: ^ElnaType - pointer_type*: ^ElnaType - bool_type*: ^ElnaType - char_type*: ^ElnaType - string_type*: ^ElnaTypeRecord - -proc elna_symbol_type_info_create*(type_representation: ^ElnaType) -> ^ElnaSymbolTypeInfo -var - result: ^ElnaSymbolTypeInfo -begin - result := malloc#[ElnaSymbolTypeInfo](#size(ElnaSymbolTypeInfo)); - result^.kind := ElnaSymbolInfoKind.type_info; - result^._type := type_representation -return result - -proc elna_symbol_temporary_info_create*(attr: Word; temporary_type: ^ElnaType) -> ^ElnaSymbolTemporaryInfo -var - result: ^ElnaSymbolTemporaryInfo -begin - result := malloc#[ElnaSymbolTemporaryInfo](#size(ElnaSymbolTemporaryInfo)); - result^.kind := ElnaSymbolInfoKind.temporary_info; - result^.variable_type := temporary_type; - result^.attr := attr -return result - -proc elna_symbol_procedure_info_create*(is_extern: Bool) -> ^ElnaSymbolProcedureInfo -var - result: ^ElnaSymbolProcedureInfo -begin - result := malloc#[ElnaSymbolProcedureInfo](#size(ElnaSymbolProcedureInfo)); - result^.kind := ElnaSymbolInfoKind.procedure_info; - result^.procedure_type := nil; - result^.symbol_table := nil; - result^.is_extern := is_extern -return result - -proc elna_symbol_table_create*(parent: ^ElnaSymbolTable) -> ^ElnaSymbolTable -var - new_symbol_table: ^ElnaSymbolTable -begin - new_symbol_table := malloc#[ElnaSymbolTable](#size(ElnaSymbolTable)); - new_symbol_table^.capacity := 64u; - new_symbol_table^.symbols := malloc#[ElnaSymbolEntry](new_symbol_table^.capacity * #size(ElnaSymbolEntry)); - new_symbol_table^.count := 0u; - new_symbol_table^.parent := parent -return new_symbol_table - -proc elna_symbol_table_enter*(symbol_table: ^ElnaSymbolTable; symbol_name: []const Word8; symbol: ^ElnaSymbolInfo) -var - entry: ^ElnaSymbolEntry -begin - if symbol_table^.count >= symbol_table^.capacity then - symbol_table^.capacity := symbol_table^.capacity * 2u; - symbol_table^.symbols := realloc#[ElnaSymbolEntry](symbol_table^.symbols, symbol_table^.capacity * #size(ElnaSymbolEntry)) - end; - entry := symbol_table^.symbols + symbol_table^.count; - entry^.name := symbol_name; - entry^.symbol_info := symbol; - symbol_table^.count := symbol_table^.count + 1u -return - -proc elna_symbol_table_lookup_local*(symbol_table: ^ElnaSymbolTable; symbol_name: []const Word8) -> ^ElnaSymbolInfo -var - i: Word := 0u - entry: ^ElnaSymbolEntry - result: ^ElnaSymbolInfo := nil -begin - while i < symbol_table^.count & result = nil do - entry := symbol_table^.symbols + i; - if entry^.name = symbol_name then - result := entry^.symbol_info - end; - i := i + 1u - end -return result - -proc elna_symbol_table_lookup*(symbol_table: ^ElnaSymbolTable; symbol_name: []const Word8) -> ^ElnaSymbolInfo -var - current: ^ElnaSymbolTable - found: ^ElnaSymbolInfo := nil -begin - current := symbol_table; - while current <> nil & found = nil do - found := elna_symbol_table_lookup_local(current, symbol_name); - current := current^.parent - end -return found - -proc elna_symbol_string_build() -var - current_field: ^ElnaTypeField - char_pointer: ^ElnaTypePointer -begin - string_type := malloc#[ElnaTypeRecord](#size(ElnaTypeRecord)); - string_type^.kind := ElnaTypeKind._record; - string_type^.size := 16u; - string_type^.alignment := 8u; - string_type^.members := malloc#[ElnaTypeField](2u * #size(ElnaTypeField)); - string_type^.length := 2u; - - char_pointer := malloc#[ElnaTypePointer](#size(ElnaTypePointer)); - char_pointer^.kind := ElnaTypeKind.pointer; - char_pointer^.size := 8u; - char_pointer^.alignment := 8u; - char_pointer^.base := char_type; - - current_field := string_type^.members; - current_field^.name := "ptr"; - current_field^.field_type := cast(char_pointer: ^ElnaType); - - current_field := current_field + 1u; - current_field^.name := "length"; - current_field^.field_type := word_type -return - -proc elna_symbol_table_build*() -var - current_info: ^ElnaSymbolTypeInfo -begin - symbol_table_global := elna_symbol_table_create(nil); - - word_type := malloc#[ElnaType](#size(ElnaType)); - word_type^.kind := ElnaTypeKind.primitive; - word_type^.size := 8u; - word_type^.alignment := 8u; - current_info := elna_symbol_type_info_create(word_type); - elna_symbol_table_enter(symbol_table_global, "Word", cast(current_info: ^ElnaSymbolInfo)); - - int_type := malloc#[ElnaType](#size(ElnaType)); - int_type^.kind := ElnaTypeKind.primitive; - int_type^.size := 8u; - int_type^.alignment := 8u; - current_info := elna_symbol_type_info_create(int_type); - elna_symbol_table_enter(symbol_table_global, "Int", cast(current_info: ^ElnaSymbolInfo)); - - pointer_type := malloc#[ElnaType](#size(ElnaType)); - pointer_type^.kind := ElnaTypeKind.primitive; - pointer_type^.size := 8u; - pointer_type^.alignment := 8u; - current_info := elna_symbol_type_info_create(pointer_type); - elna_symbol_table_enter(symbol_table_global, "Pointer", cast(current_info: ^ElnaSymbolInfo)); - - bool_type := malloc#[ElnaType](#size(ElnaType)); - bool_type^.kind := ElnaTypeKind.primitive; - bool_type^.size := 1u; - bool_type^.alignment := 1u; - current_info := elna_symbol_type_info_create(bool_type); - elna_symbol_table_enter(symbol_table_global, "Bool", cast(current_info: ^ElnaSymbolInfo)); - - char_type := malloc#[ElnaType](#size(ElnaType)); - char_type^.kind := ElnaTypeKind.primitive; - char_type^.size := 1u; - char_type^.alignment := 1u; - current_info := elna_symbol_type_info_create(char_type); - elna_symbol_table_enter(symbol_table_global, "Char", cast(current_info: ^ElnaSymbolInfo)); - - elna_symbol_string_build(); - current_info := elna_symbol_type_info_create(cast(string_type: ^ElnaType)); - elna_symbol_table_enter(symbol_table_global, "String", cast(current_info: ^ElnaSymbolInfo)) -return - -end. diff --git a/source/sys/posix/cctype.elna b/source/sys/posix/cctype.elna deleted file mode 100644 index 19c3491..0000000 --- a/source/sys/posix/cctype.elna +++ /dev/null @@ -1,24 +0,0 @@ -(* 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 tolower*(c: Int) -> Int -extern - -proc toupper*(c: Int) -> Int -extern - -end. diff --git a/source/sys/posix/cstdio.elna b/source/sys/posix/cstdio.elna deleted file mode 100644 index 928c7e1..0000000 --- a/source/sys/posix/cstdio.elna +++ /dev/null @@ -1,59 +0,0 @@ -(* 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* = extern - -var - stdin*: ^FILE := extern - stdout*: ^FILE := extern - stderr*: ^FILE := extern - -proc fopen*(pathname, mode: ^const Word8) -> ^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 fread*#[T](ptr: ^T; size: Word; nmemb: Word; stream: ^FILE) -> Word -extern - -proc fwrite*#[T](ptr: ^const T; size: Word; nitems: Word; stream: ^FILE) -> Word -extern - -proc fputc*(c: Int; stream: ^FILE) -> Word -extern - -proc perror*(s: ^const Word8) -extern - -proc puts*(s: ^const Word8) -> Int -extern - -proc putchar*(c: Int) -> Int -extern - -proc sprintf*(str: ^Word8; format: ^const Word8) #{varargs} -> Int -extern - -proc fprintf*(stream: ^FILE; format: ^const Word8) #{varargs} -> Int -extern - -proc fdopen*(fildes: Int; mode: ^const Word8) -> ^FILE -extern - -end. diff --git a/source/sys/posix/cstdlib.elna b/source/sys/posix/cstdlib.elna deleted file mode 100644 index 10a4d80..0000000 --- a/source/sys/posix/cstdlib.elna +++ /dev/null @@ -1,24 +0,0 @@ -(* 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*#[T](size: Word) -> ^T -extern - -proc free*#[T](ptr: ^T) -extern - -proc calloc*#[T](nmemb: Word; size: Word) -> ^T -extern - -proc realloc*#[T](ptr: ^T; size: Word) -> ^T -extern - -proc atoi*(str: ^Word8) -> Int -extern - -proc exit*(code: Int) #{noreturn} -extern - -end. diff --git a/source/sys/posix/cstring.elna b/source/sys/posix/cstring.elna deleted file mode 100644 index 3973573..0000000 --- a/source/sys/posix/cstring.elna +++ /dev/null @@ -1,30 +0,0 @@ -(* 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*#[T](ptr: ^T; c: Int; n: Word) -> ^Word8 -extern - -proc memcpy*#[T](dst: ^T; src: ^const T; n: Word) -extern - -proc memcmp*#[T](s1, s2: ^const T; n: Word) -> Int -extern - -proc strcmp*(s1: ^const Word8; s2: ^const Word8) -> Int -extern - -proc strncmp*(s1: ^const Word8; s2: ^const Word8; n: Word) -> Int -extern - -proc strncpy*(dst: ^Word8; src: ^const Word8; dsize: Word) -> ^Word8 -extern - -proc strcpy*(dst: ^Word8; src: ^const Word8) -> ^Word8 -extern - -proc strlen*(ptr: ^const Word8) -> Word -extern - -end. diff --git a/source/tac.elna b/source/tac.elna deleted file mode 100644 index 3d65e42..0000000 --- a/source/tac.elna +++ /dev/null @@ -1,1074 +0,0 @@ -(* 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 common, sys.posix.cstdlib, sys.posix.cstdio, sys.posix.cstring, lexer, ast, symbol, diagnostic - -type - ElnaTacOperator* = ( - get_address, - add, - load, - store, - proc_call, - copy, - copy_to_offset, - copy_from_offset, - subtract, - divide, - remainder, - multiply, - _xor, - _or, - and, - less_than, - greater_than, - less_or_equal, - greater_or_equal, - equal, - not_equal, - negate, - complement, - jump, - jump_if_zero, - jump_if_not_zero, - label, - _return, - add_ptr, - nop - ) - - ElnaTacKind* = (list, label, constant, variable, ignore) - - ElnaTacOperand* = record - kind: ElnaTacKind; - name: []const Word8; - constant: Word; - length: Word; - list_operands: ^ElnaTacOperand - end - - ElnaTacInstruction* = record(ElnaListNode) - operator: ElnaTacOperator; - operands: [4]ElnaTacOperand - end - - ElnaTacProcedure* = record - next: ^ElnaTacProcedure; - name: []const Word8; - body: ElnaList; - parameters: ^[]const Word8; - count: Word; - symbol_table: ^ElnaSymbolTable - end - - ElnaTacStaticVariable* = record - next: ^ElnaTacStaticVariable; - name: []const Word8; - size: Word - end - - ElnaTacStringConstant* = record - next: ^ElnaTacStringConstant; - name: []const Word8; - value: []const Word8 - end - - ElnaInstructionModule* = record - strings: ^ElnaTacStringConstant; - data: ^ElnaTacStaticVariable; - code: ^ElnaTacProcedure - end - - ElnaTacOperandType = (plain_object, dereferenced_pointer, sub_object) - - ElnaTacOperandResult = record - kind: ElnaTacOperandType; - offset: Word - end - -var - pseudo_counter: Word := 0u - label_counter: Word := 0u - string_counter: Word := 0u - module_strings_first: ^ElnaTacStringConstant := nil - module_strings_last: ^ElnaTacStringConstant := nil - -proc elna_tac_instruction_create*(operator: ElnaTacOperator) -> ^ElnaTacInstruction -var - result: ^ElnaTacInstruction -begin - result := malloc#[ElnaTacInstruction](#size(ElnaTacInstruction)); - result^.next := nil; - result^.operator := operator; - result^.operands[1].kind := ElnaTacKind.ignore; - result^.operands[2].kind := ElnaTacKind.ignore; - result^.operands[3].kind := ElnaTacKind.ignore; - result^.operands[4].kind := ElnaTacKind.ignore -return result - -proc elna_tac_instruction_set_operand*(this: ^ElnaTacInstruction; n: Word; - kind: ElnaTacKind; name: []const Word8; constant: Word; length: Word) -begin - this^.operands[n].kind := kind; - this^.operands[n].name := name; - this^.operands[n].constant := constant; - this^.operands[n].length := length; - this^.operands[n].list_operands := nil -return - -proc elna_tac_instruction_set_op*(this: ^ElnaTacInstruction; n: Word; op: ^ElnaTacOperand) -begin - this^.operands[n] := op^ -return - -proc elna_tac_instruction_set_const*(this: ^ElnaTacInstruction; n: Word; value: Word; length: Word) -begin - this^.operands[n].kind := ElnaTacKind.constant; - this^.operands[n].name := ""; - this^.operands[n].constant := value; - this^.operands[n].length := length; - this^.operands[n].list_operands := nil -return - -proc elna_tac_instruction_set_label*(this: ^ElnaTacInstruction; n: Word; label_name: []const Word8) -begin - this^.operands[n].kind := ElnaTacKind.label; - this^.operands[n].name := label_name; - this^.operands[n].constant := 0u; - this^.operands[n].length := label_name.length; - this^.operands[n].list_operands := nil -return - -proc elna_tac_make_variable*(operand: ^ElnaTacOperand; symbol_table: ^ElnaSymbolTable; variable_type: ^ElnaType) -var - buffer: ^Word8 - name_slice: []const Word8 - temporary_info: ^ElnaSymbolTemporaryInfo - len: Int -begin - pseudo_counter := pseudo_counter + 1u; - buffer := malloc#[Word8](16u); - len := sprintf(buffer, "t%u\0".ptr, pseudo_counter); - - name_slice := buffer[1u to cast(len: Word)]; - - operand^.kind := ElnaTacKind.variable; - operand^.name := name_slice; - operand^.constant := 0u; - operand^.length := name_slice.length; - operand^.list_operands := nil; - - temporary_info := elna_symbol_temporary_info_create(1u, variable_type); - elna_symbol_table_enter(symbol_table, name_slice, cast(temporary_info: ^ElnaSymbolInfo)) -return - -proc elna_tac_label*() -> []const Word8 -var - buffer: ^Word8 - result: []const Word8 - len: Int -begin - label_counter := label_counter + 1u; - buffer := malloc#[Word8](16u); - len := sprintf(buffer, "l%u\0".ptr, label_counter); - result := buffer[1u to cast(len: Word)] -return result - -proc elna_tac_integer_literal(integer_literal_node: ^ElnaTreeIntegerLiteral; operand: ^ElnaTacOperand) -begin - operand^.kind := ElnaTacKind.constant; - operand^.name := ""; - operand^.constant := integer_literal_node^.value; - operand^.length := word_type^.size; - operand^.list_operands := nil -return - -proc elna_tac_boolean_literal(boolean_literal_node: ^ElnaTreeBooleanLiteral; operand: ^ElnaTacOperand) -begin - operand^.kind := ElnaTacKind.constant; - operand^.name := ""; - if boolean_literal_node^.value then - operand^.constant := 1u - else - operand^.constant := 0u - end; - operand^.length := bool_type^.size; - operand^.list_operands := nil -return - -proc elna_tac_nil_literal(operand: ^ElnaTacOperand) -begin - operand^.kind := ElnaTacKind.constant; - operand^.name := ""; - operand^.constant := 0u; - operand^.length := 8u; - operand^.list_operands := nil -return - -proc elna_tac_character_literal(character_literal_node: ^ElnaTreeCharacterLiteral; operand: ^ElnaTacOperand) -begin - operand^.kind := ElnaTacKind.constant; - operand^.name := ""; - operand^.constant := cast(character_literal_node^.value: Word); - operand^.length := char_type^.size; - operand^.list_operands := nil -return - -proc elna_tac_variable_expression(variable_expression: ^ElnaTreeVariableExpression; operand: ^ElnaTacOperand) -begin - operand^.kind := ElnaTacKind.variable; - operand^.name := variable_expression^.name; - operand^.constant := 0u; - operand^.length := variable_expression^.name.length; - operand^.list_operands := nil -return - -proc elna_tac_trait_expression(trait_node: ^ElnaTreeTraitExpression; operand: ^ElnaTacOperand) -var - symbol_info: ^ElnaSymbolInfo - type_info: ^ElnaSymbolTypeInfo - parser_node: ^ElnaTreeNamedTypeExpression -begin - parser_node := cast(trait_node^.argument: ^ElnaTreeNamedTypeExpression); - symbol_info := elna_symbol_table_lookup(symbol_table_global, parser_node^.name); - - operand^.kind := ElnaTacKind.constant; - operand^.name := ""; - operand^.length := 8u; - operand^.list_operands := nil; - if symbol_info <> nil & symbol_info^.kind = ElnaSymbolInfoKind.type_info then - type_info := cast(symbol_info: ^ElnaSymbolTypeInfo); - operand^.constant := type_info^._type^.size - else - operand^.constant := 0u - end -return - -proc elna_tac_string_literal(instructions: ^ElnaList; string_literal_node: ^ElnaTreeStringLiteral; - symbol_table: ^ElnaSymbolTable; operand: ^ElnaTacOperand) -var - string_entry: ^ElnaTacStringConstant - label_buf: ^Word8 - label_slice: []const Word8 - label_len: Int - instruction: ^ElnaTacInstruction - address: ElnaTacOperand -begin - string_counter := string_counter + 1u; - label_buf := malloc#[Word8](16u); - label_len := sprintf(label_buf, "str_%u\0".ptr, string_counter); - label_slice := label_buf[1u to cast(label_len: Word)]; - - string_entry := malloc#[ElnaTacStringConstant](#size(ElnaTacStringConstant)); - string_entry^.next := nil; - string_entry^.name := label_slice; - string_entry^.value := string_literal_node^.value; - - if module_strings_first = nil then - module_strings_first := string_entry - else - module_strings_last^.next := string_entry - end; - module_strings_last := string_entry; - - elna_tac_make_variable(operand, symbol_table, cast(string_type: ^ElnaType)); - elna_tac_make_variable(@address, symbol_table, pointer_type); - - instruction := elna_tac_instruction_create(ElnaTacOperator.get_address); - elna_tac_instruction_set_operand(instruction, 1u, ElnaTacKind.variable, label_slice, 0u, label_slice.length); - elna_tac_instruction_set_op(instruction, 2u, @address); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)); - - instruction := elna_tac_instruction_create(ElnaTacOperator.copy_to_offset); - elna_tac_instruction_set_op(instruction, 1u, @address); - elna_tac_instruction_set_op(instruction, 2u, operand); - elna_tac_instruction_set_const(instruction, 3u, 0u, 8u); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)); - - instruction := elna_tac_instruction_create(ElnaTacOperator.copy_to_offset); - elna_tac_instruction_set_const(instruction, 1u, string_literal_node^.value.length, 8u); - elna_tac_instruction_set_op(instruction, 2u, operand); - elna_tac_instruction_set_const(instruction, 3u, 8u, 8u); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)) -return - -proc elna_tac_copy_address(instructions: ^ElnaList; operand_result: ^ElnaTacOperandResult; from, dest: ^ElnaTacOperand) -var - instruction: ^ElnaTacInstruction -begin - if operand_result^.kind = ElnaTacOperandType.dereferenced_pointer then - dest^ := from^ - elsif operand_result^.kind = ElnaTacOperandType.sub_object then - instruction := elna_tac_instruction_create(ElnaTacOperator.get_address); - elna_tac_instruction_set_op(instruction, 1u, from); - elna_tac_instruction_set_op(instruction, 2u, dest); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)); - - instruction := elna_tac_instruction_create(ElnaTacOperator.add); - elna_tac_instruction_set_const(instruction, 1u, operand_result^.offset, 4u); - elna_tac_instruction_set_op(instruction, 2u, dest); - elna_tac_instruction_set_op(instruction, 3u, dest); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)) - else - instruction := elna_tac_instruction_create(ElnaTacOperator.get_address); - elna_tac_instruction_set_op(instruction, 1u, from); - elna_tac_instruction_set_op(instruction, 2u, dest); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)) - end -return - -proc elna_tac_simple_expression(instructions: ^ElnaList; parser_node: ^ElnaTreeExpression; - symbol_table: ^ElnaSymbolTable; operand: ^ElnaTacOperand) -begin - case parser_node^.kind of - ElnaTreeKind.integer_literal: - elna_tac_integer_literal(cast(parser_node: ^ElnaTreeIntegerLiteral), operand) - | ElnaTreeKind.character_literal: - elna_tac_character_literal(cast(parser_node: ^ElnaTreeCharacterLiteral), operand) - | ElnaTreeKind.string_literal: - elna_tac_string_literal(instructions, cast(parser_node: ^ElnaTreeStringLiteral), symbol_table, operand) - | ElnaTreeKind.boolean_literal: - elna_tac_boolean_literal(cast(parser_node: ^ElnaTreeBooleanLiteral), operand) - | ElnaTreeKind.null: - elna_tac_nil_literal(operand) - | ElnaTreeKind.variable_expression: - elna_tac_variable_expression(cast(parser_node: ^ElnaTreeVariableExpression), operand) - | ElnaTreeKind.trait_expression: - elna_tac_trait_expression(cast(parser_node: ^ElnaTreeTraitExpression), operand) - | ElnaTreeKind._cast: - elna_tac_binary_expression(instructions, (cast(parser_node: ^ElnaTreeCastExpression))^.expression, symbol_table, operand) - else - end -return - -proc elna_tac_unary_expression(instructions: ^ElnaList; parser_node: ^ElnaTreeExpression; - symbol_table: ^ElnaSymbolTable; operand: ^ElnaTacOperand) -var - operator: ElnaLexerKind - unary_operand: ^ElnaTreeExpression - unary_node: ^ElnaTreeUnaryExpression - operand_result: ElnaTacOperandResult - instruction: ^ElnaTacInstruction - base: ElnaTacOperand - has_unary: Bool := false -begin - if parser_node^.kind = ElnaTreeKind.unary_expression then - unary_node := cast(parser_node: ^ElnaTreeUnaryExpression); - operator := unary_node^.operator; - unary_operand := unary_node^.operand; - has_unary := true - else - unary_operand := parser_node - end; - elna_tac_designator(instructions, unary_operand, symbol_table, @operand_result, @base); - - if has_unary & operator = ElnaLexerKind.at then - elna_tac_make_variable(operand, symbol_table, word_type); - elna_tac_copy_address(instructions, @operand_result, @base, operand) - elsif has_unary & operator = ElnaLexerKind.minus then - elna_tac_make_variable(operand, symbol_table, parser_node^.type_decoration); - instruction := elna_tac_instruction_create(ElnaTacOperator.negate); - elna_tac_instruction_set_op(instruction, 1u, @base); - elna_tac_instruction_set_op(instruction, 2u, operand); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)) - elsif has_unary & operator = ElnaLexerKind.not then - elna_tac_make_variable(operand, symbol_table, parser_node^.type_decoration); - instruction := elna_tac_instruction_create(ElnaTacOperator.complement); - elna_tac_instruction_set_op(instruction, 1u, @base); - elna_tac_instruction_set_op(instruction, 2u, operand); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)) - elsif operand_result.kind = ElnaTacOperandType.dereferenced_pointer then - elna_tac_make_variable(operand, symbol_table, parser_node^.type_decoration); - instruction := elna_tac_instruction_create(ElnaTacOperator.load); - elna_tac_instruction_set_op(instruction, 1u, @base); - elna_tac_instruction_set_op(instruction, 2u, operand); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)) - elsif operand_result.kind = ElnaTacOperandType.sub_object then - elna_tac_make_variable(operand, symbol_table, parser_node^.type_decoration); - instruction := elna_tac_instruction_create(ElnaTacOperator.copy_from_offset); - elna_tac_instruction_set_op(instruction, 1u, @base); - elna_tac_instruction_set_const(instruction, 2u, operand_result.offset, 4u); - elna_tac_instruction_set_op(instruction, 3u, operand); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)) - else - operand^ := base - end -return - -proc elna_tac_add_pointer(parser_node: ^ElnaTreeExpression; lhs, rhs: ^ElnaTacOperand; - symbol_table: ^ElnaSymbolTable; operand: ^ElnaTacOperand) -> ^ElnaTacInstruction -var - instruction: ^ElnaTacInstruction - pointer_type_node: ^ElnaTypePointer - elem_size: Word := 1u -begin - if parser_node^.type_decoration <> nil & parser_node^.type_decoration^.kind = ElnaTypeKind.pointer then - pointer_type_node := cast(parser_node^.type_decoration: ^ElnaTypePointer); - if pointer_type_node^.base <> nil then - elem_size := pointer_type_node^.base^.size - end - end; - instruction := elna_tac_instruction_create(ElnaTacOperator.add_ptr); - elna_tac_make_variable(operand, symbol_table, word_type); - elna_tac_instruction_set_op(instruction, 1u, lhs); - elna_tac_instruction_set_op(instruction, 2u, rhs); - elna_tac_instruction_set_const(instruction, 3u, elem_size, 4u); - elna_tac_instruction_set_op(instruction, 4u, operand) -return instruction - -proc elna_tac_binary_create(instructions: ^ElnaList; operator: ElnaTacOperator; - lhs, rhs: ^ElnaTacOperand; symbol_table: ^ElnaSymbolTable; operand: ^ElnaTacOperand) -var - instruction: ^ElnaTacInstruction - lhs_symbol: ^ElnaSymbolInfo - temp_info: ^ElnaSymbolTemporaryInfo - variable_type: ^ElnaType := word_type -begin - if lhs^.kind = ElnaTacKind.variable then - lhs_symbol := elna_symbol_table_lookup(symbol_table, lhs^.name); - if lhs_symbol <> nil & lhs_symbol^.kind = ElnaSymbolInfoKind.temporary_info then - temp_info := cast(lhs_symbol: ^ElnaSymbolTemporaryInfo); - variable_type := temp_info^.variable_type - end - end; - elna_tac_make_variable(operand, symbol_table, variable_type); - - instruction := elna_tac_instruction_create(operator); - elna_tac_instruction_set_op(instruction, 1u, lhs); - elna_tac_instruction_set_op(instruction, 2u, rhs); - elna_tac_instruction_set_op(instruction, 3u, operand); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)) -return - -proc elna_tac_subtract_create(instructions: ^ElnaList; parser_node: ^ElnaTreeBinaryExpression; - lhs, rhs: ^ElnaTacOperand; symbol_table: ^ElnaSymbolTable; operand: ^ElnaTacOperand) -var - instruction: ^ElnaTacInstruction - lhs_is_pointer: Bool := false - rhs_is_not_pointer: Bool := true -begin - if parser_node^.lhs^.type_decoration <> nil & parser_node^.lhs^.type_decoration^.kind = ElnaTypeKind.pointer then - lhs_is_pointer := true - end; - if parser_node^.rhs^.type_decoration <> nil & parser_node^.rhs^.type_decoration^.kind = ElnaTypeKind.pointer then - rhs_is_not_pointer := false - end; - - if lhs_is_pointer & rhs_is_not_pointer then - instruction := elna_tac_instruction_create(ElnaTacOperator.negate); - elna_tac_instruction_set_op(instruction, 1u, rhs); - elna_tac_instruction_set_op(instruction, 2u, operand); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)); - - instruction := elna_tac_add_pointer(parser_node^.lhs, lhs, operand, symbol_table, operand); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)) - else - elna_tac_binary_create(instructions, ElnaTacOperator.subtract, lhs, rhs, symbol_table, operand) - end -return - -proc elna_tac_binary_expression(instructions: ^ElnaList; parser_node: ^ElnaTreeExpression; - symbol_table: ^ElnaSymbolTable; operand: ^ElnaTacOperand) -var - binary_node: ^ElnaTreeBinaryExpression - instruction: ^ElnaTacInstruction - lhs: ElnaTacOperand - rhs: ElnaTacOperand -begin - if parser_node^.kind <> ElnaTreeKind.binary_expression then - elna_tac_unary_expression(instructions, parser_node, symbol_table, operand) - else - binary_node := cast(parser_node: ^ElnaTreeBinaryExpression); - elna_tac_unary_expression(instructions, binary_node^.lhs, symbol_table, @lhs); - elna_tac_unary_expression(instructions, binary_node^.rhs, symbol_table, @rhs); - - case binary_node^.operator of - ElnaLexerKind.plus: - if binary_node^.lhs^.type_decoration <> nil & binary_node^.lhs^.type_decoration^.kind = ElnaTypeKind.pointer then - instruction := elna_tac_add_pointer(binary_node^.lhs, @lhs, @rhs, symbol_table, operand); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)) - elsif binary_node^.rhs^.type_decoration <> nil & binary_node^.rhs^.type_decoration^.kind = ElnaTypeKind.pointer then - instruction := elna_tac_add_pointer(binary_node^.rhs, @rhs, @lhs, symbol_table, operand); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)) - else - elna_tac_binary_create(instructions, ElnaTacOperator.add, @lhs, @rhs, symbol_table, operand) - end - | ElnaLexerKind.minus: - elna_tac_subtract_create(instructions, binary_node, @lhs, @rhs, symbol_table, operand) - | ElnaLexerKind.multiplication: - elna_tac_binary_create(instructions, ElnaTacOperator.multiply, @lhs, @rhs, symbol_table, operand) - | ElnaLexerKind.division: - elna_tac_binary_create(instructions, ElnaTacOperator.divide, @lhs, @rhs, symbol_table, operand) - | ElnaLexerKind.remainder: - elna_tac_binary_create(instructions, ElnaTacOperator.remainder, @lhs, @rhs, symbol_table, operand) - | ElnaLexerKind.and: - elna_tac_binary_create(instructions, ElnaTacOperator.and, @lhs, @rhs, symbol_table, operand) - | ElnaLexerKind._or: - elna_tac_binary_create(instructions, ElnaTacOperator._or, @lhs, @rhs, symbol_table, operand) - | ElnaLexerKind._xor: - elna_tac_binary_create(instructions, ElnaTacOperator._xor, @lhs, @rhs, symbol_table, operand) - | ElnaLexerKind.equals: - elna_tac_binary_create(instructions, ElnaTacOperator.equal, @lhs, @rhs, symbol_table, operand) - | ElnaLexerKind.not_equal: - elna_tac_binary_create(instructions, ElnaTacOperator.not_equal, @lhs, @rhs, symbol_table, operand) - | ElnaLexerKind.less_than: - elna_tac_binary_create(instructions, ElnaTacOperator.less_than, @lhs, @rhs, symbol_table, operand) - | ElnaLexerKind.greater_than: - elna_tac_binary_create(instructions, ElnaTacOperator.greater_than, @lhs, @rhs, symbol_table, operand) - | ElnaLexerKind.less_equal: - elna_tac_binary_create(instructions, ElnaTacOperator.less_or_equal, @lhs, @rhs, symbol_table, operand) - | ElnaLexerKind.greater_equal: - elna_tac_binary_create(instructions, ElnaTacOperator.greater_or_equal, @lhs, @rhs, symbol_table, operand) - else - end - end -return - -proc elna_tac_call(instructions: ^ElnaList; parsed_call: ^ElnaTreeCall; symbol_table: ^ElnaSymbolTable; - operand: ^ElnaTacOperand) -var - parsed_expression: ^ElnaTreeVariableExpression - arguments_operand: ^ElnaTacOperand - call_instruction: ^ElnaTacInstruction - argument_entry: ^ElnaTreeExpressionList - symbol_info: ^ElnaSymbolInfo - procedure_info: ^ElnaSymbolProcedureInfo - i: Word := 0u -begin - parsed_expression := parsed_call^.callee; - arguments_operand := malloc#[ElnaTacOperand](parsed_call^.count * #size(ElnaTacOperand)); - symbol_info := elna_symbol_table_lookup(symbol_table, parsed_expression^.name); - - call_instruction := elna_tac_instruction_create(ElnaTacOperator.proc_call); - elna_tac_instruction_set_label(call_instruction, 1u, parsed_expression^.name); - - call_instruction^.operands[2].kind := ElnaTacKind.list; - call_instruction^.operands[2].list_operands := arguments_operand; - call_instruction^.operands[2].length := parsed_call^.count; - - if symbol_info <> nil & symbol_info^.kind = ElnaSymbolInfoKind.procedure_info then - procedure_info := cast(symbol_info: ^ElnaSymbolProcedureInfo); - if procedure_info^.procedure_type^.return_type = nil then - call_instruction^.operands[3].kind := ElnaTacKind.ignore - else - elna_tac_make_variable(operand, symbol_table, procedure_info^.procedure_type^.return_type); - elna_tac_instruction_set_op(call_instruction, 3u, operand) - end - else - call_instruction^.operands[3].kind := ElnaTacKind.ignore - end; - - argument_entry := parsed_call^.arguments; - while argument_entry <> nil & i < parsed_call^.count do - elna_tac_binary_expression(instructions, argument_entry^.expression, symbol_table, arguments_operand + i); - argument_entry := argument_entry^.next; - i := i + 1u - end; - elna_list_append(instructions, cast(call_instruction: ^ElnaListNode)) -return - -proc elna_tac_goto_statement(instructions: ^ElnaList; parser_node: ^ElnaTreeGotoStatement) -var - instruction: ^ElnaTacInstruction -begin - instruction := elna_tac_instruction_create(ElnaTacOperator.jump); - elna_tac_instruction_set_label(instruction, 1u, parser_node^.label); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)) -return - -proc elna_tac_label_declaration(instructions: ^ElnaList; parser_node: ^ElnaTreeLabelDeclaration) -var - result: ^ElnaTacInstruction -begin - result := elna_tac_instruction_create(ElnaTacOperator.label); - elna_tac_instruction_set_label(result, 1u, parser_node^.label); - elna_list_append(instructions, cast(result: ^ElnaListNode)) -return - -proc elna_tac_enumeration_value(field_access_expression: ^ElnaTreeFieldAccessExpression; operand: ^ElnaTacOperand) -var - enumeration_type: ^ElnaTypeEnumeration - members: ^[]const Word8 - members_length: Word - symbol_info: ^ElnaSymbolInfo - type_info: ^ElnaSymbolTypeInfo - counter: Word := 1u - found: Bool := false - aggregate_tree: ^ElnaTreeVariableExpression -begin - aggregate_tree := cast(field_access_expression^.aggregate: ^ElnaTreeVariableExpression); - symbol_info := elna_symbol_table_lookup(symbol_table_global, aggregate_tree^.name); - - if symbol_info <> nil & symbol_info^.kind = ElnaSymbolInfoKind.type_info then - type_info := cast(symbol_info: ^ElnaSymbolTypeInfo); - if type_info^._type^.kind = ElnaTypeKind.enumeration then - enumeration_type := cast(type_info^._type: ^ElnaTypeEnumeration); - members := enumeration_type^.members; - members_length := enumeration_type^.length; - - while members_length > 0u & ~found do - if members^ = field_access_expression^.field then - found := true; - operand^.kind := ElnaTacKind.constant; - operand^.constant := counter; - operand^.length := 4u; - operand^.name := ""; - operand^.list_operands := nil - else - members_length := members_length - 1u; - members := members + 1u; - counter := counter + 1u - end - end - end - end -return - -proc elna_tac_dereference_expression(instructions: ^ElnaList; dereference_expression: ^ElnaTreeDereferenceExpression; - symbol_table: ^ElnaSymbolTable; operand: ^ElnaTacOperand) -var - load_instruction: ^ElnaTacInstruction - operand_result: ElnaTacOperandResult - intermediate: ElnaTacOperand -begin - elna_tac_designator(instructions, dereference_expression^.pointer, symbol_table, @operand_result, operand); - - if operand_result.kind = ElnaTacOperandType.dereferenced_pointer then - intermediate := operand^; - elna_tac_make_variable(operand, symbol_table, word_type); - - load_instruction := elna_tac_instruction_create(ElnaTacOperator.load); - elna_tac_instruction_set_op(load_instruction, 1u, @intermediate); - elna_tac_instruction_set_op(load_instruction, 2u, operand); - elna_list_append(instructions, cast(load_instruction: ^ElnaListNode)) - elsif operand_result.kind = ElnaTacOperandType.sub_object then - intermediate := operand^; - elna_tac_make_variable(operand, symbol_table, word_type); - - load_instruction := elna_tac_instruction_create(ElnaTacOperator.copy_from_offset); - elna_tac_instruction_set_op(load_instruction, 1u, @intermediate); - elna_tac_instruction_set_const(load_instruction, 2u, operand_result.offset, 4u); - elna_tac_instruction_set_op(load_instruction, 3u, operand); - elna_list_append(instructions, cast(load_instruction: ^ElnaListNode)) - end -return - -proc elna_tac_field_access_expression(instructions: ^ElnaList; field_access_expression: ^ElnaTreeFieldAccessExpression; - symbol_table: ^ElnaSymbolTable; operand_result: ^ElnaTacOperandResult; operand: ^ElnaTacOperand) -var - field_type: ^ElnaType - instruction: ^ElnaTacInstruction - designator_base: ^ElnaTreeExpression - aggregate_type: ^ElnaTypeRecord - field_count: Word - current_field: ^ElnaTypeField - field_offset: Word := 0u - base: ElnaTacOperand - found: Bool := false -begin - designator_base := field_access_expression^.aggregate; - aggregate_type := cast(designator_base^.type_decoration: ^ElnaTypeRecord); - - elna_tac_designator(instructions, designator_base, symbol_table, operand_result, @base); - - if aggregate_type <> nil & aggregate_type^.kind = ElnaTypeKind._record then - field_count := aggregate_type^.length; - current_field := aggregate_type^.members; - - while field_count > 0u & ~found do - if current_field^.name = field_access_expression^.field then - found := true - else - field_type := current_field^.field_type; - field_count := field_count - 1u; - field_offset := field_offset + field_type^.size; - current_field := current_field + 1u - end - end - end; - - if operand_result^.kind = ElnaTacOperandType.dereferenced_pointer then - elna_tac_make_variable(operand, symbol_table, word_type); - - instruction := elna_tac_instruction_create(ElnaTacOperator.add); - elna_tac_instruction_set_op(instruction, 1u, @base); - elna_tac_instruction_set_const(instruction, 2u, field_offset, 4u); - elna_tac_instruction_set_op(instruction, 3u, operand); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)) - elsif operand_result^.kind = ElnaTacOperandType.sub_object then - operand^ := base; - operand_result^.offset := operand_result^.offset + field_offset - else - operand^ := base; - operand_result^.kind := ElnaTacOperandType.sub_object; - operand_result^.offset := field_offset - end -return - -proc elna_tac_array_access_expression(instructions: ^ElnaList; array_access_expression: ^ElnaTreeArrayAccessExpression; - symbol_table: ^ElnaSymbolTable; operand: ^ElnaTacOperand) -var - instruction: ^ElnaTacInstruction - operand_result: ElnaTacOperandResult - inter_operand: ElnaTacOperand - index_operand: ElnaTacOperand - aggregate_type: ^ElnaTypeArray - designator_base: ^ElnaTreeExpression - element_type: ^ElnaType - elem_size: Word := 1u -begin - designator_base := array_access_expression^.array; - if designator_base^.type_decoration <> nil & designator_base^.type_decoration^.kind = ElnaTypeKind.array then - aggregate_type := cast(designator_base^.type_decoration: ^ElnaTypeArray); - element_type := aggregate_type^.base; - if element_type <> nil then - elem_size := element_type^.size - end - end; - - elna_tac_binary_expression(instructions, array_access_expression^.index, symbol_table, @inter_operand); - elna_tac_make_variable(@index_operand, symbol_table, word_type); - - (* In Elna arrays are 1-based, subtract 1 for 0-based index *) - instruction := elna_tac_instruction_create(ElnaTacOperator.subtract); - elna_tac_instruction_set_op(instruction, 1u, @inter_operand); - elna_tac_instruction_set_const(instruction, 2u, 1u, 4u); - elna_tac_instruction_set_op(instruction, 3u, @index_operand); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)); - - elna_tac_designator(instructions, array_access_expression^.array, - symbol_table, @operand_result, @inter_operand); - elna_tac_make_variable(operand, symbol_table, word_type); - elna_tac_copy_address(instructions, @operand_result, @inter_operand, operand); - - instruction := elna_tac_instruction_create(ElnaTacOperator.add_ptr); - elna_tac_instruction_set_op(instruction, 1u, operand); - elna_tac_instruction_set_op(instruction, 2u, @index_operand); - elna_tac_instruction_set_const(instruction, 3u, elem_size, 4u); - elna_tac_instruction_set_op(instruction, 4u, operand); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)) -return - -proc elna_tac_designator(instructions: ^ElnaList; parser_node: ^ElnaTreeExpression; symbol_table: ^ElnaSymbolTable; - operand_result: ^ElnaTacOperandResult; operand: ^ElnaTacOperand) -var - field_access_expression: ^ElnaTreeFieldAccessExpression - designator_base: ^ElnaTreeExpression -begin - operand_result^.kind := ElnaTacOperandType.plain_object; - operand_result^.offset := 0u; - - case parser_node^.kind of - ElnaTreeKind.dereference_expression: - elna_tac_dereference_expression(instructions, cast(parser_node: ^ElnaTreeDereferenceExpression), symbol_table, operand); - operand_result^.kind := ElnaTacOperandType.dereferenced_pointer - | ElnaTreeKind.field_access_expression: - field_access_expression := cast(parser_node: ^ElnaTreeFieldAccessExpression); - designator_base := field_access_expression^.aggregate; - - if designator_base^.type_decoration = nil then - elna_tac_enumeration_value(field_access_expression, operand) - else - elna_tac_field_access_expression(instructions, field_access_expression, symbol_table, operand_result, operand) - end - | ElnaTreeKind.array_access_expression: - elna_tac_array_access_expression(instructions, cast(parser_node: ^ElnaTreeArrayAccessExpression), symbol_table, operand); - operand_result^.kind := ElnaTacOperandType.dereferenced_pointer - | ElnaTreeKind.call: - elna_tac_call(instructions, cast(parser_node: ^ElnaTreeCall), symbol_table, operand) - else - elna_tac_simple_expression(instructions, parser_node, symbol_table, operand) - end -return - -proc elna_tac_assign_statement(instructions: ^ElnaList; parser_tree: ^ElnaTreeAssignStatement; symbol_table: ^ElnaSymbolTable) -var - operand_result: ElnaTacOperandResult - instruction: ^ElnaTacInstruction - assignment_operand: ElnaTacOperand - assignee: ElnaTacOperand -begin - elna_tac_designator(instructions, parser_tree^.assignee, symbol_table, @operand_result, @assignee); - elna_tac_binary_expression(instructions, parser_tree^.assignment, symbol_table, @assignment_operand); - - if operand_result.kind = ElnaTacOperandType.dereferenced_pointer then - instruction := elna_tac_instruction_create(ElnaTacOperator.store); - elna_tac_instruction_set_op(instruction, 1u, @assignment_operand); - elna_tac_instruction_set_op(instruction, 2u, @assignee) - elsif operand_result.kind = ElnaTacOperandType.sub_object then - instruction := elna_tac_instruction_create(ElnaTacOperator.copy_to_offset); - elna_tac_instruction_set_op(instruction, 1u, @assignment_operand); - elna_tac_instruction_set_op(instruction, 2u, @assignee); - elna_tac_instruction_set_const(instruction, 3u, operand_result.offset, 4u) - else - instruction := elna_tac_instruction_create(ElnaTacOperator.copy); - elna_tac_instruction_set_op(instruction, 1u, @assignment_operand); - elna_tac_instruction_set_op(instruction, 2u, @assignee) - end; - elna_list_append(instructions, cast(instruction: ^ElnaListNode)) -return - -proc elna_tac_return_statement(instructions: ^ElnaList; parser_node: ^ElnaTreeReturnStatement; symbol_table: ^ElnaSymbolTable) -var - instruction: ^ElnaTacInstruction - operand: ElnaTacOperand -begin - instruction := elna_tac_instruction_create(ElnaTacOperator._return); - if parser_node^.returned <> nil then - elna_tac_binary_expression(instructions, parser_node^.returned, symbol_table, @operand); - elna_tac_instruction_set_op(instruction, 1u, @operand) - else - instruction^.operands[1].kind := ElnaTacKind.ignore - end; - elna_list_append(instructions, cast(instruction: ^ElnaListNode)) -return - -proc elna_tac_conditional_statements(instructions: ^ElnaList; parser_node: ^ElnaTreeConditionalStatements; - after_end_label: []const Word8; symbol_table: ^ElnaSymbolTable) -var - condition_label: []const Word8 - instruction: ^ElnaTacInstruction - operand: ElnaTacOperand -begin - elna_tac_binary_expression(instructions, parser_node^.condition, symbol_table, @operand); - condition_label := elna_tac_label(); - - instruction := elna_tac_instruction_create(ElnaTacOperator.jump_if_zero); - elna_tac_instruction_set_op(instruction, 1u, @operand); - elna_tac_instruction_set_label(instruction, 2u, condition_label); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)); - - elna_tac_statements(instructions, parser_node^.statements, symbol_table); - - instruction := elna_tac_instruction_create(ElnaTacOperator.jump); - elna_tac_instruction_set_label(instruction, 1u, after_end_label); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)); - - instruction := elna_tac_instruction_create(ElnaTacOperator.label); - elna_tac_instruction_set_label(instruction, 1u, condition_label); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)) -return - -proc elna_tac_if_statement(instructions: ^ElnaList; parser_node: ^ElnaTreeIfStatement; symbol_table: ^ElnaSymbolTable) -var - current_node: ^ElnaTreeConditionalStatements - after_end_label: []const Word8 - instruction: ^ElnaTacInstruction -begin - after_end_label := elna_tac_label(); - current_node := parser_node^.conditionals; - - while current_node <> nil do - elna_tac_conditional_statements(instructions, current_node, after_end_label, symbol_table); - current_node := current_node^.next - end; - - if parser_node^._else <> nil then - elna_tac_statements(instructions, parser_node^._else, symbol_table) - end; - - instruction := elna_tac_instruction_create(ElnaTacOperator.label); - elna_tac_instruction_set_label(instruction, 1u, after_end_label); - elna_list_append(instructions, cast(instruction: ^ElnaListNode)) -return - -proc elna_tac_statement(instructions: ^ElnaList; parser_node: ^ElnaTreeStatement; symbol_table: ^ElnaSymbolTable) -var - operand: ElnaTacOperand - call_statement: ^ElnaTreeCallStatement -begin - case parser_node^.kind of - ElnaTreeKind.goto_statement: - elna_tac_goto_statement(instructions, cast(parser_node: ^ElnaTreeGotoStatement)) - | ElnaTreeKind.if_statement: - elna_tac_if_statement(instructions, cast(parser_node: ^ElnaTreeIfStatement), symbol_table) - | ElnaTreeKind.return_statement: - elna_tac_return_statement(instructions, cast(parser_node: ^ElnaTreeReturnStatement), symbol_table) - | ElnaTreeKind.label_declaration: - elna_tac_label_declaration(instructions, cast(parser_node: ^ElnaTreeLabelDeclaration)) - | ElnaTreeKind.call_statement: - call_statement := cast(parser_node: ^ElnaTreeCallStatement); - elna_tac_call(instructions, call_statement^.call, symbol_table, @operand) - | ElnaTreeKind.assign_statement: - elna_tac_assign_statement(instructions, cast(parser_node: ^ElnaTreeAssignStatement), symbol_table) - else - end -return - -proc elna_tac_statements(instructions: ^ElnaList; current_statement: ^ElnaTreeStatement; symbol_table: ^ElnaSymbolTable) -var - current: ^ElnaTreeStatement -begin - current := current_statement; - while current <> nil do - elna_tac_statement(instructions, current, symbol_table); - current := current^.next - end -return - -proc elna_tac_parameters(ast_list: ^ElnaTreeDeclaration; parameter_count: ^Word) -> ^[]const Word8 -var - ast_parameter: ^ElnaTreeDeclaration - parameter_list: ^[]const Word8 - count: Word := 0u - i: Word := 0u -begin - ast_parameter := ast_list; - while ast_parameter <> nil do - count := count + 1u; - ast_parameter := ast_parameter^.next - end; - parameter_count^ := count; - - parameter_list := malloc#[[]const Word8](count * #size([]const Word8)); - ast_parameter := ast_list; - while i < count do - (parameter_list + i)^ := ast_parameter^.name; - i := i + 1u; - ast_parameter := ast_parameter^.next - end -return parameter_list - -proc elna_tac_procedure_declaration(parser_node: ^ElnaTreeProcedureDeclaration) -> ^ElnaTacProcedure -var - symbol_info: ^ElnaSymbolInfo - procedure_info: ^ElnaSymbolProcedureInfo - result: ^ElnaTacProcedure - parameter_count: Word := 0u -begin - result := malloc#[ElnaTacProcedure](#size(ElnaTacProcedure)); - result^.next := nil; - elna_list_initialize(@result^.body); - result^.name := parser_node^.name; - - symbol_info := elna_symbol_table_lookup(symbol_table_global, parser_node^.name); - if symbol_info <> nil & symbol_info^.kind = ElnaSymbolInfoKind.procedure_info then - procedure_info := cast(symbol_info: ^ElnaSymbolProcedureInfo); - result^.symbol_table := procedure_info^.symbol_table - else - result^.symbol_table := symbol_table_global - end; - - result^.parameters := elna_tac_parameters(parser_node^.parameters, @parameter_count); - result^.count := parameter_count; - pseudo_counter := 0u; - - elna_tac_statements(@result^.body, parser_node^.body, result^.symbol_table) -return result - -proc elna_tac_procedures(parser_node: ^ElnaTreeProcedureDeclaration) -> ^ElnaTacProcedure -var - result: ^ElnaTacProcedure - current_procedure: ^ElnaTacProcedure := nil - first_procedure: ^ElnaTacProcedure := nil - current_node: ^ElnaTreeProcedureDeclaration -begin - current_node := parser_node; - while current_node <> nil do - if ~current_node^.is_extern then - result := elna_tac_procedure_declaration(current_node); - if first_procedure = nil then - first_procedure := result - else - current_procedure^.next := result - end; - current_procedure := result - end; - current_node := cast(current_node^.next: ^ElnaTreeProcedureDeclaration) - end -return first_procedure - -proc elna_tac_variable_declaration(parser_tree: ^ElnaTreeVariableDeclaration) -> ^ElnaTacStaticVariable -var - result: ^ElnaTacStaticVariable - symbol_info: ^ElnaSymbolInfo - temp_info: ^ElnaSymbolTemporaryInfo -begin - result := malloc#[ElnaTacStaticVariable](#size(ElnaTacStaticVariable)); - result^.next := nil; - result^.name := parser_tree^.name; - result^.size := 4u; - - symbol_info := elna_symbol_table_lookup(symbol_table_global, parser_tree^.name); - if symbol_info <> nil & symbol_info^.kind = ElnaSymbolInfoKind.temporary_info then - temp_info := cast(symbol_info: ^ElnaSymbolTemporaryInfo); - if temp_info^.variable_type <> nil then - result^.size := temp_info^.variable_type^.size - end - end -return result - -proc elna_tac_var_part(parser_node: ^ElnaTreeDeclaration) -> ^ElnaTacStaticVariable -var - node: ^ElnaTacStaticVariable - current_variable: ^ElnaTacStaticVariable := nil - first_variable: ^ElnaTacStaticVariable := nil - current_node: ^ElnaTreeDeclaration -begin - current_node := parser_node; - while current_node <> nil do - node := elna_tac_variable_declaration(cast(current_node: ^ElnaTreeVariableDeclaration)); - if first_variable = nil then - first_variable := node - else - current_variable^.next := node - end; - current_variable := node; - current_node := current_node^.next - end -return first_variable - -proc elna_tac_program_body(parser_node: ^ElnaTreeStatement) -> ^ElnaTacProcedure -var - result: ^ElnaTacProcedure - symbol_info: ^ElnaSymbolInfo - procedure_info: ^ElnaSymbolProcedureInfo -begin - result := malloc#[ElnaTacProcedure](#size(ElnaTacProcedure)); - result^.next := nil; - elna_list_initialize(@result^.body); - result^.name := "main"; - - symbol_info := elna_symbol_table_lookup(symbol_table_global, result^.name); - if symbol_info <> nil & symbol_info^.kind = ElnaSymbolInfoKind.procedure_info then - procedure_info := cast(symbol_info: ^ElnaSymbolProcedureInfo); - result^.symbol_table := procedure_info^.symbol_table - else - result^.symbol_table := symbol_table_global - end; - - result^.parameters := nil; - result^.count := 0u; - pseudo_counter := 0u; - - elna_tac_statements(@result^.body, parser_node, result^.symbol_table) -return result - -proc elna_tac_module_declaration*(parser_node: ^ElnaTreeModuleDeclaration) -> ^ElnaInstructionModule -var - result: ^ElnaInstructionModule - last_proc: ^ElnaTacProcedure - body_proc: ^ElnaTacProcedure -begin - result := malloc#[ElnaInstructionModule](#size(ElnaInstructionModule)); - result^.strings := module_strings_first; - result^.data := elna_tac_var_part(parser_node^.globals); - result^.code := elna_tac_procedures(parser_node^.procedures); - - if parser_node^.body <> nil then - body_proc := elna_tac_program_body(parser_node^.body); - if result^.code = nil then - result^.code := body_proc - else - last_proc := result^.code; - while last_proc^.next <> nil do - last_proc := last_proc^.next - end; - last_proc^.next := body_proc - end - end; - result^.strings := module_strings_first -return result - -end. diff --git a/source/type_check.elna b/source/type_check.elna deleted file mode 100644 index 8edc30d..0000000 --- a/source/type_check.elna +++ /dev/null @@ -1,315 +0,0 @@ -(* 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 common, lexer, ast, symbol, diagnostic - -proc elna_type_is_aggregate*(_type: ^ElnaType) -> Bool -var - result: Bool := false -begin - if _type <> nil then - result := _type^.kind = ElnaTypeKind._record or _type^.kind = ElnaTypeKind.array - end -return result - -proc elna_type_character_literal(parser_node: ^ElnaTreeCharacterLiteral) -begin - parser_node^.type_decoration := char_type -return - -proc elna_type_integer_literal(parser_node: ^ElnaTreeIntegerLiteral) -begin - parser_node^.type_decoration := word_type -return - -proc elna_type_string_literal(parser_node: ^ElnaTreeStringLiteral) -begin - parser_node^.type_decoration := cast(string_type: ^ElnaType) -return - -proc elna_type_boolean_literal(parser_node: ^ElnaTreeBooleanLiteral) -begin - parser_node^.type_decoration := bool_type -return - -proc elna_type_nil_literal(parser_node: ^ElnaTreeNilLiteral) -begin - parser_node^.type_decoration := pointer_type -return - -proc elna_type_variable_expression(parser_node: ^ElnaTreeVariableExpression; symbol_table: ^ElnaSymbolTable) -var - variable_info: ^ElnaSymbolInfo - temporary_info: ^ElnaSymbolTemporaryInfo - procedure_info: ^ElnaSymbolProcedureInfo -begin - variable_info := elna_symbol_table_lookup(symbol_table, parser_node^.name); - if variable_info <> nil then - if variable_info^.kind = ElnaSymbolInfoKind.temporary_info then - temporary_info := cast(variable_info: ^ElnaSymbolTemporaryInfo); - parser_node^.type_decoration := temporary_info^.variable_type - elsif variable_info^.kind = ElnaSymbolInfoKind.procedure_info then - procedure_info := cast(variable_info: ^ElnaSymbolProcedureInfo); - parser_node^.type_decoration := cast(procedure_info^.procedure_type: ^ElnaType) - end - end -return - -proc elna_type_cast_expression(parser_node: ^ElnaTreeCastExpression; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -begin - elna_type_binary_expression(parser_node^.expression, symbol_table, error_list) -return - -proc elna_type_call(parser_node: ^ElnaTreeCall; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) -var - argument_tree: ^ElnaTreeExpressionList - procedure_type: ^ElnaTypeProcedure -begin - argument_tree := parser_node^.arguments; - - elna_type_variable_expression(parser_node^.callee, symbol_table); - if parser_node^.callee^.type_decoration <> nil & parser_node^.callee^.type_decoration^.kind = ElnaTypeKind.procedure then - procedure_type := cast(parser_node^.callee^.type_decoration: ^ElnaTypeProcedure); - parser_node^.type_decoration := procedure_type^.return_type - end; - - while argument_tree <> nil do - elna_type_binary_expression(argument_tree^.expression, symbol_table, error_list); - argument_tree := argument_tree^.next - end -return - -proc elna_type_dereference_expression(parser_node: ^ElnaTreeDereferenceExpression; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -var - base_type: ^ElnaType := nil - pointer_type_node: ^ElnaTypePointer -begin - elna_type_designator(parser_node^.pointer, symbol_table, error_list); - - if parser_node^.pointer^.type_decoration <> nil then - base_type := parser_node^.pointer^.type_decoration; - if base_type^.kind = ElnaTypeKind.pointer then - pointer_type_node := cast(base_type: ^ElnaTypePointer); - base_type := pointer_type_node^.base - end - end; - parser_node^.type_decoration := base_type -return - -proc elna_type_field_access_expression(parser_node: ^ElnaTreeFieldAccessExpression; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -var - variable_expression: ^ElnaTreeVariableExpression - base_type: ^ElnaType := nil - type_kind: ^ElnaSymbolTypeInfo - symbol_info: ^ElnaSymbolInfo - aggregate_type: ^ElnaTypeRecord - field_count: Word - current_field: ^ElnaTypeField -begin - if parser_node^.aggregate^.kind = ElnaTreeKind.variable_expression then - variable_expression := cast(parser_node^.aggregate: ^ElnaTreeVariableExpression); - symbol_info := elna_symbol_table_lookup(symbol_table_global, variable_expression^.name); - if symbol_info <> nil & symbol_info^.kind = ElnaSymbolInfoKind.type_info then - type_kind := cast(symbol_info: ^ElnaSymbolTypeInfo); - base_type := type_kind^._type - end - end; - - if base_type = nil then - elna_type_designator(parser_node^.aggregate, symbol_table, error_list); - if parser_node^.aggregate^.type_decoration <> nil & parser_node^.aggregate^.type_decoration^.kind = ElnaTypeKind._record then - aggregate_type := cast(parser_node^.aggregate^.type_decoration: ^ElnaTypeRecord); - field_count := aggregate_type^.length; - current_field := aggregate_type^.members; - - while field_count > 0u & base_type = nil do - if current_field^.name = parser_node^.field then - base_type := current_field^.field_type - else - field_count := field_count - 1u; - current_field := current_field + 1u - end - end - end - end; - - parser_node^.type_decoration := base_type -return - -proc elna_type_array_access_expression(parser_node: ^ElnaTreeArrayAccessExpression; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -var - aggregate_type: ^ElnaTypeArray -begin - elna_type_designator(parser_node^.array, symbol_table, error_list); - elna_type_binary_expression(parser_node^.index, symbol_table, error_list); - - if parser_node^.array^.type_decoration <> nil & parser_node^.array^.type_decoration^.kind = ElnaTypeKind.array then - aggregate_type := cast(parser_node^.array^.type_decoration: ^ElnaTypeArray); - parser_node^.type_decoration := aggregate_type^.base - end -return - -proc elna_type_simple_expression(parser_node: ^ElnaTreeExpression; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) -begin - case parser_node^.kind of - ElnaTreeKind.integer_literal: - elna_type_integer_literal(cast(parser_node: ^ElnaTreeIntegerLiteral)) - | ElnaTreeKind.character_literal: - elna_type_character_literal(cast(parser_node: ^ElnaTreeCharacterLiteral)) - | ElnaTreeKind.string_literal: - elna_type_string_literal(cast(parser_node: ^ElnaTreeStringLiteral)) - | ElnaTreeKind.boolean_literal: - elna_type_boolean_literal(cast(parser_node: ^ElnaTreeBooleanLiteral)) - | ElnaTreeKind.null: - elna_type_nil_literal(cast(parser_node: ^ElnaTreeNilLiteral)) - | ElnaTreeKind._cast: - elna_type_cast_expression(cast(parser_node: ^ElnaTreeCastExpression), symbol_table, error_list) - | ElnaTreeKind.variable_expression: - elna_type_variable_expression(cast(parser_node: ^ElnaTreeVariableExpression), symbol_table) - else - end -return - -proc elna_type_designator(parser_node: ^ElnaTreeExpression; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) -begin - case parser_node^.kind of - ElnaTreeKind.dereference_expression: - elna_type_dereference_expression(cast(parser_node: ^ElnaTreeDereferenceExpression), symbol_table, error_list) - | ElnaTreeKind.field_access_expression: - elna_type_field_access_expression(cast(parser_node: ^ElnaTreeFieldAccessExpression), symbol_table, error_list) - | ElnaTreeKind.array_access_expression: - elna_type_array_access_expression(cast(parser_node: ^ElnaTreeArrayAccessExpression), symbol_table, error_list) - | ElnaTreeKind.call: - elna_type_call(cast(parser_node: ^ElnaTreeCall), symbol_table, error_list) - else - elna_type_simple_expression(parser_node, symbol_table, error_list) - end -return - -proc elna_type_unary_expression(parser_node: ^ElnaTreeExpression; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -var - unary_node: ^ElnaTreeUnaryExpression -begin - if parser_node^.kind = ElnaTreeKind.unary_expression then - unary_node := cast(parser_node: ^ElnaTreeUnaryExpression); - elna_type_designator(unary_node^.operand, symbol_table, error_list); - parser_node^.type_decoration := unary_node^.operand^.type_decoration - else - elna_type_designator(parser_node, symbol_table, error_list) - end -return - -proc elna_type_binary_expression(parser_node: ^ElnaTreeExpression; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -var - binary_node: ^ElnaTreeBinaryExpression -begin - if parser_node <> nil then - if parser_node^.kind = ElnaTreeKind.binary_expression then - binary_node := cast(parser_node: ^ElnaTreeBinaryExpression); - elna_type_unary_expression(binary_node^.rhs, symbol_table, error_list); - elna_type_unary_expression(binary_node^.lhs, symbol_table, error_list); - parser_node^.type_decoration := binary_node^.lhs^.type_decoration - else - elna_type_unary_expression(parser_node, symbol_table, error_list) - end - end -return - -proc elna_type_assign_statement(parser_node: ^ElnaTreeAssignStatement; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -begin - elna_type_designator(parser_node^.assignee, symbol_table, error_list); - elna_type_binary_expression(parser_node^.assignment, symbol_table, error_list) -return - -proc elna_type_conditional_statements(parser_node: ^ElnaTreeConditionalStatements; symbol_table: ^ElnaSymbolTable; - error_list: ^ElnaList) -var - current: ^ElnaTreeConditionalStatements -begin - current := parser_node; - while current <> nil do - elna_type_binary_expression(current^.condition, symbol_table, error_list); - elna_type_statements(current^.statements, symbol_table, error_list); - current := current^.next - end -return - -proc elna_type_if_statement(parser_node: ^ElnaTreeIfStatement; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) -begin - elna_type_conditional_statements(parser_node^.conditionals, symbol_table, error_list); - if parser_node^._else <> nil then - elna_type_statements(parser_node^._else, symbol_table, error_list) - end -return - -proc elna_type_return_statement(parser_node: ^ElnaTreeReturnStatement; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) -begin - if parser_node^.returned <> nil then - elna_type_binary_expression(parser_node^.returned, symbol_table, error_list) - end -return - -proc elna_type_statement(parser_node: ^ElnaTreeStatement; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) -var - call_statement: ^ElnaTreeCallStatement -begin - case parser_node^.kind of - ElnaTreeKind.if_statement: - elna_type_if_statement(cast(parser_node: ^ElnaTreeIfStatement), symbol_table, error_list) - | ElnaTreeKind.return_statement: - elna_type_return_statement(cast(parser_node: ^ElnaTreeReturnStatement), symbol_table, error_list) - | ElnaTreeKind.call_statement: - call_statement := cast(parser_node: ^ElnaTreeCallStatement); - elna_type_call(call_statement^.call, symbol_table, error_list) - | ElnaTreeKind.assign_statement: - elna_type_assign_statement(cast(parser_node: ^ElnaTreeAssignStatement), symbol_table, error_list) - else - end -return - -proc elna_type_statements(parser_node: ^ElnaTreeStatement; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) -var - current: ^ElnaTreeStatement -begin - current := parser_node; - while current <> nil do - elna_type_statement(current, symbol_table, error_list); - current := current^.next - end -return - -proc elna_type_procedure_declaration(parser_node: ^ElnaTreeProcedureDeclaration; error_list: ^ElnaList) -var - procedure_info: ^ElnaSymbolProcedureInfo - symbol_info: ^ElnaSymbolInfo -begin - symbol_info := elna_symbol_table_lookup(symbol_table_global, parser_node^.name); - if symbol_info <> nil & symbol_info^.kind = ElnaSymbolInfoKind.procedure_info then - procedure_info := cast(symbol_info: ^ElnaSymbolProcedureInfo); - elna_type_statements(parser_node^.body, procedure_info^.symbol_table, error_list) - end -return - -proc elna_type_module_declaration*(parser_node: ^ElnaTreeModuleDeclaration; error_list: ^ElnaList) -var - current_proc: ^ElnaTreeProcedureDeclaration -begin - current_proc := parser_node^.procedures; - while current_proc <> nil do - elna_type_procedure_declaration(current_proc, error_list); - current_proc := cast(current_proc^.next: ^ElnaTreeProcedureDeclaration) - end; - if parser_node^.body <> nil then - elna_type_statements(parser_node^.body, symbol_table_global, error_list) - end -return - -end. diff --git a/testsuite/compilable/generic_export.elna b/testsuite/compilable/generic_export.elna new file mode 100644 index 0000000..64767fe --- /dev/null +++ b/testsuite/compilable/generic_export.elna @@ -0,0 +1,11 @@ +module + +type + Stack#[T]* = record + item: ^T + end + +proc push#[T]*(s: ^Stack#[T]; item: ^T) +return + +end. diff --git a/testsuite/fail_compilation/generic_variable.elna b/testsuite/fail_compilation/generic_variable.elna new file mode 100644 index 0000000..21f031a --- /dev/null +++ b/testsuite/fail_compilation/generic_variable.elna @@ -0,0 +1,6 @@ +module + +var + x#[T]: Int (* @Error Variables cannot have generic parameters *) + +end. |
