189 lines
6.8 KiB
C++
189 lines
6.8 KiB
C++
#include "elna/gcc/elna-generic.h"
|
|
#include "elna/gcc/elna-diagnostic.h"
|
|
|
|
#include "input.h"
|
|
#include "cgraph.h"
|
|
#include "gimplify.h"
|
|
#include "stringpool.h"
|
|
#include "diagnostic.h"
|
|
|
|
namespace elna
|
|
{
|
|
namespace gcc
|
|
{
|
|
void generic_visitor::visit(source::call_statement *statement)
|
|
{
|
|
empty_visitor::visit(statement);
|
|
|
|
const char *format_integer = "%d\n";
|
|
tree args[] = {
|
|
build_string_literal(strlen(format_integer) + 1, format_integer),
|
|
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);
|
|
}
|
|
|
|
void generic_visitor::visit(source::program *program)
|
|
{
|
|
tree main_fndecl_type_param[] = {
|
|
integer_type_node,
|
|
build_pointer_type(build_pointer_type (char_type_node))
|
|
};
|
|
tree main_fndecl_type = build_function_type_array(integer_type_node, 2, main_fndecl_type_param);
|
|
tree main_fndecl = build_fn_decl("main", main_fndecl_type);
|
|
tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, integer_type_node);
|
|
DECL_RESULT(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);
|
|
|
|
this->current_statements = alloc_stmt_list();
|
|
|
|
empty_visitor::visit(program);
|
|
|
|
append_to_statement_list(return_stmt, &this->current_statements);
|
|
|
|
tree new_block = build_block(NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE);
|
|
tree bind_expr = build3(BIND_EXPR, void_type_node, NULL_TREE, this->current_statements, new_block);
|
|
|
|
BLOCK_SUPERCONTEXT(new_block) = main_fndecl;
|
|
DECL_INITIAL(main_fndecl) = new_block;
|
|
DECL_SAVED_TREE(main_fndecl) = bind_expr;
|
|
|
|
DECL_EXTERNAL(main_fndecl) = 0;
|
|
DECL_PRESERVE_P(main_fndecl) = 1;
|
|
|
|
gimplify_function_tree(main_fndecl);
|
|
|
|
cgraph_node::finalize_function(main_fndecl, true);
|
|
}
|
|
|
|
void generic_visitor::visit(source::integer_literal *literal)
|
|
{
|
|
current_expression = build_int_cst_type(integer_type_node, literal->number());
|
|
}
|
|
|
|
void generic_visitor::visit(source::boolean_literal *literal)
|
|
{
|
|
current_expression = build_int_cst_type(boolean_type_node, literal->boolean());
|
|
}
|
|
|
|
void generic_visitor::visit(source::binary_expression *expression)
|
|
{
|
|
expression->lhs().accept(this);
|
|
auto left = this->current_expression;
|
|
|
|
expression->rhs().accept(this);
|
|
auto right = this->current_expression;
|
|
|
|
tree_code operator_code{};
|
|
|
|
switch (expression->operation())
|
|
{
|
|
case source::binary_operator::sum:
|
|
operator_code = PLUS_EXPR;
|
|
break;
|
|
case source::binary_operator::subtraction:
|
|
operator_code = MINUS_EXPR;
|
|
break;
|
|
case source::binary_operator::division:
|
|
operator_code = TRUNC_DIV_EXPR;
|
|
break;
|
|
case source::binary_operator::multiplication:
|
|
operator_code = MULT_EXPR;
|
|
break;
|
|
default:
|
|
gcc_unreachable();
|
|
}
|
|
|
|
this->current_expression = build2(operator_code, integer_type_node, left, right);
|
|
}
|
|
|
|
void generic_visitor::visit(source::declaration *declaration)
|
|
{
|
|
if (declaration->type().base() != "Int" && declaration->type().base() != "Bool")
|
|
{
|
|
error_at(elna_gcc_location(&declaration->type().position()),
|
|
"type '%s' not declared",
|
|
declaration->type().base().c_str());
|
|
return;
|
|
}
|
|
auto declaration_location = elna_gcc_location(&declaration->position());
|
|
tree declaration_tree = build_decl(declaration_location, VAR_DECL,
|
|
get_identifier(declaration->identifier().c_str()), integer_type_node);
|
|
auto result = this->symbol_map.insert({ declaration->identifier(), declaration_tree });
|
|
|
|
if (result.second)
|
|
{
|
|
auto declaration_statement = build1_loc(declaration_location, DECL_EXPR,
|
|
void_type_node, declaration_tree);
|
|
append_to_statement_list(declaration_statement, &this->current_statements);
|
|
}
|
|
else
|
|
{
|
|
error_at(declaration_location,
|
|
"variable '%s' already declared in this scope",
|
|
declaration->identifier().c_str());
|
|
}
|
|
}
|
|
|
|
void generic_visitor::visit(source::variable_expression *expression)
|
|
{
|
|
auto symbol = this->symbol_map.find(expression->name());
|
|
|
|
if (symbol == this->symbol_map.end())
|
|
{
|
|
error_at(elna_gcc_location(&expression->position()),
|
|
"variable '%s' not declared in the current scope",
|
|
expression->name().c_str());
|
|
this->current_expression = error_mark_node;
|
|
return;
|
|
}
|
|
this->current_expression = symbol->second;
|
|
}
|
|
|
|
void generic_visitor::visit(source::assign_statement *statement)
|
|
{
|
|
auto lvalue = this->symbol_map.find(statement->lvalue());
|
|
auto statement_location = elna_gcc_location(&statement->position());
|
|
|
|
if (lvalue == this->symbol_map.end())
|
|
{
|
|
error_at(statement_location,
|
|
"variable '%s' not declared in the current scope",
|
|
statement->lvalue().c_str());
|
|
return;
|
|
}
|
|
statement->rvalue().accept(this);
|
|
|
|
if (TREE_TYPE(this->current_expression) != TREE_TYPE(lvalue->second))
|
|
{
|
|
error_at(elna_gcc_location(&statement->position()),
|
|
"cannot assign value of type %s to variable '%s' of type %s",
|
|
elna_gcc_print_type(TREE_TYPE(this->current_expression)),
|
|
statement->lvalue().c_str(),
|
|
elna_gcc_print_type(TREE_TYPE(lvalue->second)));
|
|
this->current_expression = error_mark_node;
|
|
return;
|
|
}
|
|
auto assignment = build2_loc(statement_location, MODIFY_EXPR,
|
|
void_type_node, lvalue->second, this->current_expression);
|
|
|
|
append_to_statement_list(assignment, &this->current_statements);
|
|
this->current_expression = NULL_TREE;
|
|
}
|
|
}
|
|
}
|