Implement procedure pointers
This commit is contained in:
		
							
								
								
									
										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 if (is_procedure_type(type))
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                return std::string("^" + print_type(pointer_target_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.
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user