Translate position to a GCC location
This commit is contained in:
parent
51f5603c4a
commit
d46608b358
@ -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 \
|
||||
|
14
gcc/elna-convert.cc
Normal file
14
gcc/elna-convert.cc
Normal 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
26
gcc/elna-diagnostic.cc
Normal 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>>";
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
47
gcc/elna1.cc
47
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 <fstream>
|
||||
#include <elna/source/driver.h>
|
||||
#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,23 +60,10 @@ 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);
|
||||
|
||||
/* I don't know why this has to be done explicitly. */
|
||||
@ -88,45 +74,36 @@ elna_langhook_init (void)
|
||||
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 };
|
||||
|
||||
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);
|
||||
|
||||
linemap_add(line_table, LC_ENTER, 0, filename, 1);
|
||||
if (auto result = parser())
|
||||
{
|
||||
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 };
|
||||
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());
|
||||
}
|
||||
linemap_add(line_table, LC_LEAVE, 0, NULL, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
13
include/elna/gcc/elna-diagnostic.h
Normal file
13
include/elna/gcc/elna-diagnostic.h
Normal 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);
|
@ -8,6 +8,9 @@
|
||||
#include "tree.h"
|
||||
#include "tree-iterator.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
namespace elna
|
||||
{
|
||||
namespace gcc
|
||||
@ -16,12 +19,17 @@ namespace gcc
|
||||
{
|
||||
tree current_statements{ NULL_TREE };
|
||||
tree current_expression{ NULL_TREE };
|
||||
std::unordered_map<std::string, tree> 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;
|
||||
};
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user