Support procedures returning values

This commit is contained in:
2025-01-18 21:30:11 +01:00
parent a79def50e5
commit 7b36a3803f
10 changed files with 217 additions and 73 deletions

View File

@ -33,7 +33,7 @@ namespace source
definition->body().accept(this);
}
void empty_visitor::visit(call_statement *statement)
void empty_visitor::visit(call_expression *statement)
{
for (auto& argument : statement->arguments())
{
@ -41,6 +41,11 @@ namespace source
}
}
void empty_visitor::visit(expression_statement *statement)
{
statement->body().accept(this);
}
void empty_visitor::visit(compound_statement *statement)
{
for (const auto nested_statement : statement->statements)
@ -66,6 +71,16 @@ namespace source
statement->body().accept(this);
}
void empty_visitor::visit(return_statement *statement)
{
expression *return_expression = statement->return_expression();
if (return_expression != nullptr)
{
return_expression->accept(this);
}
}
void empty_visitor::visit(block *block)
{
for (const auto definition : block->value_definitions)
@ -433,8 +448,8 @@ namespace source
}
procedure_definition::procedure_definition(const struct position position, const std::string& identifier,
block *body)
: definition(position, identifier), m_body(body)
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))
{
}
@ -448,6 +463,11 @@ namespace source
return m_body;
}
type_expression *procedure_definition::return_type()
{
return m_return_type;
}
procedure_definition::~procedure_definition()
{
if (m_body != nullptr)
@ -768,27 +788,27 @@ namespace source
delete m_operand;
}
call_statement::call_statement(const struct position position, const std::string& name)
: statement(position), m_name(name)
call_expression::call_expression(const struct position position, const std::string& name)
: expression(position), m_name(name)
{
}
void call_statement::accept(parser_visitor *visitor)
void call_expression::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
std::string& call_statement::name()
std::string& call_expression::name()
{
return m_name;
}
std::vector<expression *>& call_statement::arguments()
std::vector<expression *>& call_expression::arguments()
{
return m_arguments;
}
call_statement::~call_statement()
call_expression::~call_expression()
{
for (auto argument : m_arguments)
{
@ -796,8 +816,28 @@ namespace source
}
}
expression_statement::expression_statement(const struct position position, expression *body)
: statement(position), m_body(body)
{
}
void expression_statement::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
expression& expression_statement::body()
{
return *m_body;
}
expression_statement::~expression_statement()
{
delete m_body;
}
compound_statement::compound_statement(const struct position position, std::vector<statement *>&& statements)
: statement(position), statements(std::move(statements))
: node(position), statements(std::move(statements))
{
}
@ -814,6 +854,29 @@ namespace source
}
}
return_statement::return_statement(const struct position position, expression *return_expression)
: statement(position), m_return_expression(return_expression)
{
}
void return_statement::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
expression *return_statement::return_expression()
{
return m_return_expression;
}
return_statement::~return_statement()
{
if (m_return_expression != nullptr)
{
delete m_return_expression;
}
}
void assign_statement::accept(parser_visitor *visitor)
{
visitor->visit(this);

View File

@ -100,6 +100,9 @@ or {
not {
return yy::parser::make_NOT(this->location);
}
return {
return yy::parser::make_RETURN(this->location);
}
[A-Za-z_][A-Za-z0-9_]* {
return yy::parser::make_IDENTIFIER(yytext, this->location);
}

View File

@ -62,7 +62,7 @@
%token <std::string> CHARACTER "character"
%token <std::string> STRING "string"
%token <bool> BOOLEAN
%token IF WHILE DO THEN ELSE
%token IF WHILE DO THEN ELSE RETURN
%token CONST VAR PROCEDURE ARRAY OF TYPE RECORD POINTER TO UNION
%token BEGIN_BLOCK END_BLOCK EXTERN
%token LEFT_PAREN RIGHT_PAREN LEFT_SQUARE RIGHT_SQUARE SEMICOLON DOT COMMA
@ -82,9 +82,10 @@
%type <std::vector<elna::source::expression *>> expressions actual_parameter_list;
%type <elna::source::designator_expression *> designator_expression;
%type <elna::source::assign_statement *> assign_statement;
%type <elna::source::call_statement *> call_statement;
%type <elna::source::call_expression *> call_expression;
%type <elna::source::while_statement *> while_statement;
%type <elna::source::if_statement *> if_statement;
%type <elna::source::return_statement *> return_statement;
%type <elna::source::statement *> statement;
%type <std::vector<elna::source::statement *>> statements optional_statements;
%type <elna::source::procedure_definition *> procedure_definition;
@ -144,14 +145,22 @@ procedure_definition:
PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON block SEMICOLON
{
$$ = new elna::source::procedure_definition(elna::source::position{},
std::move($2), $5);
std::swap($$->parameters, $3);
$2, std::move($3), nullptr, $5);
}
| PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON EXTERN SEMICOLON
{
$$ = new elna::source::procedure_definition(elna::source::position{},
std::move($2));
std::swap($$->parameters, $3);
$2, std::move($3), nullptr, nullptr);
}
| PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON block SEMICOLON
{
$$ = new elna::source::procedure_definition(elna::source::position{},
$2, std::move($3), $5, $7);
}
| PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON EXTERN SEMICOLON
{
$$ = new elna::source::procedure_definition(elna::source::position{},
$2, std::move($3), $5, nullptr);
}
procedure_definitions:
procedure_definition procedure_definitions
@ -167,9 +176,9 @@ assign_statement: designator_expression ASSIGNMENT expression
{
$$ = new elna::source::assign_statement(elna::source::make_position(@1), $1, $3);
}
call_statement: IDENTIFIER actual_parameter_list
call_expression: IDENTIFIER actual_parameter_list
{
$$ = new elna::source::call_statement(elna::source::make_position(@1), $1);
$$ = new elna::source::call_expression(elna::source::make_position(@1), $1);
std::swap($$->arguments(), $2);
}
while_statement: WHILE expression DO optional_statements END_BLOCK
@ -189,6 +198,11 @@ if_statement:
auto _else = new elna::source::compound_statement(elna::source::make_position(@5), std::move($6));
$$ = new elna::source::if_statement(elna::source::make_position(@1), $2, then, _else);
}
return_statement:
RETURN expression
{
$$ = new elna::source::return_statement(elna::source::make_position(@1), $2);
}
literal:
INTEGER
{
@ -282,6 +296,7 @@ expression:
$$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, 'o');
}
| logical_operand { $$ = $1; }
| call_expression { $$ = $1; }
expressions:
expression COMMA expressions
{
@ -308,9 +323,10 @@ designator_expression:
}
statement:
assign_statement { $$ = $1; }
| call_statement { $$ = $1; }
| while_statement { $$ = $1; }
| if_statement { $$ = $1; }
| return_statement { $$ = $1; }
| expression { $$ = new elna::source::expression_statement(elna::source::make_position(@1), $1); }
statements:
statement SEMICOLON statements
{