Implement noreturn procedure declarations
This commit is contained in:
parent
39750f4656
commit
0b835abfa9
@ -419,7 +419,13 @@ namespace boot
|
||||
|
||||
procedure_definition::procedure_definition(const struct position position, const std::string& identifier,
|
||||
const bool exported, std::shared_ptr<top_type> 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 }
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -280,6 +280,9 @@ defer {
|
||||
@ {
|
||||
return yy::parser::make_AT(this->location);
|
||||
}
|
||||
! {
|
||||
return yy::parser::make_EXCLAMATION(this->location);
|
||||
}
|
||||
. {
|
||||
std::stringstream ss;
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
23
gcc/lang.opt
Normal file
23
gcc/lang.opt
Normal file
@ -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
|
||||
; <http://www.gnu.org/licenses/>.
|
||||
|
||||
; 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
|
@ -366,10 +366,16 @@ namespace boot
|
||||
block *m_body{ nullptr };
|
||||
|
||||
public:
|
||||
struct no_return_t
|
||||
{
|
||||
};
|
||||
const bool no_return{ false };
|
||||
std::vector<variable_declaration *> parameters;
|
||||
|
||||
procedure_definition(const struct position position, const std::string& identifier,
|
||||
const bool exported, std::shared_ptr<top_type> 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<top_type> return_type();
|
||||
|
100
source.elna
100
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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user