diff --git a/boot/ast.cc b/boot/ast.cc index 043de55..8358abb 100644 --- a/boot/ast.cc +++ b/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& 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, diff --git a/boot/parser.yy b/boot/parser.yy index 3a55b97..42ea4f2 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -74,25 +74,49 @@ along with GCC; see the file COPYING3. If not see } %start program; -%token IDENTIFIER "identifier" -%token INTEGER "integer" -%token WORD "word" -%token FLOAT "float" -%token CHARACTER "character" -%token STRING "string" +%token IDENTIFIER +%token INTEGER +%token WORD +%token FLOAT +%token CHARACTER +%token STRING %token 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 literal; %type constant_definition; @@ -126,7 +150,7 @@ along with GCC; see the file COPYING3. If not see %type >> 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::make_position(@1)); std::swap($1, $$->parameters); } - | formal_parameter_list ARROW EXCLAMATION + | formal_parameter_list "->" "!" { $$ = std::make_shared(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::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(elna::boot::make_position(@1), $1.at(0)); } - | NIL + | "nil" { $$ = new elna::boot::number_literal(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::make_position(@1), $4, $2); } - | HAT type_expression + | "^" type_expression { $$ = std::make_shared(elna::boot::make_position(@1), $2); } - | RECORD optional_fields END_BLOCK + | "record" optional_fields "end" { $$ = std::make_shared(elna::boot::make_position(@1), std::move($2)); } - | UNION fields END_BLOCK + | "union" fields "end" { $$ = std::make_shared(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::make_position(@1), $1); } -variable_declaration: identifier_definitions COLON type_expression +variable_declaration: identifier_definitions ":" type_expression { for (const std::pair& 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) diff --git a/gcc/elna-diagnostic.cc b/gcc/elna-diagnostic.cc index 61cb0ff..7e75de0 100644 --- a/gcc/elna-diagnostic.cc +++ b/gcc/elna-diagnostic.cc @@ -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); diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 878dafd..73dcddc 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -44,10 +44,12 @@ namespace gcc } void generic_visitor::build_procedure_call(location_t call_location, - tree symbol, const std::vector& arguments) + tree procedure_address, const std::vector& arguments) { vec *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 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 basic_type = type.is_basic()) @@ -834,18 +859,8 @@ namespace gcc } else if (std::shared_ptr procedure_type = type.is_procedure()) { - std::vector 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; } diff --git a/gcc/elna-tree.cc b/gcc/elna-tree.cc index 149539e..c8262df 100644 --- a/gcc/elna-tree.cc +++ b/gcc/elna-tree.cc @@ -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 diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index 6eed4ab..83f1afb 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -417,28 +417,6 @@ namespace boot top_type& body(); }; - /** - * Procedure call expression. - */ - class call_expression : public expression - { - std::string m_name; - std::vector 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& 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 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; diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index dfd2caa..7fd4115 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -40,6 +40,7 @@ namespace gcc std::shared_ptr 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& arguments); + tree procedure_address, const std::vector& arguments); void build_record_call(location_t call_location, tree symbol, const std::vector& arguments); diff --git a/include/elna/gcc/elna-tree.h b/include/elna/gcc/elna-tree.h index 5274b0b..1f83b05 100644 --- a/include/elna/gcc/elna-tree.h +++ b/include/elna/gcc/elna-tree.h @@ -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. diff --git a/source.elna b/source.elna index ed0b1b2..9225a26 100644 --- a/source.elna +++ b/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.