diff --git a/gcc/Make-lang.in b/gcc/Make-lang.in index dbe18f8..ae52ac1 100644 --- a/gcc/Make-lang.in +++ b/gcc/Make-lang.in @@ -21,7 +21,9 @@ gccelna$(exeext): $(GCCELNA_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBDEPS elna_OBJS = \ elna/elna1.o \ - elna/generic-visitor.o \ + elna/elna-generic.o \ + elna/elna-convert.o \ + elna/elna-diagnostic.o \ elna/ast.o \ elna/driver.o \ elna/lexer.o \ diff --git a/gcc/elna-convert.cc b/gcc/elna-convert.cc new file mode 100644 index 0000000..ad10324 --- /dev/null +++ b/gcc/elna-convert.cc @@ -0,0 +1,14 @@ +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "fold-const.h" +#include "convert.h" + +/* Creates an expression whose value is that of EXPR, converted to type TYPE. + This function implements all reasonable scalar conversions. */ + +tree convert(tree type, tree expr) +{ + return expr; +} diff --git a/gcc/elna-diagnostic.cc b/gcc/elna-diagnostic.cc new file mode 100644 index 0000000..3bfaaab --- /dev/null +++ b/gcc/elna-diagnostic.cc @@ -0,0 +1,26 @@ +#include "elna/gcc/elna-diagnostic.h" + +location_t elna_gcc_location(const elna::source::position *position) +{ + linemap_line_start(line_table, position->line, 0); + + return linemap_position_for_column(line_table, position->column); +} + +const char *elna_gcc_print_type(tree type) +{ + gcc_assert(TYPE_P(type)); + + if (type == integer_type_node) + { + return "Int"; + } + else if (type == boolean_type_node) + { + return "Boolean"; + } + else + { + return "<>"; + } +} diff --git a/gcc/generic-visitor.cc b/gcc/elna-generic.cc similarity index 52% rename from gcc/generic-visitor.cc rename to gcc/elna-generic.cc index 766349a..0dccd6b 100644 --- a/gcc/generic-visitor.cc +++ b/gcc/elna-generic.cc @@ -1,8 +1,11 @@ -#include "elna/gcc/generic-visitor.h" +#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 { @@ -72,6 +75,11 @@ namespace gcc 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); @@ -102,5 +110,79 @@ namespace gcc 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; + } } } diff --git a/gcc/elna1.cc b/gcc/elna1.cc index 5b6c8c4..fe994b1 100644 --- a/gcc/elna1.cc +++ b/gcc/elna1.cc @@ -10,15 +10,14 @@ #include "fold-const.h" #include "stor-layout.h" #include "debug.h" -#include "convert.h" #include "langhooks.h" #include "langhooks-def.h" #include "common/common-target.h" #include #include -#include "elna/source/semantic.h" -#include "elna/gcc/generic-visitor.h" +#include "elna/gcc/elna-generic.h" +#include "elna/gcc/elna-diagnostic.h" #include "parser.hh" /* Language-dependent contents of a type. */ @@ -61,72 +60,50 @@ struct GTY (()) language_function int dummy; }; -/* Creates an expression whose value is that of EXPR, converted to type TYPE. - This function implements all reasonable scalar conversions. */ - -tree -convert (tree type, tree expr) -{ - return expr; -} - /* Language hooks. */ -static bool -elna_langhook_init (void) +static bool elna_langhook_init(void) { - /* NOTE: Newer versions of GCC use only: - build_common_tree_nodes (false); - See Eugene's comment in the comments section. */ - build_common_tree_nodes (false); + build_common_tree_nodes (false); - /* I don't know why this has to be done explicitly. */ - void_list_node = build_tree_list (NULL_TREE, void_type_node); + /* I don't know why this has to be done explicitly. */ + void_list_node = build_tree_list (NULL_TREE, void_type_node); - build_common_builtin_nodes (); + build_common_builtin_nodes (); - return true; + return true; } -constexpr std::size_t pointer_size = 4; - -static void -elna_parse_file (const char *filename) +static void elna_parse_file (const char *filename) { - std::ifstream file{ filename, std::ios::in }; + std::ifstream file{ filename, std::ios::in }; - if (!file) + if (!file) { - fatal_error (UNKNOWN_LOCATION, "cannot open filename %s: %m", filename); + fatal_error(UNKNOWN_LOCATION, "cannot open filename %s: %m", filename); } - elna::source::driver driver{ filename }; - elna::source::lexer lexer(file); - yy::parser parser(lexer, driver); + elna::source::driver driver{ filename }; + elna::source::lexer lexer(file); + yy::parser parser(lexer, driver); - if (auto result = parser()) + linemap_add(line_table, LC_ENTER, 0, filename, 1); + if (auto result = parser()) { - for (const auto& error : driver.errors()) + for (const auto& error : driver.errors()) { - linemap_add (line_table, LC_ENTER, 0, filename, 1); + auto gcc_location = elna_gcc_location(&error->position); - linemap_line_start (line_table, error->line (), 0); - auto gcc_location = linemap_position_for_column (line_table, error->column ()); - linemap_add (line_table, LC_LEAVE, 0, NULL, 0); - - error_at (gcc_location, error->what ().c_str ()); + error_at(gcc_location, error->what().c_str()); } - return; } - - auto symbol_table = elna::source::add_builtin_symbols(); - elna::source::name_analysis_visitor name_analysis_visitor{ symbol_table, filename, pointer_size }; - elna::source::type_analysis_visitor type_analysis_visitor{ symbol_table, filename, pointer_size }; - elna::gcc::generic_visitor generic_visitor; + else + { + elna::gcc::generic_visitor generic_visitor; - name_analysis_visitor.visit(driver.tree.get()); - type_analysis_visitor.visit(driver.tree.get()); - generic_visitor.visit(driver.tree.get()); + generic_visitor.visit(driver.tree.get()); + } + linemap_add(line_table, LC_LEAVE, 0, NULL, 0); } static void diff --git a/include/elna/gcc/elna-diagnostic.h b/include/elna/gcc/elna-diagnostic.h new file mode 100644 index 0000000..e8f3de0 --- /dev/null +++ b/include/elna/gcc/elna-diagnostic.h @@ -0,0 +1,13 @@ +#pragma once + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "input.h" +#include "tree.h" + +#include "elna/source/result.h" + +location_t elna_gcc_location(const elna::source::position *position); + +const char *elna_gcc_print_type(tree type); diff --git a/include/elna/gcc/generic-visitor.h b/include/elna/gcc/elna-generic.h similarity index 63% rename from include/elna/gcc/generic-visitor.h rename to include/elna/gcc/elna-generic.h index fbfd648..388c40a 100644 --- a/include/elna/gcc/generic-visitor.h +++ b/include/elna/gcc/elna-generic.h @@ -8,6 +8,9 @@ #include "tree.h" #include "tree-iterator.h" +#include +#include + namespace elna { namespace gcc @@ -16,12 +19,17 @@ namespace gcc { tree current_statements{ NULL_TREE }; tree current_expression{ NULL_TREE }; + std::unordered_map symbol_map; public: void visit(source::program *program) override; void visit(source::call_statement *statement) override; void visit(source::integer_literal *literal) override; + void visit(source::boolean_literal *literal) override; void visit(source::binary_expression *expression) override; + void visit(source::declaration *declaration) override; + void visit(source::variable_expression *expression) override; + void visit(source::assign_statement *statement) override; }; } } diff --git a/include/elna/source/result.h b/include/elna/source/result.h index b5f4d64..f30938d 100644 --- a/include/elna/source/result.h +++ b/include/elna/source/result.h @@ -27,8 +27,6 @@ namespace source */ class error { - position m_position; - protected: /** * Constructs an error. @@ -36,9 +34,10 @@ namespace source * \param path Source file name. * \param position Error position in the source text. */ - error(const char *path, const position position); + error(const char *path, const struct position position); public: + const struct position position; const char *path; virtual ~error() noexcept = default; @@ -55,7 +54,7 @@ namespace source class name_collision final : public error { - position previous; + const struct position previous; std::string name; public: @@ -66,7 +65,7 @@ namespace source * \param previous Position of the previously defined symbol. */ name_collision(const std::string& name, const char *path, - const position current, const position previous); + const struct position current, const struct position previous); std::string what() const override; }; diff --git a/source/result.cc b/source/result.cc index f4c5ff0..8bd5947 100644 --- a/source/result.cc +++ b/source/result.cc @@ -7,23 +7,23 @@ namespace elna { namespace source { - error::error(const char *path, const position position) - : m_position(position), path(path) + error::error(const char *path, const struct position position) + : position(position), path(path) { } std::size_t error::line() const noexcept { - return this->m_position.line; + return this->position.line; } std::size_t error::column() const noexcept { - return this->m_position.column; + return this->position.column; } name_collision::name_collision(const std::string& name, const char *path, - const position current, const position previous) + const struct position current, const struct position previous) : error(path, current), name(name), previous(previous) { }