Implement procedure pointers

This commit is contained in:
2025-02-24 00:24:36 +01:00
parent 18857e1a88
commit 85b6843ecf
9 changed files with 217 additions and 181 deletions

View File

@ -46,7 +46,7 @@ namespace boot
void empty_visitor::visit(call_expression *expression)
{
for (auto& argument : expression->arguments())
for (struct expression *const argument : expression->arguments)
{
argument->accept(this);
}
@ -734,8 +734,8 @@ namespace boot
delete m_operand;
}
call_expression::call_expression(const struct position position, const std::string& name)
: expression(position), m_name(name)
call_expression::call_expression(const struct position position, designator_expression *callable)
: expression(position), m_callable(callable)
{
}
@ -744,22 +744,18 @@ namespace boot
visitor->visit(this);
}
std::string& call_expression::name()
designator_expression& call_expression::callable()
{
return m_name;
}
std::vector<expression *>& call_expression::arguments()
{
return m_arguments;
return *m_callable;
}
call_expression::~call_expression()
{
for (auto argument : m_arguments)
for (expression *const argument : arguments)
{
delete argument;
}
delete m_callable;
}
cast_expression::cast_expression(const struct position position,

View File

@ -74,25 +74,49 @@ along with GCC; see the file COPYING3. If not see
}
%start program;
%token <std::string> IDENTIFIER "identifier"
%token <std::int32_t> INTEGER "integer"
%token <std::uint32_t> WORD "word"
%token <float> FLOAT "float"
%token <std::string> CHARACTER "character"
%token <std::string> STRING "string"
%token <std::string> IDENTIFIER
%token <std::int32_t> INTEGER
%token <std::uint32_t> WORD
%token <float> FLOAT
%token <std::string> CHARACTER
%token <std::string> STRING
%token <bool> BOOLEAN
%token IF WHILE DO THEN ELSE ELSIF RETURN
%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 NOT CAST EXCLAMATION
%token ASSIGNMENT COLON HAT AT NIL ARROW
%token LEFT_PAREN "(" RIGHT_PAREN ")" LEFT_SQUARE "[" RIGHT_SQUARE "]"
%token ASSIGNMENT ":="
ARROW "->" EXCLAMATION "!"
AT "@" HAT "^"
COLON ":" SEMICOLON ";" DOT "." COMMA ","
%token NOT "not"
CAST "cast"
NIL "nil"
CONST "const"
VAR "var"
PROCEDURE "proc"
TYPE "type"
RECORD "record"
UNION "union"
EXTERN "extern"
IF "if"
WHILE "while"
DO "do"
THEN "then"
ELSE "else"
ELSIF "elsif"
RETURN "return"
BEGIN_BLOCK "begin"
END_BLOCK "end"
DEFER "defer"
%token OR "or" AND "and" XOR "xor"
EQUALS "=" NOT_EQUAL "<>" LESS_THAN "<" GREATER_THAN ">" LESS_EQUAL "<=" GREATER_EQUAL ">="
SHIFT_LEFT "<<" SHIFT_RIGHT ">>"
PLUS "+" MINUS "-"
MULTIPLICATION "*" DIVISION "/" REMAINDER "%"
%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
%left "or" "and" "xor"
%left "=" "<>" "<" ">" "<=" ">="
%left "<<" ">>"
%left "+" "-"
%left "*" "/" "%"
%type <elna::boot::literal *> literal;
%type <elna::boot::constant_definition *> constant_definition;
@ -126,7 +150,7 @@ along with GCC; see the file COPYING3. If not see
%type <std::vector<std::pair<std::string, bool>>> identifier_definitions;
%%
program:
constant_part type_part variable_part procedure_part BEGIN_BLOCK optional_statements END_BLOCK DOT
constant_part type_part variable_part procedure_part "begin" optional_statements "end" "."
{
auto tree = new elna::boot::program(elna::boot::make_position(@5));
@ -138,7 +162,7 @@ program:
driver.tree.reset(tree);
}
block: constant_part variable_part BEGIN_BLOCK optional_statements END_BLOCK
block: constant_part variable_part "begin" optional_statements "end"
{
$$ = new elna::boot::block(elna::boot::make_position(@3));
@ -147,7 +171,7 @@ block: constant_part variable_part BEGIN_BLOCK optional_statements END_BLOCK
std::swap($$->body, $4);
}
identifier_definition:
IDENTIFIER MULTIPLICATION
IDENTIFIER "*"
{
$$ = std::make_pair($1, true);
}
@ -156,7 +180,7 @@ identifier_definition:
$$ = std::make_pair($1, false);
}
identifier_definitions:
identifier_definition COMMA identifier_definitions
identifier_definition "," identifier_definitions
{
std::swap($$, $3);
$$.emplace($$.cbegin(), $1);
@ -168,22 +192,22 @@ procedure_heading:
$$ = std::make_shared<elna::boot::procedure_type>(elna::boot::make_position(@1));
std::swap($1, $$->parameters);
}
| formal_parameter_list ARROW EXCLAMATION
| formal_parameter_list "->" "!"
{
$$ = std::make_shared<elna::boot::procedure_type>(elna::boot::make_position(@1), elna::boot::no_return);
std::swap($1, $$->parameters);
}
| formal_parameter_list ARROW type_expression
| formal_parameter_list "->" type_expression
{
$$ = std::make_shared<elna::boot::procedure_type>(elna::boot::make_position(@1), $3);
std::swap($1, $$->parameters);
}
procedure_definition:
PROCEDURE identifier_definition procedure_heading SEMICOLON block
"proc" identifier_definition procedure_heading ";" block
{
$$ = new elna::boot::procedure_definition(elna::boot::make_position(@1), $2.first, $2.second, $3, $5);
}
| PROCEDURE identifier_definition procedure_heading SEMICOLON EXTERN
| "proc" identifier_definition procedure_heading ";" "extern"
{
$$ = new elna::boot::procedure_definition(elna::boot::make_position(@1), $2.first, $2.second, $3);
}
@ -197,21 +221,21 @@ procedure_definitions:
procedure_part:
/* no procedure definitions */ {}
| procedure_definitions { std::swap($$, $1); }
assign_statement: designator_expression ASSIGNMENT expression
assign_statement: designator_expression ":=" expression
{
$$ = new elna::boot::assign_statement(elna::boot::make_position(@1), $1, $3);
}
call_expression: IDENTIFIER actual_parameter_list
call_expression: designator_expression actual_parameter_list
{
$$ = new elna::boot::call_expression(elna::boot::make_position(@1), $1);
std::swap($$->arguments(), $2);
std::swap($$->arguments, $2);
}
cast_expression: CAST LEFT_PAREN expression COLON type_expression RIGHT_PAREN
cast_expression: "cast" "(" expression ":" type_expression ")"
{
$$ = new elna::boot::cast_expression(elna::boot::make_position(@1), $5, $3);
}
elsif_do_statements:
ELSIF expression DO optional_statements elsif_do_statements
"elsif" expression "do" optional_statements elsif_do_statements
{
elna::boot::conditional_statements *branch = new elna::boot::conditional_statements($2);
std::swap(branch->statements, $4);
@ -219,7 +243,7 @@ elsif_do_statements:
$$.emplace($$.begin(), branch);
}
| {}
while_statement: WHILE expression DO optional_statements elsif_do_statements END_BLOCK
while_statement: "while" expression "do" optional_statements elsif_do_statements "end"
{
auto body = new elna::boot::conditional_statements($2);
std::swap($4, body->statements);
@ -227,7 +251,7 @@ while_statement: WHILE expression DO optional_statements elsif_do_statements END
std::swap($5, $$->branches);
}
elsif_then_statements:
ELSIF expression THEN optional_statements elsif_then_statements
"elsif" expression "then" optional_statements elsif_then_statements
{
elna::boot::conditional_statements *branch = new elna::boot::conditional_statements($2);
std::swap(branch->statements, $4);
@ -236,14 +260,14 @@ elsif_then_statements:
}
| {}
if_statement:
IF expression THEN optional_statements elsif_then_statements END_BLOCK
"if" expression "then" optional_statements elsif_then_statements "end"
{
auto then = new elna::boot::conditional_statements($2);
std::swap($4, then->statements);
$$ = new elna::boot::if_statement(elna::boot::make_position(@1), then);
std::swap($5, $$->branches);
}
| IF expression THEN optional_statements elsif_then_statements ELSE optional_statements END_BLOCK
| "if" expression "then" optional_statements elsif_then_statements "else" optional_statements "end"
{
auto then = new elna::boot::conditional_statements($2);
std::swap($4, then->statements);
@ -251,11 +275,11 @@ 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
defer_statement: DEFER optional_statements "end"
{
$$ = new elna::boot::defer_statement(elna::boot::make_position(@1));
std::swap($2, $$->statements);
@ -281,7 +305,7 @@ literal:
{
$$ = new elna::boot::number_literal<unsigned char>(elna::boot::make_position(@1), $1.at(0));
}
| NIL
| "nil"
{
$$ = new elna::boot::number_literal<std::nullptr_t>(elna::boot::make_position(@1), nullptr);
}
@ -292,129 +316,126 @@ literal:
operand:
literal { $$ = $1; }
| designator_expression { $$ = $1; }
| LEFT_PAREN type_expression RIGHT_PAREN
{
$$ = new elna::boot::type_expression(elna::boot::make_position(@1), $2);
}
| "(" type_expression ")" { $$ = new elna::boot::type_expression(elna::boot::make_position(@1), $2); }
| cast_expression { $$ = $1; }
| call_expression { $$ = $1; }
| LEFT_PAREN expression RIGHT_PAREN { $$ = $2; }
| "(" expression ")" { $$ = $2; }
expression:
unary { $$ = $1; }
| expression MULTIPLICATION expression
| expression "*" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::multiplication);
}
| expression DIVISION expression
| expression "/" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::division);
}
| expression REMAINDER expression
| expression "%" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::remainder);
}
| expression PLUS expression
| expression "+" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::sum);
}
| expression MINUS expression
| expression "-" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::subtraction);
}
| expression EQUALS expression
| expression "=" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::equals);
}
| expression NOT_EQUAL expression
| expression "<>" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::not_equals);
}
| expression LESS_THAN expression
| expression "<" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::less);
}
| expression GREATER_THAN expression
| expression ">" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::greater);
}
| expression LESS_EQUAL expression
| expression "<=" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::less_equal);
}
| expression GREATER_EQUAL expression
| expression ">=" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::greater_equal);
}
| expression AND expression
| expression "and" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::conjunction);
}
| expression OR expression
| expression "or" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::disjunction);
}
| expression XOR expression
| expression "xor" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::exclusive_disjunction);
}
| expression SHIFT_LEFT expression
| expression "<<" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::shift_left);
}
| expression SHIFT_RIGHT expression
| expression ">>" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::shift_right);
}
unary:
AT operand
"@" operand
{
$$ = new elna::boot::unary_expression(elna::boot::make_position(@1), $2,
elna::boot::unary_operator::reference);
}
| NOT operand
| "not" operand
{
$$ = new elna::boot::unary_expression(elna::boot::make_position(@1), $2,
elna::boot::unary_operator::negation);
}
| MINUS operand
| "-" operand
{
$$ = new elna::boot::unary_expression(elna::boot::make_position(@1), $2,
elna::boot::unary_operator::minus);
}
| operand { $$ = $1; }
expressions:
expression COMMA expressions
expression "," expressions
{
std::swap($$, $3);
$$.emplace($$.cbegin(), $1);
}
| expression { $$.emplace_back(std::move($1)); }
designator_expression:
operand LEFT_SQUARE expression RIGHT_SQUARE
operand "[" expression "]"
{
$$ = new elna::boot::array_access_expression(elna::boot::make_position(@2), $1, $3);
}
| operand DOT IDENTIFIER
| operand "." IDENTIFIER
{
$$ = new elna::boot::field_access_expression(elna::boot::make_position(@2), $1, $3);
}
| operand HAT
| operand "^"
{
$$ = new elna::boot::dereference_expression(elna::boot::make_position(@1), $1);
}
@ -443,7 +464,7 @@ optional_statements:
statements { std::swap($$, $1); }
| /* no statements */ {}
field_declaration:
IDENTIFIER COLON type_expression { $$ = std::make_pair($1, $3); }
IDENTIFIER ":" type_expression { $$ = std::make_pair($1, $3); }
fields:
field_declaration fields
{
@ -455,23 +476,23 @@ optional_fields:
fields { std::swap($$, $1); }
| /* no fields */ {}
type_expression:
LEFT_SQUARE INTEGER RIGHT_SQUARE type_expression
"[" INTEGER "]" type_expression
{
$$ = std::make_shared<elna::boot::array_type>(elna::boot::make_position(@1), $4, $2);
}
| HAT type_expression
| "^" type_expression
{
$$ = std::make_shared<elna::boot::pointer_type>(elna::boot::make_position(@1), $2);
}
| RECORD optional_fields END_BLOCK
| "record" optional_fields "end"
{
$$ = std::make_shared<elna::boot::record_type>(elna::boot::make_position(@1), std::move($2));
}
| UNION fields END_BLOCK
| "union" fields "end"
{
$$ = std::make_shared<elna::boot::union_type>(elna::boot::make_position(@1), std::move($2));
}
| PROCEDURE procedure_heading
| "proc" procedure_heading
{
$$ = $2;
}
@ -479,7 +500,7 @@ type_expression:
{
$$ = std::make_shared<elna::boot::basic_type>(elna::boot::make_position(@1), $1);
}
variable_declaration: identifier_definitions COLON type_expression
variable_declaration: identifier_definitions ":" type_expression
{
for (const std::pair<std::string, bool>& identifier : $1)
{
@ -498,8 +519,8 @@ variable_declarations:
| variable_declaration { std::swap($$, $1); }
variable_part:
/* no variable declarations */ {}
| VAR variable_declarations { std::swap($$, $2); }
constant_definition: identifier_definition EQUALS literal
| "var" variable_declarations { std::swap($$, $2); }
constant_definition: identifier_definition "=" literal
{
$$ = new elna::boot::constant_definition(elna::boot::make_position(@1), $1.first, $1.second, $3);
}
@ -512,9 +533,9 @@ constant_definitions:
| constant_definition { $$.emplace_back(std::move($1)); }
constant_part:
/* no constant definitions */ {}
| CONST {}
| CONST constant_definitions { std::swap($$, $2); }
type_definition: identifier_definition EQUALS type_expression
| "const" {}
| "const" constant_definitions { std::swap($$, $2); }
type_definition: identifier_definition "=" type_expression
{
$$ = new elna::boot::type_definition(elna::boot::make_position(@1), $1.first, $1.second, $3);
}
@ -527,25 +548,25 @@ type_definitions:
| type_definition { $$.emplace_back(std::move($1)); }
type_part:
/* no type definitions */ {}
| TYPE {}
| TYPE type_definitions { std::swap($$, $2); }
formal_parameter: IDENTIFIER COLON type_expression
| "type" {}
| "type" type_definitions { std::swap($$, $2); }
formal_parameter: IDENTIFIER ":" type_expression
{
$$ = new elna::boot::variable_declaration(elna::boot::make_position(@2), $1, $3);
}
formal_parameters:
formal_parameter COMMA formal_parameters
formal_parameter "," formal_parameters
{
std::swap($$, $3);
$$.emplace($$.cbegin(), $1);
}
| formal_parameter { $$.emplace_back(std::move($1)); }
formal_parameter_list:
LEFT_PAREN RIGHT_PAREN {}
| LEFT_PAREN formal_parameters RIGHT_PAREN { std::swap($$, $2); }
"(" ")" {}
| "(" formal_parameters ")" { std::swap($$, $2); }
actual_parameter_list:
LEFT_PAREN RIGHT_PAREN {}
| LEFT_PAREN expressions RIGHT_PAREN { std::swap($$, $2); }
"(" ")" {}
| "(" expressions ")" { std::swap($$, $2); }
%%
void yy::parser::error(const location_type& loc, const std::string& message)