Implement procedure pointers
This commit is contained in:
parent
18857e1a88
commit
85b6843ecf
18
boot/ast.cc
18
boot/ast.cc
@ -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,
|
||||
|
191
boot/parser.yy
191
boot/parser.yy
@ -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)
|
||||
|
@ -80,9 +80,18 @@ namespace gcc
|
||||
}
|
||||
else if (is_pointer_type(type))
|
||||
{
|
||||
return std::string("^" + print_type(TREE_TYPE(type)));
|
||||
tree pointer_target_type = TREE_TYPE(type);
|
||||
|
||||
if (TREE_CODE(pointer_target_type) == FUNCTION_TYPE)
|
||||
{
|
||||
return print_type(pointer_target_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::string("^" + print_type(pointer_target_type));
|
||||
}
|
||||
}
|
||||
else if (is_procedure_type(type))
|
||||
else if (TREE_CODE(type) == FUNCTION_TYPE)
|
||||
{
|
||||
std::string output = "proc(";
|
||||
tree parameter_type = TYPE_ARG_TYPES(type);
|
||||
|
@ -44,10 +44,12 @@ namespace gcc
|
||||
}
|
||||
|
||||
void generic_visitor::build_procedure_call(location_t call_location,
|
||||
tree symbol, const std::vector<boot::expression *>& arguments)
|
||||
tree procedure_address, const std::vector<boot::expression *>& arguments)
|
||||
{
|
||||
vec<tree, va_gc> *argument_trees = nullptr;
|
||||
tree current_parameter = TYPE_ARG_TYPES(TREE_TYPE(symbol));
|
||||
tree symbol_type = TREE_TYPE(TREE_TYPE(procedure_address));
|
||||
|
||||
tree current_parameter = TYPE_ARG_TYPES(symbol_type);
|
||||
|
||||
vec_alloc(argument_trees, arguments.size());
|
||||
for (boot::expression *const argument : arguments)
|
||||
@ -56,11 +58,12 @@ namespace gcc
|
||||
if (is_void_type(TREE_VALUE(current_parameter)))
|
||||
{
|
||||
error_at(argument_location, "too many arguments, expected %i, got %lu",
|
||||
list_length(TYPE_ARG_TYPES(TREE_TYPE(symbol))) - 1, arguments.size());
|
||||
list_length(TYPE_ARG_TYPES(symbol_type)) - 1, arguments.size());
|
||||
this->current_expression = error_mark_node;
|
||||
break;
|
||||
}
|
||||
argument->accept(this);
|
||||
this->current_expression = prepare_rvalue(this->current_expression);
|
||||
if (!is_assignable_from(TREE_VALUE(current_parameter), this->current_expression))
|
||||
{
|
||||
error_at(argument_location,
|
||||
@ -72,15 +75,16 @@ namespace gcc
|
||||
current_parameter = TREE_CHAIN(current_parameter);
|
||||
argument_trees->quick_push(this->current_expression);
|
||||
}
|
||||
tree stmt = build_call_expr_loc_vec(call_location, symbol, argument_trees);
|
||||
tree stmt = fold_build_call_array_loc(call_location, TREE_TYPE(symbol_type),
|
||||
procedure_address, vec_safe_length(argument_trees), vec_safe_address(argument_trees));
|
||||
|
||||
if (!is_void_type(TREE_VALUE(current_parameter)))
|
||||
{
|
||||
error_at(call_location, "too few arguments, expected %i, got %lu",
|
||||
list_length(TYPE_ARG_TYPES(TREE_TYPE(symbol))) - 1, arguments.size());
|
||||
list_length(TYPE_ARG_TYPES(symbol_type)) - 1, arguments.size());
|
||||
this->current_expression = error_mark_node;
|
||||
}
|
||||
else if (TREE_TYPE(TREE_TYPE(symbol)) == void_type_node)
|
||||
else if (TREE_TYPE(symbol_type) == void_type_node)
|
||||
{
|
||||
append_statement(stmt);
|
||||
this->current_expression = NULL_TREE;
|
||||
@ -134,27 +138,31 @@ namespace gcc
|
||||
|
||||
void generic_visitor::visit(boot::call_expression *expression)
|
||||
{
|
||||
tree symbol = this->lookup(expression->name());
|
||||
location_t call_location = get_location(&expression->position());
|
||||
expression->callable().accept(this);
|
||||
|
||||
if (symbol == NULL_TREE)
|
||||
tree expression_type = TYPE_P(this->current_expression)
|
||||
? this->current_expression
|
||||
: TREE_TYPE(this->current_expression);
|
||||
|
||||
if (TYPE_P(this->current_expression) && TREE_CODE(expression_type) == RECORD_TYPE)
|
||||
{
|
||||
error_at(call_location, "procedure '%s' not declared",
|
||||
expression->name().c_str());
|
||||
this->current_expression = error_mark_node;
|
||||
build_record_call(call_location, this->current_expression, expression->arguments);
|
||||
}
|
||||
else if (DECL_P(symbol) && is_procedure_type(TREE_TYPE(symbol)))
|
||||
else if (TREE_CODE(expression_type) == FUNCTION_TYPE)
|
||||
{
|
||||
build_procedure_call(call_location, symbol, expression->arguments());
|
||||
this->current_expression = build1(ADDR_EXPR,
|
||||
build_pointer_type_for_mode(expression_type, VOIDmode, true), this->current_expression);
|
||||
build_procedure_call(call_location, this->current_expression, expression->arguments);
|
||||
}
|
||||
else if (TYPE_P(symbol) && TREE_CODE(symbol) == RECORD_TYPE)
|
||||
else if (is_pointer_type(expression_type) && TREE_CODE(TREE_TYPE(expression_type)) == FUNCTION_TYPE)
|
||||
{
|
||||
build_record_call(call_location, symbol, expression->arguments());
|
||||
build_procedure_call(call_location, this->current_expression, expression->arguments);
|
||||
}
|
||||
else
|
||||
{
|
||||
error_at(call_location, "'%s' cannot be called, it is neither a procedure nor record",
|
||||
print_type(TYPE_P(symbol) ? symbol : TREE_TYPE(symbol)).c_str());
|
||||
print_type(expression_type).c_str());
|
||||
this->current_expression = error_mark_node;
|
||||
}
|
||||
}
|
||||
@ -242,7 +250,7 @@ namespace gcc
|
||||
|
||||
void generic_visitor::visit(boot::procedure_definition *definition)
|
||||
{
|
||||
tree declaration_type = build_type(definition->heading());
|
||||
tree declaration_type = build_procedure_type(definition->heading());
|
||||
tree fndecl = build_fn_decl(definition->identifier.c_str(), declaration_type);
|
||||
this->symbol_map->enter(definition->identifier, fndecl);
|
||||
|
||||
@ -281,6 +289,7 @@ namespace gcc
|
||||
}
|
||||
DECL_ARGUMENTS(fndecl) = argument_chain;
|
||||
TREE_PUBLIC(fndecl) = definition->exported;
|
||||
TREE_ADDRESSABLE(fndecl) = 1;
|
||||
|
||||
if (definition->body != nullptr)
|
||||
{
|
||||
@ -647,6 +656,7 @@ namespace gcc
|
||||
switch (expression->operation())
|
||||
{
|
||||
case boot::unary_operator::reference:
|
||||
this->current_expression = prepare_rvalue(this->current_expression);
|
||||
TREE_ADDRESSABLE(this->current_expression) = 1;
|
||||
this->current_expression = build_fold_addr_expr_with_type_loc(location,
|
||||
this->current_expression,
|
||||
@ -739,6 +749,21 @@ namespace gcc
|
||||
}
|
||||
}
|
||||
|
||||
tree generic_visitor::build_procedure_type(boot::procedure_type& type)
|
||||
{
|
||||
std::vector<tree> parameter_types(type.parameters.size());
|
||||
|
||||
for (std::size_t i = 0; i < type.parameters.size(); ++i)
|
||||
{
|
||||
parameter_types[i] = build_type(type.parameters.at(i)->variable_type());
|
||||
}
|
||||
tree return_type = type.return_type == nullptr
|
||||
? void_type_node
|
||||
: build_type(*type.return_type);
|
||||
|
||||
return build_function_type_array(return_type, type.parameters.size(), parameter_types.data());
|
||||
}
|
||||
|
||||
tree generic_visitor::build_type(boot::top_type& type)
|
||||
{
|
||||
if (std::shared_ptr<boot::basic_type> basic_type = type.is_basic())
|
||||
@ -834,18 +859,8 @@ namespace gcc
|
||||
}
|
||||
else if (std::shared_ptr<boot::procedure_type> procedure_type = type.is_procedure())
|
||||
{
|
||||
std::vector<tree> parameter_types(procedure_type->parameters.size());
|
||||
|
||||
for (std::size_t i = 0; i < procedure_type->parameters.size(); ++i)
|
||||
{
|
||||
parameter_types[i] = build_type(procedure_type->parameters.at(i)->variable_type());
|
||||
}
|
||||
tree return_type = procedure_type->return_type == nullptr
|
||||
? void_type_node
|
||||
: build_type(*procedure_type->return_type);
|
||||
|
||||
return build_function_type_array(return_type,
|
||||
procedure_type->parameters.size(), parameter_types.data());
|
||||
tree procedure_type_node = build_procedure_type(*procedure_type);
|
||||
return build_pointer_type_for_mode(procedure_type_node, VOIDmode, true);
|
||||
}
|
||||
return NULL_TREE;
|
||||
}
|
||||
@ -893,14 +908,10 @@ namespace gcc
|
||||
if (symbol == NULL_TREE)
|
||||
{
|
||||
error_at(get_location(&expression->position()),
|
||||
"variable '%s' not declared in the current scope",
|
||||
"symbol '%s' not declared in the current scope",
|
||||
expression->name().c_str());
|
||||
this->current_expression = error_mark_node;
|
||||
}
|
||||
else if (TREE_CODE(symbol) == FUNCTION_DECL)
|
||||
{
|
||||
this->current_expression = build1(ADDR_EXPR, build_pointer_type(TREE_TYPE(symbol)), symbol);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->current_expression = symbol;
|
||||
@ -1029,10 +1040,11 @@ namespace gcc
|
||||
{
|
||||
statement->lvalue().accept(this);
|
||||
|
||||
auto lvalue = this->current_expression;
|
||||
auto statement_location = get_location(&statement->position());
|
||||
tree lvalue = this->current_expression;
|
||||
location_t statement_location = get_location(&statement->position());
|
||||
|
||||
statement->rvalue().accept(this);
|
||||
tree rvalue = prepare_rvalue(this->current_expression);
|
||||
|
||||
if (TREE_CODE(lvalue) == CONST_DECL)
|
||||
{
|
||||
@ -1040,10 +1052,9 @@ namespace gcc
|
||||
statement->lvalue().is_variable()->name().c_str());
|
||||
this->current_expression = error_mark_node;
|
||||
}
|
||||
else if (is_assignable_from(TREE_TYPE(lvalue), this->current_expression))
|
||||
else if (is_assignable_from(TREE_TYPE(lvalue), rvalue))
|
||||
{
|
||||
tree assignment = build2_loc(statement_location, MODIFY_EXPR,
|
||||
void_type_node, lvalue, this->current_expression);
|
||||
tree assignment = build2_loc(statement_location, MODIFY_EXPR, void_type_node, lvalue, rvalue);
|
||||
|
||||
append_statement(assignment);
|
||||
this->current_expression = NULL_TREE;
|
||||
@ -1052,7 +1063,7 @@ namespace gcc
|
||||
{
|
||||
error_at(statement_location,
|
||||
"cannot assign value of type '%s' to variable of type '%s'",
|
||||
print_type(TREE_TYPE(this->current_expression)).c_str(),
|
||||
print_type(TREE_TYPE(rvalue)).c_str(),
|
||||
print_type(TREE_TYPE(lvalue)).c_str());
|
||||
this->current_expression = error_mark_node;
|
||||
}
|
||||
|
@ -51,12 +51,6 @@ namespace gcc
|
||||
return TREE_CODE(type) == ARRAY_TYPE;
|
||||
}
|
||||
|
||||
bool is_procedure_type(tree type)
|
||||
{
|
||||
gcc_assert(TYPE_P(type));
|
||||
return TREE_CODE(type) == FUNCTION_TYPE;
|
||||
}
|
||||
|
||||
bool is_void_type(tree type)
|
||||
{
|
||||
return type == NULL_TREE || type == void_type_node;
|
||||
@ -77,6 +71,18 @@ namespace gcc
|
||||
|| (is_pointer_type(lhs_type) && lhs_type == rhs_type);
|
||||
}
|
||||
|
||||
tree prepare_rvalue(tree rvalue)
|
||||
{
|
||||
if (DECL_P(rvalue) && TREE_CODE(TREE_TYPE(rvalue)) == FUNCTION_TYPE)
|
||||
{
|
||||
return build1(ADDR_EXPR, build_pointer_type_for_mode(TREE_TYPE(rvalue), VOIDmode, true), rvalue);
|
||||
}
|
||||
else
|
||||
{
|
||||
return rvalue;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_assignable_from(tree assignee, tree assignment)
|
||||
{
|
||||
return get_qualified_type(TREE_TYPE(assignment), TYPE_UNQUALIFIED) == assignee
|
||||
|
@ -417,28 +417,6 @@ namespace boot
|
||||
top_type& body();
|
||||
};
|
||||
|
||||
/**
|
||||
* Procedure call expression.
|
||||
*/
|
||||
class call_expression : public expression
|
||||
{
|
||||
std::string m_name;
|
||||
std::vector<expression *> m_arguments;
|
||||
|
||||
public:
|
||||
/**
|
||||
* \param position Source code position.
|
||||
* \param name Callable's name.
|
||||
*/
|
||||
call_expression(const struct position position, const std::string& name);
|
||||
virtual void accept(parser_visitor *visitor) override;
|
||||
|
||||
std::string& name();
|
||||
std::vector<expression *>& arguments();
|
||||
|
||||
virtual ~call_expression() override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast expression.
|
||||
*/
|
||||
@ -589,6 +567,24 @@ namespace boot
|
||||
~dereference_expression() override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Procedure call expression.
|
||||
*/
|
||||
class call_expression : public expression
|
||||
{
|
||||
designator_expression *m_callable;
|
||||
|
||||
public:
|
||||
std::vector<expression *> arguments;
|
||||
|
||||
call_expression(const struct position position, designator_expression *callable);
|
||||
virtual void accept(parser_visitor *visitor) override;
|
||||
|
||||
designator_expression& callable();
|
||||
|
||||
virtual ~call_expression() override;
|
||||
};
|
||||
|
||||
class assign_statement : public statement
|
||||
{
|
||||
designator_expression *m_lvalue;
|
||||
|
@ -40,6 +40,7 @@ namespace gcc
|
||||
std::shared_ptr<symbol_table> symbol_map;
|
||||
|
||||
tree build_label_decl(const char *name, location_t loc);
|
||||
tree build_procedure_type(boot::procedure_type& type);
|
||||
tree build_type(boot::top_type& type);
|
||||
|
||||
void enter_scope();
|
||||
@ -56,7 +57,7 @@ namespace gcc
|
||||
tree build_bit_logic_operation(boot::binary_expression *expression, tree left, tree right);
|
||||
tree build_equality_operation(boot::binary_expression *expression, tree left, tree right);
|
||||
void build_procedure_call(location_t call_location,
|
||||
tree symbol, const std::vector<boot::expression *>& arguments);
|
||||
tree procedure_address, const std::vector<boot::expression *>& arguments);
|
||||
void build_record_call(location_t call_location,
|
||||
tree symbol, const std::vector<boot::expression *>& arguments);
|
||||
|
||||
|
@ -39,7 +39,6 @@ namespace gcc
|
||||
bool is_integral_type(tree type);
|
||||
bool is_numeric_type(tree type);
|
||||
bool is_array_type(tree type);
|
||||
bool is_procedure_type(tree type);
|
||||
bool is_void_type(tree type);
|
||||
|
||||
/**
|
||||
@ -55,6 +54,16 @@ namespace gcc
|
||||
*/
|
||||
bool are_compatible_pointers(tree lhs_type, tree rhs);
|
||||
|
||||
/**
|
||||
* Prepares a value to be bound to a variable or parameter.
|
||||
*
|
||||
* If rvalue is a procedure declaration, builds a procedure pointer.
|
||||
*
|
||||
* \param rvalue Value to be assigned.
|
||||
* \return Processed value.
|
||||
*/
|
||||
tree prepare_rvalue(tree rvalue);
|
||||
|
||||
/**
|
||||
* \param assignee Assignee.
|
||||
* \param assignee Assignment.
|
||||
|
13
source.elna
13
source.elna
@ -891,19 +891,6 @@ begin
|
||||
return 0
|
||||
end
|
||||
|
||||
proc f();
|
||||
begin
|
||||
write_s("In f\n")
|
||||
end
|
||||
|
||||
proc g();
|
||||
var x: ^proc()
|
||||
begin
|
||||
x := cast(f: ^proc())
|
||||
(* x() *)
|
||||
end
|
||||
|
||||
begin
|
||||
g()
|
||||
exit(process(cast(count: Int), cast(parameters: ^^Char)))
|
||||
end.
|
||||
|
Loading…
x
Reference in New Issue
Block a user