Support else in if then conditions
This commit is contained in:
parent
c558c3d6b4
commit
75a691134f
4
config-lang.in
Normal file
4
config-lang.in
Normal file
@ -0,0 +1,4 @@
|
||||
language="elna"
|
||||
gcc_subdir="elna/gcc"
|
||||
|
||||
. ${srcdir}/elna/gcc/config-lang.in
|
@ -89,14 +89,27 @@ elna.stageprofile: stageprofile-start
|
||||
elna.stagefeedback: stagefeedback-start
|
||||
-mv elna/*$(objext) stagefeedback/elna
|
||||
|
||||
ELNA_INCLUDES = -I $(srcdir)/elna -I $(srcdir)/elna/generated
|
||||
ELNA_INCLUDES = -I $(srcdir)/elna/include -I elna/generated
|
||||
|
||||
CFLAGS-elna/elna1.o += $(ELNA_INCLUDES)
|
||||
|
||||
elna/%.o: elna/source/%.cc
|
||||
elna/%.o: elna/source/%.cc elna/generated/parser.hh elna/generated/location.hh
|
||||
$(COMPILE) $(ELNA_INCLUDES) $<
|
||||
$(POSTCOMPILE)
|
||||
|
||||
elna/%.o: elna/generated/%.cc
|
||||
elna/%.o: elna/generated/%.cc elna/generated/parser.hh elna/generated/location.hh
|
||||
$(COMPILE) $(ELNA_INCLUDES) $<
|
||||
$(POSTCOMPILE)
|
||||
|
||||
elna/%.o: elna/gcc/%.cc elna/generated/parser.hh elna/generated/location.hh
|
||||
$(COMPILE) $(ELNA_INCLUDES) $<
|
||||
$(POSTCOMPILE)
|
||||
|
||||
elna/generated/parser.cc: elna/source/parser.yy
|
||||
mkdir -p $(dir $@)
|
||||
$(BISON) -d -o $@ $<
|
||||
|
||||
elna/generated/parser.hh elna/generated/location.hh: elna/generated/parser.cc
|
||||
@touch $@
|
||||
|
||||
elna/generated/lexer.cc: elna/source/lexer.ll
|
||||
mkdir -p $(dir $@)
|
||||
$(FLEX) -o $@ $<
|
||||
|
@ -1,11 +1,11 @@
|
||||
# gcc-src/gcc/config/config-lang.in
|
||||
language="elna"
|
||||
gcc_subdir="elna/gcc"
|
||||
|
||||
compilers="elna1\$(exeext)"
|
||||
|
||||
target_libs=""
|
||||
|
||||
gtfiles="\$(srcdir)/elna/elna1.cc"
|
||||
gtfiles="\$(srcdir)/elna/gcc/elna1.cc"
|
||||
|
||||
lang_requires_boot_languages=c++
|
||||
|
||||
|
@ -118,20 +118,25 @@ namespace gcc
|
||||
|
||||
auto expression_location = get_location(&expression->position());
|
||||
tree_code operator_code = ERROR_MARK;
|
||||
tree target_type = error_mark_node;
|
||||
|
||||
switch (expression->operation())
|
||||
{
|
||||
case source::binary_operator::sum:
|
||||
operator_code = PLUS_EXPR;
|
||||
target_type = integer_type_node;
|
||||
break;
|
||||
case source::binary_operator::subtraction:
|
||||
operator_code = MINUS_EXPR;
|
||||
target_type = integer_type_node;
|
||||
break;
|
||||
case source::binary_operator::division:
|
||||
operator_code = TRUNC_DIV_EXPR;
|
||||
target_type = integer_type_node;
|
||||
break;
|
||||
case source::binary_operator::multiplication:
|
||||
operator_code = MULT_EXPR;
|
||||
target_type = integer_type_node;
|
||||
break;
|
||||
}
|
||||
if (operator_code != ERROR_MARK) // An arithmetic operation.
|
||||
@ -150,21 +155,27 @@ namespace gcc
|
||||
{
|
||||
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:
|
||||
operator_code = LT_EXPR;
|
||||
target_type = boolean_type_node;
|
||||
break;
|
||||
case source::binary_operator::greater:
|
||||
operator_code = GT_EXPR;
|
||||
target_type = boolean_type_node;
|
||||
break;
|
||||
case source::binary_operator::less_equal:
|
||||
operator_code = LE_EXPR;
|
||||
target_type = boolean_type_node;
|
||||
break;
|
||||
case source::binary_operator::greater_equal:
|
||||
operator_code = GE_EXPR;
|
||||
target_type = boolean_type_node;
|
||||
break;
|
||||
}
|
||||
if (left_type != right_type)
|
||||
@ -176,8 +187,11 @@ namespace gcc
|
||||
this->current_expression = error_mark_node;
|
||||
return;
|
||||
}
|
||||
gcc_assert(operator_code != ERROR_MARK);
|
||||
gcc_assert(target_type != error_mark_node);
|
||||
|
||||
this->current_expression = build2_loc(expression_location,
|
||||
operator_code, integer_type_node, left, right);
|
||||
operator_code, target_type, left, right);
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::constant_definition *definition)
|
||||
@ -210,16 +224,25 @@ namespace gcc
|
||||
|
||||
void generic_visitor::visit(source::declaration *declaration)
|
||||
{
|
||||
if (declaration->type().base() != "Int" && declaration->type().base() != "Bool")
|
||||
tree declaration_type = error_mark_node;
|
||||
|
||||
if (declaration->type().base() == "Int")
|
||||
{
|
||||
declaration_type = integer_type_node;
|
||||
}
|
||||
else if (declaration->type().base() == "Bool")
|
||||
{
|
||||
declaration_type = boolean_type_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
error_at(get_location(&declaration->type().position()),
|
||||
"type '%s' not declared",
|
||||
declaration->type().base().c_str());
|
||||
"type '%s' not declared", declaration->type().base().c_str());
|
||||
return;
|
||||
}
|
||||
auto declaration_location = get_location(&declaration->position());
|
||||
tree declaration_tree = build_decl(declaration_location, VAR_DECL,
|
||||
get_identifier(declaration->identifier().c_str()), integer_type_node);
|
||||
get_identifier(declaration->identifier().c_str()), declaration_type);
|
||||
auto result = this->symbol_map.insert({ declaration->identifier(), declaration_tree });
|
||||
|
||||
if (result.second)
|
||||
@ -312,8 +335,21 @@ namespace gcc
|
||||
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->alternative()->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_endif);
|
||||
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,
|
||||
@ -322,6 +358,13 @@ namespace gcc
|
||||
|
||||
statement->body().accept(this);
|
||||
|
||||
if (statement->alternative() != nullptr)
|
||||
{
|
||||
auto else_label_expr = build1(LABEL_EXPR, void_type_node, else_label_decl);
|
||||
append_to_statement_list(else_label_expr, &this->current_statements);
|
||||
|
||||
statement->alternative()->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);
|
||||
|
||||
|
@ -361,19 +361,22 @@ namespace source
|
||||
{
|
||||
std::unique_ptr<expression> m_prerequisite;
|
||||
std::unique_ptr<statement> m_body;
|
||||
std::unique_ptr<statement> m_alternative;
|
||||
|
||||
public:
|
||||
/**
|
||||
* \param position Source code position.
|
||||
* \param prerequisite Condition.
|
||||
* \param body Statement executed if the condition is met.
|
||||
* \param alternative Statement executed if the condition is not met.
|
||||
*/
|
||||
if_statement(const struct position position, std::unique_ptr<expression>&& prerequisite,
|
||||
std::unique_ptr<statement>&& body);
|
||||
std::unique_ptr<statement>&& body, std::unique_ptr<statement>&& alternative = nullptr);
|
||||
virtual void accept(parser_visitor *visitor) override;
|
||||
|
||||
expression& prerequisite();
|
||||
statement& body();
|
||||
std::unique_ptr<statement>& alternative();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -485,8 +485,9 @@ namespace source
|
||||
}
|
||||
|
||||
if_statement::if_statement(const struct position position, std::unique_ptr<expression>&& prerequisite,
|
||||
std::unique_ptr<statement>&& body)
|
||||
: statement(position), m_prerequisite(std::move(prerequisite)), m_body(std::move(body))
|
||||
std::unique_ptr<statement>&& body, std::unique_ptr<statement>&& alternative)
|
||||
: statement(position), m_prerequisite(std::move(prerequisite)), m_body(std::move(body)),
|
||||
m_alternative(std::move(alternative))
|
||||
{
|
||||
}
|
||||
|
||||
@ -505,6 +506,11 @@ namespace source
|
||||
return *m_body;
|
||||
}
|
||||
|
||||
std::unique_ptr<statement>& if_statement::alternative()
|
||||
{
|
||||
return m_alternative;
|
||||
}
|
||||
|
||||
while_statement::while_statement(const struct position position, std::unique_ptr<expression>&& prerequisite,
|
||||
std::unique_ptr<statement>&& body)
|
||||
: statement(position), m_prerequisite(std::move(prerequisite)), m_body(std::move(body))
|
||||
|
@ -37,6 +37,9 @@ if {
|
||||
then {
|
||||
return yy::parser::make_THEN(this->location);
|
||||
}
|
||||
else {
|
||||
return yy::parser::make_ELSE(this->location);
|
||||
}
|
||||
while {
|
||||
return yy::parser::make_WHILE(this->location);
|
||||
}
|
||||
|
@ -59,7 +59,7 @@
|
||||
%token <std::string> IDENTIFIER "identifier"
|
||||
%token <std::int32_t> NUMBER "number"
|
||||
%token <bool> BOOLEAN
|
||||
%token IF THEN WHILE DO
|
||||
%token IF WHILE DO
|
||||
%token CONST VAR PROCEDURE
|
||||
%token BEGIN_BLOCK END_BLOCK
|
||||
%token LEFT_PAREN RIGHT_PAREN SEMICOLON DOT COMMA
|
||||
@ -67,6 +67,9 @@
|
||||
%token PLUS MINUS MULTIPLICATION DIVISION
|
||||
%token ASSIGNMENT COLON HAT AT
|
||||
|
||||
%precedence THEN
|
||||
%precedence ELSE
|
||||
|
||||
%type <std::unique_ptr<elna::source::integer_literal>> integer_literal;
|
||||
%type <std::unique_ptr<elna::source::boolean_literal>> boolean_literal;
|
||||
%type <std::unique_ptr<elna::source::constant_definition>> constant_definition;
|
||||
@ -169,6 +172,11 @@ if_statement:
|
||||
$$ = std::make_unique<elna::source::if_statement>(elna::source::make_position(@1),
|
||||
std::move($2), std::move($4));
|
||||
}
|
||||
| IF expression THEN statement ELSE statement
|
||||
{
|
||||
$$ = std::make_unique<elna::source::if_statement>(elna::source::make_position(@1),
|
||||
std::move($2), std::move($4), std::move($6));
|
||||
}
|
||||
pointer:
|
||||
integer_literal { $$ = std::move($1); }
|
||||
| boolean_literal { $$ = std::move($1); }
|
||||
|
Loading…
x
Reference in New Issue
Block a user