diff --git a/boot/ast.cc b/boot/ast.cc index a1ff75d..7755998 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -419,7 +419,13 @@ namespace boot procedure_definition::procedure_definition(const struct position position, const std::string& identifier, const bool exported, std::shared_ptr return_type) - : definition(position, identifier, exported), m_return_type(return_type) + : definition(position, identifier, exported), m_return_type(return_type), no_return{ false } + { + } + + procedure_definition::procedure_definition(const struct position position, const std::string& identifier, + const bool exported, no_return_t) + : definition(position, identifier, exported), m_return_type(nullptr), no_return{ true } { } diff --git a/boot/lexer.ll b/boot/lexer.ll index 574cbcf..cb8837a 100644 --- a/boot/lexer.ll +++ b/boot/lexer.ll @@ -280,6 +280,9 @@ defer { @ { return yy::parser::make_AT(this->location); } +! { + return yy::parser::make_EXCLAMATION(this->location); + } . { std::stringstream ss; diff --git a/boot/parser.yy b/boot/parser.yy index bf12292..f5362e0 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -85,13 +85,12 @@ along with GCC; see the file COPYING3. If not see %token CONST VAR PROCEDURE TYPE RECORD UNION %token BEGIN_BLOCK END_BLOCK EXTERN DEFER %token LEFT_PAREN RIGHT_PAREN LEFT_SQUARE RIGHT_SQUARE SEMICOLON DOT COMMA -%token AND OR NOT CAST SHIFT_LEFT SHIFT_RIGHT -%token GREATER_EQUAL LESS_EQUAL LESS_THAN GREATER_THAN NOT_EQUAL EQUALS -%token PLUS MINUS MULTIPLICATION DIVISION REMAINDER +%token NOT CAST EXCLAMATION %token ASSIGNMENT COLON HAT AT NIL ARROW %left OR AND XOR %left EQUALS NOT_EQUAL LESS_THAN GREATER_THAN LESS_EQUAL GREATER_EQUAL +%left SHIFT_LEFT SHIFT_RIGHT %left PLUS MINUS %left MULTIPLICATION DIVISION REMAINDER @@ -169,6 +168,12 @@ procedure_heading: $2.first, $2.second); std::swap($3, $$->parameters); } + | PROCEDURE identifier_definition formal_parameter_list ARROW EXCLAMATION SEMICOLON + { + $$ = new elna::boot::procedure_definition(elna::boot::make_position(@1), + $2.first, $2.second, elna::boot::procedure_definition::no_return_t{}); + std::swap($3, $$->parameters); + } | PROCEDURE identifier_definition formal_parameter_list ARROW type_expression SEMICOLON { $$ = new elna::boot::procedure_definition(elna::boot::make_position(@1), diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 292c0c6..092d226 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -256,6 +256,10 @@ namespace gcc tree fndecl = build_fn_decl(definition->identifier.c_str(), declaration_type); this->symbol_map->enter(definition->identifier, fndecl); + if (definition->no_return) + { + TREE_THIS_VOLATILE(fndecl) = 1; + } if (definition->body() != nullptr) { tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, return_type); diff --git a/gcc/lang.opt b/gcc/lang.opt new file mode 100644 index 0000000..1c8c95c --- /dev/null +++ b/gcc/lang.opt @@ -0,0 +1,23 @@ +; lang.opt -- Options for the Elna front end. +; Copyright (C) 2025 Free Software Foundation, Inc. +; +; GCC is free software; you can redistribute it and/or modify it under +; the terms of the GNU General Public License as published by the Free +; Software Foundation; either version 3, or (at your option) any later +; version. +; +; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +; WARRANTY; without even the implied warranty of MERCHANTABILITY or +; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +; for more details. +; +; You should have received a copy of the GNU General Public License +; along with GCC; see the file COPYING3. If not see +; . + +; See the GCC internals manual for a description of this file's format. + +; Please try to keep this file in ASCII collating order. + +Language +Elna diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index cbb437e..e569503 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -366,10 +366,16 @@ namespace boot block *m_body{ nullptr }; public: + struct no_return_t + { + }; + const bool no_return{ false }; std::vector parameters; procedure_definition(const struct position position, const std::string& identifier, const bool exported, std::shared_ptr return_type = nullptr); + procedure_definition(const struct position position, const std::string& identifier, + const bool exported, no_return_t); virtual void accept(parser_visitor *visitor) override; std::shared_ptr return_type(); diff --git a/source.elna b/source.elna index 1ad15f9..c4fa23c 100644 --- a/source.elna +++ b/source.elna @@ -60,6 +60,8 @@ const TOKEN_CHARACTER* = 55 TOKEN_STRING* = 56 TOKEN_DEFER* = 57 + TOKEN_EXCLAMATION* = 58 + TOKEN_ARROW = 59 type Position* = record @@ -92,20 +94,6 @@ type tokenize: Bool syntax_tree: Bool end - Literal* = record - value: Int - end - ConstantDefinition* = record - name: ^Char - body: ^Literal - end - ConstantPart* = record - elements: ^^ConstantDefinition - count: Word - end - Program* = record - constants: ConstantPart - end (* External procedures. @@ -134,7 +122,7 @@ proc strlen(ptr: ^Char) -> Word; extern proc strtol(nptr: ^Char, endptr: ^^Char, base: Int) -> Int; extern proc perror(s: ^Char); extern -proc exit(code: Int); extern +proc exit(code: Int) -> !; extern (* Standard procedures. @@ -567,6 +555,10 @@ begin write_s("\"...\"") elsif current_token^.kind = TOKEN_DEFER then write_s("DEFER") + elsif current_token^.kind = TOKEN_EXCLAMATION then + write_c('!') + elsif current_token^.kind = TOKEN_ARROW then + write_s("->") else write_s("UNKNOWN<") write_i(current_token^.kind) @@ -772,8 +764,16 @@ begin current_token^.kind := TOKEN_PLUS source_code := advance_source(source_code, 1u) elsif first_char = '-' then - current_token^.kind := TOKEN_MINUS source_code := advance_source(source_code, 1u) + + if source_code.text.length = 0u then + current_token^.kind := TOKEN_MINUS + elsif source_code.text[1u] = '>' then + current_token^.kind := TOKEN_ARROW + source_code := advance_source(source_code, 1u) + else + current_token^.kind := TOKEN_MINUS + end elsif first_char = '*' then current_token^.kind := TOKEN_MULTIPLICATION source_code := advance_source(source_code, 1u) @@ -800,6 +800,9 @@ begin elsif first_char = '@' then current_token^.kind := TOKEN_AT source_code := advance_source(source_code, 1u) + elsif first_char = '!' then + current_token^.kind := TOKEN_EXCLAMATION + source_code := advance_source(source_code, 1u) else current_token^.kind := 0 source_code := advance_source(source_code, 1u) @@ -818,68 +821,6 @@ begin return tokens end -proc parse_literal(tokens: ^^Token, tokens_size: ^Word) -> ^Literal; -begin - return cast(calloc(1u, Literal.size): ^Literal) -end - -proc parse_constant_definition(tokens: ^^Token, - tokens_size: ^Word) -> ^ConstantDefinition; -var - result: ^ConstantDefinition -begin - result := cast(calloc(1u, ConstantDefinition.size): ^ConstantDefinition) - - result^.name := cast(malloc(strlen(tokens^^.value.string_value)): ^Char) - strcpy(result^.name, tokens^^.value.string_value) - - tokens^ := tokens^ + 2u - tokens_size := tokens_size - 2u - - write_z(result^.name) - write_c('\n') - - result^.body := parse_literal(tokens, tokens_size) - - tokens^ := tokens^ + 2u - tokens_size := tokens_size - 2u - - return result -end - -proc parse_program(tokens: ^^Token, tokens_size: ^Word) -> ^Program; -var - result: ^Program - current_constant: ^^ConstantDefinition -begin - result := cast(calloc(1u, Program.size): ^Program) - - result^.constants.elements := nil - result^.constants.count := 0u - - if tokens^^.kind = TOKEN_CONST then - tokens^ := tokens^ + 1 - tokens_size^ := tokens_size^ - 1u - - while tokens_size^ > 0u and tokens^^.kind = TOKEN_IDENTIFIER do - result^.constants.elements := cast( - reallocarray( - cast(result^.constants.elements: ^Byte), - result^.constants.count + 1u, - (^ConstantDefinition).size - ) : ^^ConstantDefinition) - current_constant := result^.constants.elements + result^.constants.count - - result^.constants.count := result^.constants.count + 1u - - current_constant^ := parse_constant_definition(tokens, tokens_size) - if current_constant^ = nil then - return nil - end - end - end -end - proc parse_command_line*(argc: Int, argv: ^^Char) -> ^CommandLine; var parameter: ^^Char @@ -943,9 +884,6 @@ begin if command_line^.tokenize then print_tokens(tokens, tokens_size) end - if command_line^.syntax_tree then - parse_program(@tokens, @tokens_size) - end return 0 end