Support else in if then conditions

This commit is contained in:
Eugen Wissner 2024-12-30 23:12:47 +01:00
parent c558c3d6b4
commit 75a691134f
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
8 changed files with 97 additions and 17 deletions

4
config-lang.in Normal file
View File

@ -0,0 +1,4 @@
language="elna"
gcc_subdir="elna/gcc"
. ${srcdir}/elna/gcc/config-lang.in

View File

@ -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 $@ $<

View File

@ -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++

View File

@ -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);

View File

@ -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();
};
/**

View File

@ -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))

View File

@ -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);
}

View File

@ -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); }