Implement defer

This commit is contained in:
2025-02-07 22:12:59 +01:00
parent 077de53c74
commit 68c49f8cd4
13 changed files with 440 additions and 291 deletions

View File

@ -90,6 +90,14 @@ namespace boot
}
}
void empty_visitor::visit(defer_statement *defer)
{
for (statement *const body_statement : defer->statements)
{
body_statement->accept(this);
}
}
void empty_visitor::visit(block *block)
{
for (constant_definition *const constant : block->constants)
@ -204,7 +212,7 @@ namespace boot
{
}
void empty_visitor::visit(string_literal *)
void empty_visitor::visit(number_literal<std::string> *)
{
}
@ -377,8 +385,8 @@ namespace boot
}
variable_declaration::variable_declaration(const struct position position, const std::string& identifier,
type_expression *type)
: definition(position, identifier), m_type(type)
const bool exported, type_expression *type)
: definition(position, identifier, exported), m_type(type)
{
}
@ -397,19 +405,14 @@ namespace boot
return *m_type;
}
definition::definition(const struct position position, const std::string& identifier)
: node(position), m_identifier(identifier)
definition::definition(const struct position position, const std::string& identifier, const bool exported)
: node(position), identifier(identifier), exported(exported)
{
}
std::string& definition::identifier()
{
return m_identifier;
}
constant_definition::constant_definition(const struct position position, const std::string& identifier,
literal *body)
: definition(position, identifier), m_body(body)
const bool exported, literal *body)
: definition(position, identifier, exported), m_body(body)
{
}
@ -429,8 +432,8 @@ namespace boot
}
procedure_definition::procedure_definition(const struct position position, const std::string& identifier,
std::vector<variable_declaration *>&& parameters, type_expression *return_type, block *body)
: definition(position, identifier), m_return_type(return_type), m_body(body), parameters(std::move(parameters))
const bool exported, type_expression *return_type)
: definition(position, identifier, exported), m_return_type(return_type)
{
}
@ -444,6 +447,12 @@ namespace boot
return m_body;
}
procedure_definition *procedure_definition::add_body(block *procedure_body)
{
m_body = procedure_body;
return this;
}
type_expression *procedure_definition::return_type()
{
return m_return_type;
@ -462,8 +471,8 @@ namespace boot
}
type_definition::type_definition(const struct position position, const std::string& identifier,
type_expression *body)
: definition(position, identifier), m_body(body)
const bool exported, type_expression *body)
: definition(position, identifier, exported), m_body(body)
{
}
@ -535,19 +544,22 @@ namespace boot
{
}
string_literal::string_literal(const struct position position, const std::string& value)
: literal(position), m_string(value)
defer_statement::defer_statement(const struct position position)
: statement(position)
{
}
void string_literal::accept(parser_visitor *visitor)
void defer_statement::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
const std::string& string_literal::string() const
defer_statement::~defer_statement()
{
return m_string;
for (statement *body_statement : statements)
{
delete body_statement;
}
}
designator_expression::designator_expression(const struct position position)
@ -608,7 +620,7 @@ namespace boot
}
field_access_expression::field_access_expression(const struct position position,
designator_expression *base, const std::string& field)
expression *base, const std::string& field)
: designator_expression(position), m_base(base), m_field(field)
{
}
@ -618,7 +630,7 @@ namespace boot
visitor->visit(this);
}
designator_expression& field_access_expression::base()
expression& field_access_expression::base()
{
return *m_base;
}

View File

@ -9,10 +9,11 @@ namespace boot
{
position make_position(const yy::location& location)
{
return position{
static_cast<std::size_t>(location.begin.line),
static_cast<std::size_t>(location.begin.column)
};
position result;
result.line = static_cast<std::size_t>(location.begin.line);
result.column = static_cast<std::size_t>(location.begin.column);
return result;
}
syntax_error::syntax_error(const std::string& message,
@ -33,7 +34,7 @@ namespace boot
void driver::error(const yy::location& loc, const std::string& message)
{
m_errors.emplace_back(std::make_unique<boot::syntax_error>(message, input_file, loc));
m_errors.emplace_back(new boot::syntax_error(message, input_file, loc));
}
const std::list<std::unique_ptr<struct error>>& driver::errors() const noexcept
@ -41,36 +42,36 @@ namespace boot
return m_errors;
}
std::optional<char> escape_char(char escape)
char escape_char(char escape)
{
switch (escape)
{
case 'n':
return std::make_optional<char>('\n');
return '\n';
case 'a':
return std::make_optional<char>('\a');
return '\a';
case 'b':
return std::make_optional<char>('\b');
return '\b';
case 't':
return std::make_optional<char>('\t');
return '\t';
case 'f':
return std::make_optional<char>('\f');
return '\f';
case 'r':
return std::make_optional<char>('\r');
return '\r';
case 'v':
return std::make_optional<char>('\v');
return '\v';
case '\\':
return std::make_optional<char>('\\');
return '\\';
case '\'':
return std::make_optional<char>('\'');
return '\'';
case '"':
return std::make_optional<char>('"');
return '"';
case '?':
return std::make_optional<char>('\?');
return '\?';
case '0':
return std::make_optional<char>('\0');
return '\0';
default:
return std::nullopt;
return escape_invalid_char;
}
}
}

