Don't append return to void procedures
This commit is contained in:
parent
b45b00a3f6
commit
3bd4c3af6f
20
example.elna
20
example.elna
@ -79,17 +79,30 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
proc test_if();
|
proc test_if();
|
||||||
var y: Bool;
|
var x: Bool, y: Bool;
|
||||||
begin
|
begin
|
||||||
|
x := true;
|
||||||
y := false;
|
y := false;
|
||||||
|
|
||||||
writei("");
|
writei("");
|
||||||
if y then
|
if x and y then
|
||||||
writei("Test if: True")
|
writei("Test if: True")
|
||||||
else
|
else
|
||||||
writei("Test if: False")
|
writei("Test if: False")
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
proc test_not();
|
||||||
|
var x: Bool;
|
||||||
|
begin
|
||||||
|
x := false;
|
||||||
|
|
||||||
|
writei("");
|
||||||
|
if not x then
|
||||||
|
writei("Test not true.")
|
||||||
|
else
|
||||||
|
writei("Test not false")
|
||||||
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
test_primitive();
|
test_primitive();
|
||||||
test_string();
|
test_string();
|
||||||
@ -97,5 +110,6 @@ begin
|
|||||||
test_pointer();
|
test_pointer();
|
||||||
test_record();
|
test_record();
|
||||||
test_const();
|
test_const();
|
||||||
test_if()
|
test_if();
|
||||||
|
test_not()
|
||||||
end.
|
end.
|
||||||
|
@ -160,16 +160,13 @@ namespace gcc
|
|||||||
|
|
||||||
this->symbol_map->enter(definition->identifier(), source::make_info(this->main_fndecl));
|
this->symbol_map->enter(definition->identifier(), source::make_info(this->main_fndecl));
|
||||||
|
|
||||||
tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, integer_type_node);
|
tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL,
|
||||||
|
NULL_TREE, TREE_TYPE(TREE_TYPE(this->main_fndecl)));
|
||||||
DECL_CONTEXT(resdecl) = this->main_fndecl;
|
DECL_CONTEXT(resdecl) = this->main_fndecl;
|
||||||
DECL_RESULT(this->main_fndecl) = resdecl;
|
DECL_RESULT(this->main_fndecl) = resdecl;
|
||||||
tree set_result = build2(INIT_EXPR, void_type_node, DECL_RESULT(main_fndecl),
|
|
||||||
build_int_cst_type(integer_type_node, 0));
|
|
||||||
tree return_stmt = build1(RETURN_EXPR, void_type_node, set_result);
|
|
||||||
|
|
||||||
enter_scope();
|
enter_scope();
|
||||||
definition->body().accept(this);
|
definition->body().accept(this);
|
||||||
append_to_statement_list(return_stmt, &this->current_statements);
|
|
||||||
|
|
||||||
tree_symbol_mapping mapping = leave_scope();
|
tree_symbol_mapping mapping = leave_scope();
|
||||||
|
|
||||||
@ -240,6 +237,28 @@ namespace gcc
|
|||||||
this->current_expression = build_string_literal(string->string().size() + 1, string->string().c_str());
|
this->current_expression = build_string_literal(string->string().size() + 1, string->string().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void generic_visitor::build_binarary_operation(bool condition, source::binary_expression *expression,
|
||||||
|
tree_code operator_code, tree left, tree right, tree target_type)
|
||||||
|
{
|
||||||
|
auto expression_location = get_location(&expression->position());
|
||||||
|
auto left_type = TREE_TYPE(left);
|
||||||
|
auto right_type = TREE_TYPE(right);
|
||||||
|
|
||||||
|
if (condition)
|
||||||
|
{
|
||||||
|
this->current_expression = build2_loc(expression_location,
|
||||||
|
operator_code, target_type, left, right);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error_at(expression_location,
|
||||||
|
"invalid operands of type %s and %s for operator %s",
|
||||||
|
print_type(left_type), print_type(right_type),
|
||||||
|
elna::source::print_binary_operator(expression->operation()));
|
||||||
|
this->current_expression = error_mark_node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void generic_visitor::visit(source::binary_expression *expression)
|
void generic_visitor::visit(source::binary_expression *expression)
|
||||||
{
|
{
|
||||||
expression->lhs().accept(this);
|
expression->lhs().accept(this);
|
||||||
@ -281,31 +300,6 @@ namespace gcc
|
|||||||
operator_code = MULT_EXPR;
|
operator_code = MULT_EXPR;
|
||||||
target_type = left_type;
|
target_type = left_type;
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (operator_code != ERROR_MARK) // An arithmetic operation.
|
|
||||||
{
|
|
||||||
if (target_type != integer_type_node && target_type != double_type_node)
|
|
||||||
{
|
|
||||||
error_at(expression_location,
|
|
||||||
"invalid operands of type %s and %s for operator %s",
|
|
||||||
print_type(left_type), print_type(right_type),
|
|
||||||
elna::source::print_binary_operator(expression->operation()));
|
|
||||||
this->current_expression = error_mark_node;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (expression->operation())
|
|
||||||
{
|
|
||||||
case source::binary_operator::equals:
|
|
||||||
operator_code = EQ_EXPR;
|
|
||||||
target_type = boolean_type_node;
|
|
||||||
break;
|
|
||||||
case source::binary_operator::not_equals:
|
|
||||||
operator_code = NE_EXPR;
|
|
||||||
target_type = boolean_type_node;
|
|
||||||
break;
|
|
||||||
case source::binary_operator::less:
|
case source::binary_operator::less:
|
||||||
operator_code = LT_EXPR;
|
operator_code = LT_EXPR;
|
||||||
target_type = boolean_type_node;
|
target_type = boolean_type_node;
|
||||||
@ -325,6 +319,44 @@ namespace gcc
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (operator_code != ERROR_MARK) // An arithmetic operation.
|
||||||
|
{
|
||||||
|
build_binarary_operation(left_type == integer_type_node || left_type == double_type_node,
|
||||||
|
expression, operator_code, left, right, target_type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (expression->operation())
|
||||||
|
{
|
||||||
|
case source::binary_operator::conjunction:
|
||||||
|
operator_code = TRUTH_ANDIF_EXPR;
|
||||||
|
target_type = boolean_type_node;
|
||||||
|
break;
|
||||||
|
case source::binary_operator::disjunction:
|
||||||
|
operator_code = TRUTH_ORIF_EXPR;
|
||||||
|
target_type = boolean_type_node;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (operator_code != ERROR_MARK) // A logical operation.
|
||||||
|
{
|
||||||
|
build_binarary_operation(left_type == boolean_type_node,
|
||||||
|
expression, operator_code, left, right, target_type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (expression->operation())
|
||||||
|
{
|
||||||
|
case source::binary_operator::equals:
|
||||||
|
operator_code = EQ_EXPR;
|
||||||
|
target_type = boolean_type_node;
|
||||||
|
break;
|
||||||
|
case source::binary_operator::not_equals:
|
||||||
|
operator_code = NE_EXPR;
|
||||||
|
target_type = boolean_type_node;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
gcc_assert(operator_code != ERROR_MARK);
|
gcc_assert(operator_code != ERROR_MARK);
|
||||||
gcc_assert(target_type != error_mark_node);
|
gcc_assert(target_type != error_mark_node);
|
||||||
|
|
||||||
@ -334,15 +366,19 @@ namespace gcc
|
|||||||
|
|
||||||
void generic_visitor::visit(source::unary_expression *expression)
|
void generic_visitor::visit(source::unary_expression *expression)
|
||||||
{
|
{
|
||||||
|
expression->operand().accept(this);
|
||||||
|
|
||||||
switch (expression->operation())
|
switch (expression->operation())
|
||||||
{
|
{
|
||||||
case source::unary_operator::reference:
|
case source::unary_operator::reference:
|
||||||
expression->operand().accept(this);
|
|
||||||
|
|
||||||
this->current_expression = build1_loc(get_location(&expression->position()), ADDR_EXPR,
|
this->current_expression = build1_loc(get_location(&expression->position()), ADDR_EXPR,
|
||||||
build_pointer_type_for_mode(TREE_TYPE(this->current_expression), VOIDmode, true),
|
build_pointer_type_for_mode(TREE_TYPE(this->current_expression), VOIDmode, true),
|
||||||
this->current_expression);
|
this->current_expression);
|
||||||
break;
|
break;
|
||||||
|
case source::unary_operator::negation:
|
||||||
|
this->current_expression = build1_loc(get_location(&expression->position()), TRUTH_NOT_EXPR,
|
||||||
|
boolean_type_node, this->current_expression);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -674,6 +710,8 @@ namespace gcc
|
|||||||
|
|
||||||
if (statement->alternative() != nullptr)
|
if (statement->alternative() != nullptr)
|
||||||
{
|
{
|
||||||
|
append_to_statement_list(goto_endif, &this->current_statements);
|
||||||
|
|
||||||
auto else_label_expr = build1(LABEL_EXPR, void_type_node, else_label_decl);
|
auto else_label_expr = build1(LABEL_EXPR, void_type_node, else_label_decl);
|
||||||
append_to_statement_list(else_label_expr, &this->current_statements);
|
append_to_statement_list(else_label_expr, &this->current_statements);
|
||||||
|
|
||||||
|
@ -31,6 +31,9 @@ namespace gcc
|
|||||||
void enter_scope();
|
void enter_scope();
|
||||||
tree_symbol_mapping leave_scope();
|
tree_symbol_mapping leave_scope();
|
||||||
|
|
||||||
|
void build_binarary_operation(bool condition, source::binary_expression *expression,
|
||||||
|
tree_code operator_code, tree left, tree right, tree target_type);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
generic_visitor();
|
generic_visitor();
|
||||||
|
|
||||||
|
@ -24,12 +24,15 @@ namespace source
|
|||||||
less,
|
less,
|
||||||
greater,
|
greater,
|
||||||
less_equal,
|
less_equal,
|
||||||
greater_equal
|
greater_equal,
|
||||||
|
disjunction,
|
||||||
|
conjunction
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class unary_operator
|
enum class unary_operator
|
||||||
{
|
{
|
||||||
reference
|
reference,
|
||||||
|
negation
|
||||||
};
|
};
|
||||||
|
|
||||||
class variable_declaration;
|
class variable_declaration;
|
||||||
|
@ -672,6 +672,12 @@ namespace source
|
|||||||
case 'g':
|
case 'g':
|
||||||
this->m_operator = binary_operator::greater_equal;
|
this->m_operator = binary_operator::greater_equal;
|
||||||
break;
|
break;
|
||||||
|
case 'o':
|
||||||
|
this->m_operator = binary_operator::disjunction;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
this->m_operator = binary_operator::conjunction;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
@ -712,6 +718,9 @@ namespace source
|
|||||||
case '@':
|
case '@':
|
||||||
this->m_operator = unary_operator::reference;
|
this->m_operator = unary_operator::reference;
|
||||||
break;
|
break;
|
||||||
|
case '!':
|
||||||
|
this->m_operator = unary_operator::negation;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
@ -923,6 +932,10 @@ namespace source
|
|||||||
return ">";
|
return ">";
|
||||||
case binary_operator::greater_equal:
|
case binary_operator::greater_equal:
|
||||||
return ">=";
|
return ">=";
|
||||||
|
case binary_operator::conjunction:
|
||||||
|
return "and";
|
||||||
|
case binary_operator::disjunction:
|
||||||
|
return "or";
|
||||||
}
|
}
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
};
|
};
|
||||||
|
@ -79,6 +79,15 @@ true {
|
|||||||
false {
|
false {
|
||||||
return yy::parser::make_BOOLEAN(false, this->location);
|
return yy::parser::make_BOOLEAN(false, this->location);
|
||||||
}
|
}
|
||||||
|
and {
|
||||||
|
return yy::parser::make_AND(this->location);
|
||||||
|
}
|
||||||
|
or {
|
||||||
|
return yy::parser::make_OR(this->location);
|
||||||
|
}
|
||||||
|
not {
|
||||||
|
return yy::parser::make_NOT(this->location);
|
||||||
|
}
|
||||||
[A-Za-z_][A-Za-z0-9_]* {
|
[A-Za-z_][A-Za-z0-9_]* {
|
||||||
return yy::parser::make_IDENTIFIER(yytext, this->location);
|
return yy::parser::make_IDENTIFIER(yytext, this->location);
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,7 @@
|
|||||||
%token CONST VAR PROCEDURE ARRAY OF TYPE RECORD
|
%token CONST VAR PROCEDURE ARRAY OF TYPE RECORD
|
||||||
%token BEGIN_BLOCK END_BLOCK
|
%token BEGIN_BLOCK END_BLOCK
|
||||||
%token LEFT_PAREN RIGHT_PAREN LEFT_SQUARE RIGHT_SQUARE SEMICOLON DOT COMMA
|
%token LEFT_PAREN RIGHT_PAREN LEFT_SQUARE RIGHT_SQUARE SEMICOLON DOT COMMA
|
||||||
|
%token AND OR NOT
|
||||||
%token GREATER_EQUAL LESS_EQUAL LESS_THAN GREATER_THAN NOT_EQUAL EQUALS
|
%token GREATER_EQUAL LESS_EQUAL LESS_THAN GREATER_THAN NOT_EQUAL EQUALS
|
||||||
%token PLUS MINUS MULTIPLICATION DIVISION
|
%token PLUS MINUS MULTIPLICATION DIVISION
|
||||||
%token ASSIGNMENT COLON HAT AT
|
%token ASSIGNMENT COLON HAT AT
|
||||||
@ -84,7 +85,7 @@
|
|||||||
%type <std::vector<elna::source::variable_declaration *>> variable_declarations variable_part
|
%type <std::vector<elna::source::variable_declaration *>> variable_declarations variable_part
|
||||||
formal_parameter_list;
|
formal_parameter_list;
|
||||||
%type <elna::source::type_expression *> type_expression;
|
%type <elna::source::type_expression *> type_expression;
|
||||||
%type <elna::source::expression *> expression pointer summand factor comparand;
|
%type <elna::source::expression *> expression pointer summand factor comparand logical_operand;
|
||||||
%type <std::vector<elna::source::expression *>> expressions actual_parameter_list;
|
%type <std::vector<elna::source::expression *>> expressions actual_parameter_list;
|
||||||
%type <elna::source::designator_expression *> designator_expression;
|
%type <elna::source::designator_expression *> designator_expression;
|
||||||
%type <elna::source::compound_statement *> compound_statement;
|
%type <elna::source::compound_statement *> compound_statement;
|
||||||
@ -239,6 +240,10 @@ factor:
|
|||||||
{
|
{
|
||||||
$$ = new elna::source::unary_expression(elna::source::make_position(@1), $2, '@');
|
$$ = new elna::source::unary_expression(elna::source::make_position(@1), $2, '@');
|
||||||
}
|
}
|
||||||
|
| NOT pointer
|
||||||
|
{
|
||||||
|
$$ = new elna::source::unary_expression(elna::source::make_position(@1), $2, '!');
|
||||||
|
}
|
||||||
| pointer { $$ = $1; }
|
| pointer { $$ = $1; }
|
||||||
comparand:
|
comparand:
|
||||||
summand PLUS summand
|
summand PLUS summand
|
||||||
@ -250,7 +255,7 @@ comparand:
|
|||||||
$$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '-');
|
$$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '-');
|
||||||
}
|
}
|
||||||
| summand { $$ = std::move($1); }
|
| summand { $$ = std::move($1); }
|
||||||
expression:
|
logical_operand:
|
||||||
comparand EQUALS comparand
|
comparand EQUALS comparand
|
||||||
{
|
{
|
||||||
$$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '=');
|
$$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '=');
|
||||||
@ -265,20 +270,27 @@ expression:
|
|||||||
}
|
}
|
||||||
| comparand GREATER_THAN comparand
|
| comparand GREATER_THAN comparand
|
||||||
{
|
{
|
||||||
$$ = new elna::source::binary_expression(elna::source::make_position(@1),
|
$$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '>');
|
||||||
$1, $3, '>');
|
|
||||||
}
|
}
|
||||||
| comparand LESS_EQUAL comparand
|
| comparand LESS_EQUAL comparand
|
||||||
{
|
{
|
||||||
$$ = new elna::source::binary_expression(elna::source::make_position(@1),
|
$$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '<');
|
||||||
$1, $3, '<');
|
|
||||||
}
|
}
|
||||||
| comparand GREATER_EQUAL comparand
|
| comparand GREATER_EQUAL comparand
|
||||||
{
|
{
|
||||||
$$ = new elna::source::binary_expression(elna::source::make_position(@1),
|
$$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '>');
|
||||||
$1, $3, '>');
|
|
||||||
}
|
}
|
||||||
| comparand { $$ = std::move($1); }
|
| comparand { $$ = $1; }
|
||||||
|
expression:
|
||||||
|
logical_operand AND logical_operand
|
||||||
|
{
|
||||||
|
$$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, 'a');
|
||||||
|
}
|
||||||
|
| logical_operand OR logical_operand
|
||||||
|
{
|
||||||
|
$$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, 'o');
|
||||||
|
}
|
||||||
|
| logical_operand { $$ = $1; }
|
||||||
expressions:
|
expressions:
|
||||||
expression COMMA expressions
|
expression COMMA expressions
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user