Translate position to a GCC location

This commit is contained in:
Eugen Wissner 2024-12-27 23:38:25 +01:00
parent 51f5603c4a
commit d46608b358
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
9 changed files with 182 additions and 61 deletions

View File

@ -21,7 +21,9 @@ gccelna$(exeext): $(GCCELNA_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBDEPS
elna_OBJS = \ elna_OBJS = \
elna/elna1.o \ elna/elna1.o \
elna/generic-visitor.o \ elna/elna-generic.o \
elna/elna-convert.o \
elna/elna-diagnostic.o \
elna/ast.o \ elna/ast.o \
elna/driver.o \ elna/driver.o \
elna/lexer.o \ elna/lexer.o \

14
gcc/elna-convert.cc Normal file
View File

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

26
gcc/elna-diagnostic.cc Normal file
View File

@ -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 "<<unknown-type>>";
}
}

View File

@ -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 "input.h"
#include "cgraph.h" #include "cgraph.h"
#include "gimplify.h" #include "gimplify.h"
#include "stringpool.h"
#include "diagnostic.h"
namespace elna namespace elna
{ {
@ -72,6 +75,11 @@ namespace gcc
current_expression = build_int_cst_type(integer_type_node, literal->number()); 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) void generic_visitor::visit(source::binary_expression *expression)
{ {
expression->lhs().accept(this); expression->lhs().accept(this);
@ -102,5 +110,79 @@ namespace gcc
this->current_expression = build2(operator_code, integer_type_node, left, right); 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;
}
} }
} }

View File

@ -10,15 +10,14 @@
#include "fold-const.h" #include "fold-const.h"
#include "stor-layout.h" #include "stor-layout.h"
#include "debug.h" #include "debug.h"
#include "convert.h"
#include "langhooks.h" #include "langhooks.h"
#include "langhooks-def.h" #include "langhooks-def.h"
#include "common/common-target.h" #include "common/common-target.h"
#include <fstream> #include <fstream>
#include <elna/source/driver.h> #include <elna/source/driver.h>
#include "elna/source/semantic.h" #include "elna/gcc/elna-generic.h"
#include "elna/gcc/generic-visitor.h" #include "elna/gcc/elna-diagnostic.h"
#include "parser.hh" #include "parser.hh"
/* Language-dependent contents of a type. */ /* Language-dependent contents of a type. */
@ -61,23 +60,10 @@ struct GTY (()) language_function
int dummy; 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. */ /* Language hooks. */
static bool static bool elna_langhook_init(void)
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. */ /* I don't know why this has to be done explicitly. */
@ -88,10 +74,7 @@ elna_langhook_init (void)
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 };
@ -104,30 +87,24 @@ elna_parse_file (const char *filename)
elna::source::lexer lexer(file); elna::source::lexer lexer(file);
yy::parser parser(lexer, driver); yy::parser parser(lexer, driver);
linemap_add(line_table, LC_ENTER, 0, filename, 1);
if (auto result = parser()) 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;
} }
else
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; 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 static void
elna_langhook_parse_file (void) elna_langhook_parse_file (void)

View File

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

View File

@ -8,6 +8,9 @@
#include "tree.h" #include "tree.h"
#include "tree-iterator.h" #include "tree-iterator.h"
#include <unordered_map>
#include <string>
namespace elna namespace elna
{ {
namespace gcc namespace gcc
@ -16,12 +19,17 @@ namespace gcc
{ {
tree current_statements{ NULL_TREE }; tree current_statements{ NULL_TREE };
tree current_expression{ NULL_TREE }; tree current_expression{ NULL_TREE };
std::unordered_map<std::string, tree> symbol_map;
public: public:
void visit(source::program *program) override; void visit(source::program *program) override;
void visit(source::call_statement *statement) override; void visit(source::call_statement *statement) override;
void visit(source::integer_literal *literal) 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::binary_expression *expression) override;
void visit(source::declaration *declaration) override;
void visit(source::variable_expression *expression) override;
void visit(source::assign_statement *statement) override;
}; };
} }
} }

View File

@ -27,8 +27,6 @@ namespace source
*/ */
class error class error
{ {
position m_position;
protected: protected:
/** /**
* Constructs an error. * Constructs an error.
@ -36,9 +34,10 @@ namespace source
* \param path Source file name. * \param path Source file name.
* \param position Error position in the source text. * \param position Error position in the source text.
*/ */
error(const char *path, const position position); error(const char *path, const struct position position);
public: public:
const struct position position;
const char *path; const char *path;
virtual ~error() noexcept = default; virtual ~error() noexcept = default;
@ -55,7 +54,7 @@ namespace source
class name_collision final : public error class name_collision final : public error
{ {
position previous; const struct position previous;
std::string name; std::string name;
public: public:
@ -66,7 +65,7 @@ namespace source
* \param previous Position of the previously defined symbol. * \param previous Position of the previously defined symbol.
*/ */
name_collision(const std::string& name, const char *path, 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; std::string what() const override;
}; };

View File

@ -7,23 +7,23 @@ namespace elna
{ {
namespace source namespace source
{ {
error::error(const char *path, const position position) error::error(const char *path, const struct position position)
: m_position(position), path(path) : position(position), path(path)
{ {
} }
std::size_t error::line() const noexcept std::size_t error::line() const noexcept
{ {
return this->m_position.line; return this->position.line;
} }
std::size_t error::column() const noexcept 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, 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) : error(path, current), name(name), previous(previous)
{ {
} }