View File

@ -127,6 +127,9 @@ as {
sizeof {
return yy::parser::make_SIZEOF(this->location);
}
defer {
return yy::parser::make_DEFER(this->location);
}
[A-Za-z_][A-Za-z0-9_]* {
return yy::parser::make_IDENTIFIER(yytext, this->location);
}
@ -155,15 +158,12 @@ sizeof {
return yy::parser::make_CHARACTER(std::string(&character, 1), this->location);
}
'\\[0nabtfrv\\'"?]' {
std::optional<char> escape = elna::boot::escape_char(yytext[2]);
if (escape.has_value())
{
return yy::parser::make_CHARACTER(std::string(&escape.value(), 1), this->location);
}
else
char escape = elna::boot::escape_char(yytext[2]);
if (escape == escape_invalid_char)
{
REJECT;
}
return yy::parser::make_CHARACTER(std::string(&escape, 1), this->location);
}
\"[[:print:]]*\" {
std::string result;
@ -191,15 +191,12 @@ sizeof {
{
++current_position;
std::optional<char> escape = elna::boot::escape_char(*current_position);
if (escape.has_value())
{
result.push_back(escape.value());
}
else
char escape = elna::boot::escape_char(*current_position);
if (escape == elna::boot::escape_invalid_char)
{
REJECT;
}
result.push_back(escape);
}
else
{

View File

@ -71,7 +71,7 @@
%token <bool> BOOLEAN
%token IF WHILE DO THEN ELSE ELSIF RETURN
%token CONST VAR PROCEDURE ARRAY OF TYPE RECORD POINTER TO UNION
%token BEGIN_BLOCK END_BLOCK EXTERN
%token BEGIN_BLOCK END_BLOCK EXTERN DEFER
%token LEFT_PAREN RIGHT_PAREN LEFT_SQUARE RIGHT_SQUARE SEMICOLON DOT COMMA
%token AND OR NOT CAST AS SIZEOF
%token GREATER_EQUAL LESS_EQUAL LESS_THAN GREATER_THAN NOT_EQUAL EQUALS
@ -100,7 +100,7 @@
%type <elna::boot::return_statement *> return_statement;
%type <elna::boot::statement *> statement;
%type <std::vector<elna::boot::statement *>> statements optional_statements;
%type <elna::boot::procedure_definition *> procedure_definition;
%type <elna::boot::procedure_definition *> procedure_definition procedure_heading;
%type <std::vector<elna::boot::procedure_definition *>> procedure_definitions procedure_part;
%type <elna::boot::type_definition *> type_definition;
%type <std::vector<elna::boot::type_definition *>> type_definitions type_part;
@ -109,6 +109,8 @@
%type <std::vector<std::pair<std::string, elna::boot::type_expression *>>> field_list;
%type <std::vector<elna::boot::conditional_statements *>> elsif_statement_list;
%type <elna::boot::cast_expression *> cast_expression;
%type <elna::boot::defer_statement *> defer_statement;
%type <std::pair<std::string, bool>> identifier_definition;
%%
program:
constant_part type_part variable_part procedure_part BEGIN_BLOCK optional_statements END_BLOCK DOT
@ -131,27 +133,31 @@ block: constant_part variable_part BEGIN_BLOCK optional_statements END_BLOCK
std::swap($$->variables, $2);
std::swap($$->body, $4);
}
identifier_definition:
IDENTIFIER MULTIPLICATION
{
$$ = std::make_pair($1, true);
}
| IDENTIFIER
{
$$ = std::make_pair($1, false);
}
procedure_heading:
PROCEDURE identifier_definition formal_parameter_list SEMICOLON
{
$$ = new elna::boot::procedure_definition(elna::boot::make_position(@1),
$2.first, $2.second);
std::swap($3, $$->parameters);
}
| PROCEDURE identifier_definition formal_parameter_list COLON type_expression SEMICOLON
{
$$ = new elna::boot::procedure_definition(elna::boot::make_position(@1),
$2.first, $2.second, $5);
std::swap($3, $$->parameters);
}
procedure_definition:
PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON block SEMICOLON
{
$$ = new elna::boot::procedure_definition(elna::boot::make_position(@1),
$2, std::move($3), nullptr, $5);
}
| PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON EXTERN SEMICOLON
{
$$ = new elna::boot::procedure_definition(elna::boot::make_position(@1),
$2, std::move($3), nullptr, nullptr);
}
| PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON block SEMICOLON
{
$$ = new elna::boot::procedure_definition(elna::boot::make_position(@1),
$2, std::move($3), $5, $7);
}
| PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON EXTERN SEMICOLON
{
$$ = new elna::boot::procedure_definition(elna::boot::make_position(@1),
$2, std::move($3), $5, nullptr);
}
procedure_heading block SEMICOLON { $$ = $1->add_body($2); }
| procedure_heading EXTERN SEMICOLON { $$ = $1; }
procedure_definitions:
procedure_definition procedure_definitions
{
@ -206,11 +212,15 @@ if_statement:
$$ = new elna::boot::if_statement(elna::boot::make_position(@1), then, _else);
std::swap($5, $$->branches);
}
return_statement:
RETURN expression
return_statement: RETURN expression
{
$$ = new elna::boot::return_statement(elna::boot::make_position(@1), $2);
}
defer_statement: DEFER optional_statements END_BLOCK
{
$$ = new elna::boot::defer_statement(elna::boot::make_position(@1));
std::swap($2, $$->statements);
}
literal:
INTEGER
{
@ -238,7 +248,7 @@ literal:
}
| STRING
{
$$ = new elna::boot::string_literal(elna::boot::make_position(@1), $1);
$$ = new elna::boot::number_literal<std::string>(elna::boot::make_position(@1), $1);
}
operand:
literal { $$ = $1; }
@ -346,7 +356,7 @@ designator_expression:
{
$$ = new elna::boot::array_access_expression(elna::boot::make_position(@1), $1, $3);
}
| designator_expression DOT IDENTIFIER
| operand DOT IDENTIFIER
{
$$ = new elna::boot::field_access_expression(elna::boot::make_position(@2), $1, $3);
}
@ -367,6 +377,7 @@ statement:
{
$$ = new elna::boot::call_statement(elna::boot::make_position(@1), $1);
}
| defer_statement { $$ = $1; }
statements:
statement SEMICOLON statements
{
@ -407,9 +418,9 @@ type_expression:
{
$$ = new elna::boot::basic_type_expression(elna::boot::make_position(@1), $1);
}
variable_declaration: IDENTIFIER COLON type_expression
variable_declaration: identifier_definition COLON type_expression
{
$$ = new elna::boot::variable_declaration(elna::boot::make_position(@1), $1, $3);
$$ = new elna::boot::variable_declaration(elna::boot::make_position(@2), $1.first, $1.second, $3);
}
variable_declarations:
variable_declaration COMMA variable_declarations
@ -421,9 +432,9 @@ variable_declarations:
variable_part:
/* no variable declarations */ {}
| VAR variable_declarations SEMICOLON { std::swap($$, $2); }
constant_definition: IDENTIFIER EQUALS literal SEMICOLON
constant_definition: identifier_definition EQUALS literal SEMICOLON
{
$$ = new elna::boot::constant_definition(elna::boot::make_position(@1), $1, $3);
$$ = new elna::boot::constant_definition(elna::boot::make_position(@1), $1.first, $1.second, $3);
}
constant_definitions:
constant_definition constant_definitions
@ -436,9 +447,9 @@ constant_part:
/* no constant definitions */ {}
| CONST {}
| CONST constant_definitions { std::swap($$, $2); }
type_definition: IDENTIFIER EQUALS type_expression
type_definition: identifier_definition EQUALS type_expression
{
$$ = new elna::boot::type_definition(elna::boot::make_position(@1), $1, $3);
$$ = new elna::boot::type_definition(elna::boot::make_position(@1), $1.first, $1.second, $3);
}
type_definitions:
type_definition COMMA type_definitions