Implement elsif
This commit is contained in:
parent
1f7c1b4cb8
commit
18d8ded239
87
example.elna
87
example.elna
@ -1,5 +1,4 @@
|
|||||||
type
|
type
|
||||||
T = array 5 of Int,
|
|
||||||
TokenValue = union
|
TokenValue = union
|
||||||
intValue: Int;
|
intValue: Int;
|
||||||
stringValue: String
|
stringValue: String
|
||||||
@ -57,63 +56,58 @@ begin
|
|||||||
write(0, @value, 1)
|
write(0, @value, 1)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
proc write_i(value: Int);
|
||||||
|
var
|
||||||
|
digit: Int, n: Int,
|
||||||
|
buffer: array 10 of Char;
|
||||||
|
begin
|
||||||
|
n := 9;
|
||||||
|
buffer[9] := '0';
|
||||||
|
|
||||||
|
while value /= 0 do
|
||||||
|
digit := value % 10;
|
||||||
|
value := value / 10;
|
||||||
|
|
||||||
|
buffer[n] := Char(Int('0') + digit);
|
||||||
|
n := n - 1
|
||||||
|
end;
|
||||||
|
while n < 10 do
|
||||||
|
n := n + 1;
|
||||||
|
write_c(buffer[n])
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc write_u(value: Word);
|
||||||
|
begin
|
||||||
|
write_i(value)
|
||||||
|
end;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- End of standard procedures.
|
-- End of standard procedures.
|
||||||
--
|
--
|
||||||
|
|
||||||
proc test_array();
|
|
||||||
var a: T, x: Int;
|
|
||||||
begin
|
|
||||||
a[0] := 2;
|
|
||||||
a[1] := 5;
|
|
||||||
|
|
||||||
writei("");
|
|
||||||
writei("Test array:");
|
|
||||||
|
|
||||||
x := 0;
|
|
||||||
while x < 2 do
|
|
||||||
writei(a[x]);
|
|
||||||
x := x + 1
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
|
|
||||||
proc test_record();
|
proc test_record();
|
||||||
var r: Token;
|
var r: Token;
|
||||||
begin
|
begin
|
||||||
writei("");
|
write_s("\nTest record:\n");
|
||||||
writei("Test record:");
|
|
||||||
|
|
||||||
r.kind := 4;
|
r.kind := 4;
|
||||||
r.value.intValue := 8;
|
r.value.intValue := 8;
|
||||||
|
|
||||||
writei(r.value.intValue)
|
write_i(r.value.intValue)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
proc test_primitive();
|
proc test_primitive();
|
||||||
var u: Word, z: Float;
|
|
||||||
begin
|
begin
|
||||||
u := 25u;
|
write_s("\nTest primitives:\n");
|
||||||
z := 8.2;
|
write_u(25u);
|
||||||
|
write_c('\n');
|
||||||
|
|
||||||
writei("");
|
write_i(8);
|
||||||
writei("Test primitives:");
|
write_c('\n');
|
||||||
writei(u);
|
|
||||||
writei(z)
|
|
||||||
end;
|
|
||||||
|
|
||||||
proc test_param(d: Int, e: Int);
|
write_b(true);
|
||||||
begin
|
write_c('\n')
|
||||||
writei("");
|
|
||||||
writei("Test param");
|
|
||||||
writei(d);
|
|
||||||
writei(e)
|
|
||||||
end;
|
|
||||||
|
|
||||||
proc test_return_int(): Int;
|
|
||||||
begin
|
|
||||||
writei("");
|
|
||||||
writei("Test return int:");
|
|
||||||
return 5
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
proc read_source(filename: String): pointer to Char;
|
proc read_source(filename: String): pointer to Char;
|
||||||
@ -153,15 +147,10 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
test_primitive();
|
|
||||||
test_array();
|
|
||||||
test_record();
|
|
||||||
test_param(8, 7);
|
|
||||||
writei(test_return_int());
|
|
||||||
write_b(true);
|
|
||||||
write_c('\n');
|
|
||||||
|
|
||||||
compile();
|
compile();
|
||||||
|
|
||||||
|
test_record();
|
||||||
|
test_primitive();
|
||||||
|
|
||||||
exit(0)
|
exit(0)
|
||||||
end.
|
end.
|
||||||
|
@ -24,7 +24,8 @@ namespace gcc
|
|||||||
{
|
{
|
||||||
auto symbol = this->symbol_map->lookup(statement->name());
|
auto symbol = this->symbol_map->lookup(statement->name());
|
||||||
|
|
||||||
if (statement->name() == "writei")
|
if (statement->name() == "Int" || statement->name() == "Word" || statement->name() == "Bool"
|
||||||
|
|| statement->name() == "Float" || statement->name() == "Char")
|
||||||
{
|
{
|
||||||
if (statement->arguments().size() != 1)
|
if (statement->arguments().size() != 1)
|
||||||
{
|
{
|
||||||
@ -35,51 +36,10 @@ namespace gcc
|
|||||||
}
|
}
|
||||||
auto& argument = statement->arguments().at(0);
|
auto& argument = statement->arguments().at(0);
|
||||||
argument->accept(this);
|
argument->accept(this);
|
||||||
auto argument_type = TREE_TYPE(this->current_expression);
|
tree argument_type = TREE_TYPE(this->current_expression);
|
||||||
|
|
||||||
const char *format_number{ nullptr };
|
this->current_expression = build1_loc(get_location(&argument->position()), CONVERT_EXPR,
|
||||||
if (argument_type == integer_type_node)
|
symbol->payload, this->current_expression);
|
||||||
{
|
|
||||||
format_number = "%d\n";
|
|
||||||
}
|
|
||||||
else if (argument_type == unsigned_type_node)
|
|
||||||
{
|
|
||||||
format_number = "%u\n";
|
|
||||||
}
|
|
||||||
else if (argument_type == double_type_node)
|
|
||||||
{
|
|
||||||
format_number = "%f\n";
|
|
||||||
}
|
|
||||||
else if (is_pointer_type(argument_type))
|
|
||||||
{
|
|
||||||
format_number = "%p\n";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
error_at(get_location(&argument->position()),
|
|
||||||
"invalid argument of type %s for procedure %s",
|
|
||||||
print_type(argument_type), statement->name().c_str());
|
|
||||||
this->current_expression = error_mark_node;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
tree args[] = {
|
|
||||||
build_string_literal(strlen(format_number) + 1, format_number),
|
|
||||||
this->current_expression
|
|
||||||
};
|
|
||||||
tree fndecl_type_param[] = {
|
|
||||||
build_pointer_type(build_qualified_type(char_type_node, TYPE_QUAL_CONST)) /* const char* */
|
|
||||||
};
|
|
||||||
tree fndecl_type = build_varargs_function_type_array(integer_type_node, 1, fndecl_type_param);
|
|
||||||
|
|
||||||
tree printf_fn_decl = build_fn_decl("printf", fndecl_type);
|
|
||||||
DECL_EXTERNAL(printf_fn_decl) = 1;
|
|
||||||
|
|
||||||
tree printf_fn = build1(ADDR_EXPR, build_pointer_type(fndecl_type), printf_fn_decl);
|
|
||||||
|
|
||||||
tree stmt = build_call_array(integer_type_node, printf_fn, 2, args);
|
|
||||||
|
|
||||||
append_to_statement_list(stmt, &this->current_statements);
|
|
||||||
this->current_expression = NULL_TREE;
|
|
||||||
}
|
}
|
||||||
else if (symbol)
|
else if (symbol)
|
||||||
{
|
{
|
||||||
@ -733,70 +693,62 @@ namespace gcc
|
|||||||
|
|
||||||
void generic_visitor::visit(source::if_statement *statement)
|
void generic_visitor::visit(source::if_statement *statement)
|
||||||
{
|
{
|
||||||
statement->body().prerequisite().accept(this);
|
tree endif_label_decl = build_label_decl("endif", UNKNOWN_LOCATION);
|
||||||
|
tree goto_endif = build1(GOTO_EXPR, void_type_node, endif_label_decl);
|
||||||
|
|
||||||
if (TREE_TYPE(this->current_expression) != boolean_type_node)
|
make_if_branch(statement->body(), goto_endif);
|
||||||
|
|
||||||
|
for (const auto branch : statement->branches)
|
||||||
{
|
{
|
||||||
error_at(get_location(&statement->body().prerequisite().position()),
|
make_if_branch(*branch, goto_endif);
|
||||||
"expected expression of boolean type but its type is %s",
|
|
||||||
print_type(TREE_TYPE(this->current_expression)));
|
|
||||||
this->current_expression = error_mark_node;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto then_location = get_location(&statement->position());
|
|
||||||
auto prerequisite_location = get_location(&statement->body().prerequisite().position());
|
|
||||||
|
|
||||||
auto then_label_decl = build_label_decl("then", then_location);
|
|
||||||
auto endif_label_decl = build_label_decl("end_if", then_location);
|
|
||||||
|
|
||||||
auto goto_then = build1_loc(prerequisite_location, GOTO_EXPR,
|
|
||||||
void_type_node, then_label_decl);
|
|
||||||
auto goto_endif = build1_loc(prerequisite_location, GOTO_EXPR,
|
|
||||||
void_type_node, endif_label_decl);
|
|
||||||
|
|
||||||
tree else_label_decl = NULL_TREE;
|
|
||||||
tree goto_else_or_endif = NULL_TREE;
|
|
||||||
if (statement->alternative() != nullptr)
|
|
||||||
{
|
|
||||||
auto else_location = get_location(&statement->position());
|
|
||||||
else_label_decl = build_label_decl("else", else_location);
|
|
||||||
goto_else_or_endif = build1_loc(else_location, GOTO_EXPR, void_type_node, else_label_decl);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
goto_else_or_endif = goto_endif;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto cond_expr = build3_loc(prerequisite_location, COND_EXPR,
|
|
||||||
void_type_node, this->current_expression, goto_then, goto_else_or_endif);
|
|
||||||
append_to_statement_list(cond_expr, &this->current_statements);
|
|
||||||
|
|
||||||
auto then_label_expr = build1_loc(then_location, LABEL_EXPR,
|
|
||||||
void_type_node, then_label_decl);
|
|
||||||
append_to_statement_list(then_label_expr, &this->current_statements);
|
|
||||||
|
|
||||||
for (const auto body_statement : statement->body().statements)
|
|
||||||
{
|
|
||||||
body_statement->accept(this);
|
|
||||||
}
|
}
|
||||||
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);
|
|
||||||
append_to_statement_list(else_label_expr, &this->current_statements);
|
|
||||||
|
|
||||||
for (const auto body_statement : *statement->alternative())
|
for (const auto body_statement : *statement->alternative())
|
||||||
{
|
{
|
||||||
body_statement->accept(this);
|
body_statement->accept(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto endif_label_expr = build1(LABEL_EXPR, void_type_node, endif_label_decl);
|
|
||||||
append_to_statement_list(endif_label_expr, &this->current_statements);
|
|
||||||
|
|
||||||
|
tree endif_label_expr = build1(LABEL_EXPR, void_type_node, endif_label_decl);
|
||||||
|
append_to_statement_list(endif_label_expr, &this->current_statements);
|
||||||
this->current_expression = NULL_TREE;
|
this->current_expression = NULL_TREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void generic_visitor::make_if_branch(source::conditional_statements& branch, tree goto_endif)
|
||||||
|
{
|
||||||
|
branch.prerequisite().accept(this);
|
||||||
|
|
||||||
|
if (TREE_TYPE(this->current_expression) != boolean_type_node)
|
||||||
|
{
|
||||||
|
error_at(get_location(&branch.prerequisite().position()),
|
||||||
|
"expected expression of boolean type but its type is %s",
|
||||||
|
print_type(TREE_TYPE(this->current_expression)));
|
||||||
|
this->current_expression = error_mark_node;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tree then_label_decl = build_label_decl("then", UNKNOWN_LOCATION);
|
||||||
|
tree goto_then = build1(GOTO_EXPR, void_type_node, then_label_decl);
|
||||||
|
|
||||||
|
tree else_label_decl = build_label_decl("else", UNKNOWN_LOCATION);
|
||||||
|
tree goto_else = build1(GOTO_EXPR, void_type_node, else_label_decl);
|
||||||
|
|
||||||
|
auto cond_expr = build3(COND_EXPR, void_type_node, this->current_expression, goto_then, goto_else);
|
||||||
|
append_to_statement_list(cond_expr, &this->current_statements);
|
||||||
|
|
||||||
|
tree then_label_expr = build1(LABEL_EXPR, void_type_node, then_label_decl);
|
||||||
|
append_to_statement_list(then_label_expr, &this->current_statements);
|
||||||
|
|
||||||
|
for (const auto body_statement : branch.statements)
|
||||||
|
{
|
||||||
|
body_statement->accept(this);
|
||||||
|
}
|
||||||
|
append_to_statement_list(goto_endif, &this->current_statements);
|
||||||
|
|
||||||
|
tree else_label_expr = build1(LABEL_EXPR, void_type_node, else_label_decl);
|
||||||
|
append_to_statement_list(else_label_expr, &this->current_statements);
|
||||||
|
}
|
||||||
|
|
||||||
tree generic_visitor::build_label_decl(const char *name, location_t loc)
|
tree generic_visitor::build_label_decl(const char *name, location_t loc)
|
||||||
{
|
{
|
||||||
auto label_decl = build_decl(loc,
|
auto label_decl = build_decl(loc,
|
||||||
|
@ -34,6 +34,8 @@ namespace gcc
|
|||||||
void build_binary_operation(bool condition, source::binary_expression *expression,
|
void build_binary_operation(bool condition, source::binary_expression *expression,
|
||||||
tree_code operator_code, tree left, tree right, tree target_type);
|
tree_code operator_code, tree left, tree right, tree target_type);
|
||||||
|
|
||||||
|
void make_if_branch(source::conditional_statements& branch, tree goto_endif);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
generic_visitor(std::shared_ptr<source::symbol_table<tree>> symbol_table);
|
generic_visitor(std::shared_ptr<source::symbol_table<tree>> symbol_table);
|
||||||
|
|
||||||
|
@ -617,6 +617,8 @@ namespace source
|
|||||||
std::vector<statement *> *m_alternative;
|
std::vector<statement *> *m_alternative;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
std::vector<conditional_statements *> branches;
|
||||||
|
|
||||||
if_statement(const struct position position, conditional_statements *body,
|
if_statement(const struct position position, conditional_statements *body,
|
||||||
std::vector<statement *> *alternative = nullptr);
|
std::vector<statement *> *alternative = nullptr);
|
||||||
virtual void accept(parser_visitor *visitor) override;
|
virtual void accept(parser_visitor *visitor) override;
|
||||||
|
@ -898,7 +898,10 @@ namespace source
|
|||||||
if_statement::~if_statement()
|
if_statement::~if_statement()
|
||||||
{
|
{
|
||||||
delete m_body;
|
delete m_body;
|
||||||
|
for (const auto branch : branches)
|
||||||
|
{
|
||||||
|
delete branch;
|
||||||
|
}
|
||||||
if (m_alternative != nullptr)
|
if (m_alternative != nullptr)
|
||||||
{
|
{
|
||||||
delete m_alternative;
|
delete m_alternative;
|
||||||
|
@ -96,6 +96,7 @@
|
|||||||
%type <elna::source::block *> block;
|
%type <elna::source::block *> block;
|
||||||
%type <std::pair<std::string, elna::source::type_expression *>> field_declaration;
|
%type <std::pair<std::string, elna::source::type_expression *>> field_declaration;
|
||||||
%type <std::vector<std::pair<std::string, elna::source::type_expression *>>> field_list;
|
%type <std::vector<std::pair<std::string, elna::source::type_expression *>>> field_list;
|
||||||
|
%type <std::vector<elna::source::conditional_statements *>> elsif_statement_list;
|
||||||
%%
|
%%
|
||||||
program:
|
program:
|
||||||
type_part constant_part procedure_part variable_part BEGIN_BLOCK optional_statements END_BLOCK DOT
|
type_part constant_part procedure_part variable_part BEGIN_BLOCK optional_statements END_BLOCK DOT
|
||||||
@ -121,7 +122,7 @@ program:
|
|||||||
{
|
{
|
||||||
*value_definition++ = variable;
|
*value_definition++ = variable;
|
||||||
}
|
}
|
||||||
auto tree = new elna::source::program(elna::source::position{},
|
auto tree = new elna::source::program(elna::source::make_position(@5),
|
||||||
std::move(definitions), std::move(value_definitions), std::move($6));
|
std::move(definitions), std::move(value_definitions), std::move($6));
|
||||||
|
|
||||||
driver.tree.reset(tree);
|
driver.tree.reset(tree);
|
||||||
@ -139,28 +140,28 @@ block: constant_part variable_part BEGIN_BLOCK optional_statements END_BLOCK
|
|||||||
{
|
{
|
||||||
*definition++ = variable;
|
*definition++ = variable;
|
||||||
}
|
}
|
||||||
$$ = new elna::source::block(elna::source::position{},
|
$$ = new elna::source::block(elna::source::make_position(@3),
|
||||||
std::move(definitions), std::move($4));
|
std::move(definitions), std::move($4));
|
||||||
}
|
}
|
||||||
procedure_definition:
|
procedure_definition:
|
||||||
PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON block SEMICOLON
|
PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON block SEMICOLON
|
||||||
{
|
{
|
||||||
$$ = new elna::source::procedure_definition(elna::source::position{},
|
$$ = new elna::source::procedure_definition(elna::source::make_position(@1),
|
||||||
$2, std::move($3), nullptr, $5);
|
$2, std::move($3), nullptr, $5);
|
||||||
}
|
}
|
||||||
| PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON EXTERN SEMICOLON
|
| PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON EXTERN SEMICOLON
|
||||||
{
|
{
|
||||||
$$ = new elna::source::procedure_definition(elna::source::position{},
|
$$ = new elna::source::procedure_definition(elna::source::make_position(@1),
|
||||||
$2, std::move($3), nullptr, nullptr);
|
$2, std::move($3), nullptr, nullptr);
|
||||||
}
|
}
|
||||||
| PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON block SEMICOLON
|
| PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON block SEMICOLON
|
||||||
{
|
{
|
||||||
$$ = new elna::source::procedure_definition(elna::source::position{},
|
$$ = new elna::source::procedure_definition(elna::source::make_position(@1),
|
||||||
$2, std::move($3), $5, $7);
|
$2, std::move($3), $5, $7);
|
||||||
}
|
}
|
||||||
| PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON EXTERN SEMICOLON
|
| PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON EXTERN SEMICOLON
|
||||||
{
|
{
|
||||||
$$ = new elna::source::procedure_definition(elna::source::position{},
|
$$ = new elna::source::procedure_definition(elna::source::make_position(@1),
|
||||||
$2, std::move($3), $5, nullptr);
|
$2, std::move($3), $5, nullptr);
|
||||||
}
|
}
|
||||||
procedure_definitions:
|
procedure_definitions:
|
||||||
@ -188,19 +189,30 @@ while_statement: WHILE expression DO optional_statements END_BLOCK
|
|||||||
std::swap($4, body->statements);
|
std::swap($4, body->statements);
|
||||||
$$ = new elna::source::while_statement(elna::source::make_position(@1), body);
|
$$ = new elna::source::while_statement(elna::source::make_position(@1), body);
|
||||||
}
|
}
|
||||||
|
elsif_statement_list:
|
||||||
|
ELSIF expression THEN optional_statements elsif_statement_list
|
||||||
|
{
|
||||||
|
elna::source::conditional_statements *branch = new elna::source::conditional_statements($2);
|
||||||
|
std::swap(branch->statements, $4);
|
||||||
|
std::swap($5, $$);
|
||||||
|
$$.emplace($$.begin(), branch);
|
||||||
|
}
|
||||||
|
| {}
|
||||||
if_statement:
|
if_statement:
|
||||||
IF expression THEN optional_statements END_BLOCK
|
IF expression THEN optional_statements elsif_statement_list END_BLOCK
|
||||||
{
|
{
|
||||||
auto then = new elna::source::conditional_statements($2);
|
auto then = new elna::source::conditional_statements($2);
|
||||||
std::swap($4, then->statements);
|
std::swap($4, then->statements);
|
||||||
$$ = new elna::source::if_statement(elna::source::make_position(@1), then);
|
$$ = new elna::source::if_statement(elna::source::make_position(@1), then);
|
||||||
|
std::swap($5, $$->branches);
|
||||||
}
|
}
|
||||||
| IF expression THEN optional_statements ELSE optional_statements END_BLOCK
|
| IF expression THEN optional_statements elsif_statement_list ELSE optional_statements END_BLOCK
|
||||||
{
|
{
|
||||||
auto then = new elna::source::conditional_statements($2);
|
auto then = new elna::source::conditional_statements($2);
|
||||||
std::swap($4, then->statements);
|
std::swap($4, then->statements);
|
||||||
auto _else = new std::vector<elna::source::statement *>(std::move($6));
|
auto _else = new std::vector<elna::source::statement *>(std::move($7));
|
||||||
$$ = new elna::source::if_statement(elna::source::make_position(@1), then, _else);
|
$$ = new elna::source::if_statement(elna::source::make_position(@1), then, _else);
|
||||||
|
std::swap($5, $$->branches);
|
||||||
}
|
}
|
||||||
return_statement:
|
return_statement:
|
||||||
RETURN expression
|
RETURN expression
|
||||||
|
Loading…
x
Reference in New Issue
Block a user