Implement pointers
This commit is contained in:
parent
954425f4bd
commit
35c32fcf3f
@ -17,9 +17,7 @@ add_library(elna-frontend
|
|||||||
source/ast.cc include/elna/source/ast.h
|
source/ast.cc include/elna/source/ast.h
|
||||||
source/types.cc include/elna/source/types.h
|
source/types.cc include/elna/source/types.h
|
||||||
source/driver.cc include/elna/source/driver.h
|
source/driver.cc include/elna/source/driver.h
|
||||||
source/symbol_table.cc include/elna/source/symbol_table.h
|
|
||||||
source/result.cc include/elna/source/result.h
|
source/result.cc include/elna/source/result.h
|
||||||
source/semantic.cc include/elna/source/semantic.h
|
|
||||||
${BISON_parser_OUTPUTS} ${FLEX_lexer_OUTPUTS}
|
${BISON_parser_OUTPUTS} ${FLEX_lexer_OUTPUTS}
|
||||||
)
|
)
|
||||||
target_include_directories(elna-frontend PRIVATE ${CMAKE_CURRENT_BINARY_DIR} include)
|
target_include_directories(elna-frontend PRIVATE ${CMAKE_CURRENT_BINARY_DIR} include)
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#include <elna/source/driver.h>
|
#include <elna/source/driver.h>
|
||||||
#include "elna/source/semantic.h"
|
|
||||||
#include "parser.hh"
|
#include "parser.hh"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
@ -34,12 +33,6 @@ int main()
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
auto symbol_table = elna::source::add_builtin_symbols();
|
|
||||||
elna::source::name_analysis_visitor name_analysis_visitor{ symbol_table, "-", pointer_size };
|
|
||||||
elna::source::type_analysis_visitor type_analysis_visitor{ symbol_table, "-", pointer_size };
|
|
||||||
|
|
||||||
name_analysis_visitor.visit(driver.tree.get());
|
|
||||||
|
|
||||||
for (auto& definition : driver.tree->definitions())
|
for (auto& definition : driver.tree->definitions())
|
||||||
{
|
{
|
||||||
std::cout << "Definition identifier: " << definition->identifier() << std::endl;
|
std::cout << "Definition identifier: " << definition->identifier() << std::endl;
|
||||||
|
@ -30,7 +30,6 @@ elna_OBJS = \
|
|||||||
elna/lexer.o \
|
elna/lexer.o \
|
||||||
elna/parser.o \
|
elna/parser.o \
|
||||||
elna/result.o \
|
elna/result.o \
|
||||||
elna/symbol_table.o \
|
|
||||||
elna/types.o \
|
elna/types.o \
|
||||||
$(END)
|
$(END)
|
||||||
|
|
||||||
|
@ -36,6 +36,10 @@ namespace gcc
|
|||||||
{
|
{
|
||||||
return "String";
|
return "String";
|
||||||
}
|
}
|
||||||
|
else if (is_pointer_type(type))
|
||||||
|
{
|
||||||
|
return "pointer";
|
||||||
|
}
|
||||||
else if (is_array_type(type))
|
else if (is_array_type(type))
|
||||||
{
|
{
|
||||||
return "array";
|
return "array";
|
||||||
|
@ -51,6 +51,10 @@ namespace gcc
|
|||||||
{
|
{
|
||||||
format_number = "%s\n";
|
format_number = "%s\n";
|
||||||
}
|
}
|
||||||
|
else if (is_pointer_type(argument_type))
|
||||||
|
{
|
||||||
|
format_number = "%p\n";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
error_at(get_location(&argument->position()),
|
error_at(get_location(&argument->position()),
|
||||||
@ -256,6 +260,20 @@ namespace gcc
|
|||||||
operator_code, target_type, left, right);
|
operator_code, target_type, left, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void generic_visitor::visit(source::unary_expression *expression)
|
||||||
|
{
|
||||||
|
switch (expression->operation())
|
||||||
|
{
|
||||||
|
case source::unary_operator::reference:
|
||||||
|
expression->operand().accept(this);
|
||||||
|
|
||||||
|
this->current_expression = build1_loc(get_location(&expression->position()), ADDR_EXPR,
|
||||||
|
build_pointer_type_for_mode(TREE_TYPE(this->current_expression), VOIDmode, true),
|
||||||
|
this->current_expression);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void generic_visitor::visit(source::constant_definition *definition)
|
void generic_visitor::visit(source::constant_definition *definition)
|
||||||
{
|
{
|
||||||
location_t definition_location = get_location(&definition->position());
|
location_t definition_location = get_location(&definition->position());
|
||||||
@ -344,6 +362,10 @@ namespace gcc
|
|||||||
{
|
{
|
||||||
return TREE_TYPE(symbol->second);
|
return TREE_TYPE(symbol->second);
|
||||||
}
|
}
|
||||||
|
error_at(get_location(&basic_type->position()),
|
||||||
|
"type '%s' not declared", basic_type->base_name().c_str());
|
||||||
|
|
||||||
|
return error_mark_node;
|
||||||
}
|
}
|
||||||
else if (source::array_type_expression *array_type = type.is_array())
|
else if (source::array_type_expression *array_type = type.is_array())
|
||||||
{
|
{
|
||||||
@ -351,14 +373,24 @@ namespace gcc
|
|||||||
tree upper_bound = build_int_cst_type(integer_type_node, array_type->size);
|
tree upper_bound = build_int_cst_type(integer_type_node, array_type->size);
|
||||||
tree base_type = build_type(array_type->base());
|
tree base_type = build_type(array_type->base());
|
||||||
|
|
||||||
if (base_type == NULL_TREE)
|
if (base_type == NULL_TREE || base_type == error_mark_node)
|
||||||
{
|
{
|
||||||
return NULL_TREE;
|
return base_type;
|
||||||
}
|
}
|
||||||
tree range_type = build_range_type(integer_type_node, lower_bound, upper_bound);
|
tree range_type = build_range_type(integer_type_node, lower_bound, upper_bound);
|
||||||
|
|
||||||
return build_array_type(base_type, range_type);
|
return build_array_type(base_type, range_type);
|
||||||
}
|
}
|
||||||
|
else if (source::pointer_type_expression *pointer_type = type.is_pointer())
|
||||||
|
{
|
||||||
|
tree base_type = build_type(pointer_type->base());
|
||||||
|
|
||||||
|
if (base_type == NULL_TREE || base_type == error_mark_node)
|
||||||
|
{
|
||||||
|
return base_type;
|
||||||
|
}
|
||||||
|
return build_pointer_type_for_mode(base_type, VOIDmode, true);
|
||||||
|
}
|
||||||
else if (source::record_type_expression *record_type = type.is_record())
|
else if (source::record_type_expression *record_type = type.is_record())
|
||||||
{
|
{
|
||||||
std::set<std::string> field_names;
|
std::set<std::string> field_names;
|
||||||
@ -397,13 +429,8 @@ namespace gcc
|
|||||||
void generic_visitor::visit(source::declaration *declaration)
|
void generic_visitor::visit(source::declaration *declaration)
|
||||||
{
|
{
|
||||||
tree declaration_type = build_type(declaration->type());
|
tree declaration_type = build_type(declaration->type());
|
||||||
|
gcc_assert(declaration_type != NULL_TREE);
|
||||||
|
|
||||||
if (declaration_type == NULL_TREE)
|
|
||||||
{
|
|
||||||
error_at(get_location(&declaration->type().position()),
|
|
||||||
"type '%s' not declared", declaration->type().base_name().c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto declaration_location = get_location(&declaration->position());
|
auto declaration_location = get_location(&declaration->position());
|
||||||
tree declaration_tree = build_decl(declaration_location, VAR_DECL,
|
tree declaration_tree = build_decl(declaration_location, VAR_DECL,
|
||||||
get_identifier(declaration->identifier().c_str()), declaration_type);
|
get_identifier(declaration->identifier().c_str()), declaration_type);
|
||||||
@ -455,6 +482,46 @@ namespace gcc
|
|||||||
ARRAY_REF, element_type, designator, index, NULL_TREE, NULL_TREE);
|
ARRAY_REF, element_type, designator, index, NULL_TREE, NULL_TREE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void generic_visitor::visit(source::field_access_expression *expression)
|
||||||
|
{
|
||||||
|
expression->base().accept(this);
|
||||||
|
tree field_declaration = TYPE_FIELDS(TREE_TYPE(this->current_expression));
|
||||||
|
|
||||||
|
while (field_declaration != NULL_TREE)
|
||||||
|
{
|
||||||
|
tree declaration_name = DECL_NAME(field_declaration);
|
||||||
|
const char *identifier_pointer = IDENTIFIER_POINTER(declaration_name);
|
||||||
|
|
||||||
|
if (expression->field() == identifier_pointer)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
field_declaration = TREE_CHAIN(field_declaration);
|
||||||
|
}
|
||||||
|
location_t expression_location = get_location(&expression->position());
|
||||||
|
if (field_declaration == NULL_TREE)
|
||||||
|
{
|
||||||
|
error_at(expression_location,
|
||||||
|
"record type does not have a field named '%s'",
|
||||||
|
expression->field().c_str());
|
||||||
|
this->current_expression = error_mark_node;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->current_expression = build3_loc(expression_location, COMPONENT_REF,
|
||||||
|
TREE_TYPE(field_declaration), this->current_expression,
|
||||||
|
field_declaration, NULL_TREE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void generic_visitor::visit(source::dereference_expression *expression)
|
||||||
|
{
|
||||||
|
expression->base().accept(this);
|
||||||
|
|
||||||
|
this->current_expression = build1_loc(get_location(&expression->position()), INDIRECT_REF,
|
||||||
|
TREE_TYPE(TREE_TYPE(this->current_expression)), this->current_expression);
|
||||||
|
}
|
||||||
|
|
||||||
void generic_visitor::visit(source::assign_statement *statement)
|
void generic_visitor::visit(source::assign_statement *statement)
|
||||||
{
|
{
|
||||||
statement->lvalue().accept(this);
|
statement->lvalue().accept(this);
|
||||||
|
@ -16,10 +16,15 @@ namespace gcc
|
|||||||
TYPE_STRING_FLAG(elna_char_type_node) = 1;
|
TYPE_STRING_FLAG(elna_char_type_node) = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_string_type(tree type)
|
bool is_pointer_type(tree type)
|
||||||
{
|
{
|
||||||
gcc_assert(TYPE_P(type));
|
gcc_assert(TYPE_P(type));
|
||||||
return TREE_CODE(type) == POINTER_TYPE
|
return TREE_CODE(type) == POINTER_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_string_type(tree type)
|
||||||
|
{
|
||||||
|
return is_pointer_type(type)
|
||||||
&& TYPE_MAIN_VARIANT(TREE_TYPE(type)) == char_type_node;
|
&& TYPE_MAIN_VARIANT(TREE_TYPE(type)) == char_type_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,11 +39,14 @@ namespace gcc
|
|||||||
void visit(source::char_literal *character) override;
|
void visit(source::char_literal *character) override;
|
||||||
void visit(source::string_literal *string) override;
|
void visit(source::string_literal *string) override;
|
||||||
void visit(source::binary_expression *expression) override;
|
void visit(source::binary_expression *expression) override;
|
||||||
|
void visit(source::unary_expression *expression) override;
|
||||||
void visit(source::constant_definition *definition) override;
|
void visit(source::constant_definition *definition) override;
|
||||||
void visit(source::type_definition *definition) override;
|
void visit(source::type_definition *definition) override;
|
||||||
void visit(source::declaration *declaration) override;
|
void visit(source::declaration *declaration) override;
|
||||||
void visit(source::variable_expression *expression) override;
|
void visit(source::variable_expression *expression) override;
|
||||||
void visit(source::array_access_expression *expression) override;
|
void visit(source::array_access_expression *expression) override;
|
||||||
|
void visit(source::field_access_expression *expression) override;
|
||||||
|
void visit(source::dereference_expression *expression) override;
|
||||||
void visit(source::assign_statement *statement) override;
|
void visit(source::assign_statement *statement) override;
|
||||||
void visit(source::if_statement *statement) override;
|
void visit(source::if_statement *statement) override;
|
||||||
void visit(source::while_statement *statement) override;
|
void visit(source::while_statement *statement) override;
|
||||||
|
@ -23,6 +23,7 @@ namespace elna
|
|||||||
namespace gcc
|
namespace gcc
|
||||||
{
|
{
|
||||||
void init_ttree();
|
void init_ttree();
|
||||||
|
bool is_pointer_type(tree type);
|
||||||
bool is_string_type(tree type);
|
bool is_string_type(tree type);
|
||||||
bool is_array_type(tree type);
|
bool is_array_type(tree type);
|
||||||
bool is_record_type(tree type);
|
bool is_record_type(tree type);
|
||||||
|
@ -30,8 +30,7 @@ namespace source
|
|||||||
|
|
||||||
enum class unary_operator
|
enum class unary_operator
|
||||||
{
|
{
|
||||||
reference,
|
reference
|
||||||
dereference
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class declaration;
|
class declaration;
|
||||||
@ -117,8 +116,8 @@ namespace source
|
|||||||
virtual void visit(record_type_expression *expression) override;
|
virtual void visit(record_type_expression *expression) override;
|
||||||
virtual void visit(variable_expression *) override;
|
virtual void visit(variable_expression *) override;
|
||||||
virtual void visit(array_access_expression *expression) override;
|
virtual void visit(array_access_expression *expression) override;
|
||||||
virtual void visit(field_access_expression *is_field_access) override;
|
virtual void visit(field_access_expression *expression) override;
|
||||||
virtual void visit(dereference_expression *is_dereference) override;
|
virtual void visit(dereference_expression *expression) override;
|
||||||
virtual void visit(number_literal<std::int32_t> *) override;
|
virtual void visit(number_literal<std::int32_t> *) override;
|
||||||
virtual void visit(number_literal<double> *) override;
|
virtual void visit(number_literal<double> *) override;
|
||||||
virtual void visit(number_literal<bool> *) override;
|
virtual void visit(number_literal<bool> *) override;
|
||||||
@ -249,7 +248,6 @@ namespace source
|
|||||||
class type_expression : public node
|
class type_expression : public node
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual const std::string& base_name() = 0;
|
|
||||||
virtual basic_type_expression *is_basic();
|
virtual basic_type_expression *is_basic();
|
||||||
virtual array_type_expression *is_array();
|
virtual array_type_expression *is_array();
|
||||||
virtual pointer_type_expression *is_pointer();
|
virtual pointer_type_expression *is_pointer();
|
||||||
@ -262,7 +260,7 @@ namespace source
|
|||||||
/**
|
/**
|
||||||
* Expression defining a basic type.
|
* Expression defining a basic type.
|
||||||
*/
|
*/
|
||||||
class basic_type_expression : public type_expression
|
class basic_type_expression final : public type_expression
|
||||||
{
|
{
|
||||||
const std::string m_name;
|
const std::string m_name;
|
||||||
|
|
||||||
@ -274,12 +272,12 @@ namespace source
|
|||||||
basic_type_expression(const struct position position, const std::string& name);
|
basic_type_expression(const struct position position, const std::string& name);
|
||||||
virtual void accept(parser_visitor *visitor) override;
|
virtual void accept(parser_visitor *visitor) override;
|
||||||
|
|
||||||
const std::string& base_name() override;
|
const std::string& base_name();
|
||||||
|
|
||||||
basic_type_expression *is_basic() override;
|
basic_type_expression *is_basic() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class array_type_expression : public type_expression
|
class array_type_expression final : public type_expression
|
||||||
{
|
{
|
||||||
type_expression *m_base;
|
type_expression *m_base;
|
||||||
|
|
||||||
@ -290,14 +288,13 @@ namespace source
|
|||||||
virtual void accept(parser_visitor *visitor) override;
|
virtual void accept(parser_visitor *visitor) override;
|
||||||
|
|
||||||
type_expression& base();
|
type_expression& base();
|
||||||
const std::string& base_name() override;
|
|
||||||
|
|
||||||
array_type_expression *is_array() override;
|
array_type_expression *is_array() override;
|
||||||
|
|
||||||
virtual ~array_type_expression() override;
|
virtual ~array_type_expression() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class pointer_type_expression : public type_expression
|
class pointer_type_expression final : public type_expression
|
||||||
{
|
{
|
||||||
type_expression *m_base;
|
type_expression *m_base;
|
||||||
|
|
||||||
@ -306,14 +303,13 @@ namespace source
|
|||||||
virtual void accept(parser_visitor *visitor) override;
|
virtual void accept(parser_visitor *visitor) override;
|
||||||
|
|
||||||
type_expression& base();
|
type_expression& base();
|
||||||
const std::string& base_name() override;
|
|
||||||
|
|
||||||
pointer_type_expression *is_pointer() override;
|
pointer_type_expression *is_pointer() override;
|
||||||
|
|
||||||
virtual ~pointer_type_expression() override;
|
virtual ~pointer_type_expression() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class record_type_expression : public type_expression
|
class record_type_expression final : public type_expression
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using field_t = std::pair<std::string, type_expression *>;
|
using field_t = std::pair<std::string, type_expression *>;
|
||||||
@ -326,6 +322,8 @@ namespace source
|
|||||||
|
|
||||||
record_type_expression *is_record() override;
|
record_type_expression *is_record() override;
|
||||||
|
|
||||||
|
virtual ~record_type_expression() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
fields_t m_fields;
|
fields_t m_fields;
|
||||||
};
|
};
|
||||||
|
@ -1,100 +0,0 @@
|
|||||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
||||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
||||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include "elna/source/ast.h"
|
|
||||||
#include "elna/source/symbol_table.h"
|
|
||||||
|
|
||||||
namespace elna
|
|
||||||
{
|
|
||||||
namespace source
|
|
||||||
{
|
|
||||||
class name_analysis_visitor final : public empty_visitor
|
|
||||||
{
|
|
||||||
std::shared_ptr<symbol_table> table;
|
|
||||||
const char *filename;
|
|
||||||
std::list<std::unique_ptr<error>> m_errors;
|
|
||||||
const std::size_t pointer_size;
|
|
||||||
|
|
||||||
std::shared_ptr<const type> convert_declaration_type(const type_expression& ast_type) const;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* \param table Symbol table.
|
|
||||||
* \param path Source filename.
|
|
||||||
* \param target_pointer_size Pointer size on the target platform.
|
|
||||||
*/
|
|
||||||
name_analysis_visitor(std::shared_ptr<symbol_table> table, const char *filename,
|
|
||||||
const std::size_t target_pointer_size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \return Collected errors.
|
|
||||||
*/
|
|
||||||
const std::list<std::unique_ptr<error>>& errors() const noexcept;
|
|
||||||
|
|
||||||
void visit(constant_definition *definition) override;
|
|
||||||
void visit(declaration *declaration) override;
|
|
||||||
void visit(program *program) override;
|
|
||||||
void visit(procedure_definition *procedure) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Visitor which allocates registers and stack space for variables and
|
|
||||||
* parameters.
|
|
||||||
*/
|
|
||||||
class allocator_visitor final : public empty_visitor
|
|
||||||
{
|
|
||||||
std::ptrdiff_t local_offset;
|
|
||||||
std::ptrdiff_t argument_offset;
|
|
||||||
std::shared_ptr<symbol_table> table;
|
|
||||||
|
|
||||||
public:
|
|
||||||
allocator_visitor(std::shared_ptr<symbol_table> table);
|
|
||||||
|
|
||||||
void visit(declaration *declaration) override;
|
|
||||||
void visit(program *program) override;
|
|
||||||
void visit(procedure_definition *procedure) override;
|
|
||||||
void visit(call_statement *statement) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This visitor performs the type checking.
|
|
||||||
*/
|
|
||||||
class type_analysis_visitor final : public empty_visitor
|
|
||||||
{
|
|
||||||
std::shared_ptr<symbol_table> table;
|
|
||||||
const char *filename;
|
|
||||||
const std::size_t pointer_size;
|
|
||||||
std::list<std::unique_ptr<error>> m_errors;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* \param table Symbol table.
|
|
||||||
* \param path Source filename.
|
|
||||||
* \param target_pointer_size Pointer size on the target platform.
|
|
||||||
*/
|
|
||||||
type_analysis_visitor(std::shared_ptr<symbol_table> table, const char *filename,
|
|
||||||
const std::size_t target_pointer_size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \return Collected errors.
|
|
||||||
*/
|
|
||||||
const std::list<std::unique_ptr<error>>& errors() const noexcept;
|
|
||||||
|
|
||||||
void visit(program *program) override;
|
|
||||||
void visit(procedure_definition *procedure) override;
|
|
||||||
void visit(integer_literal *literal) override;
|
|
||||||
void visit(boolean_literal *literal) override;
|
|
||||||
void visit(variable_expression *expression) override;
|
|
||||||
void visit(unary_expression *expression) override;
|
|
||||||
void visit(binary_expression *expression) override;
|
|
||||||
void visit(call_statement *statement) override;
|
|
||||||
void visit(constant_definition *definition) override;
|
|
||||||
void visit(while_statement *statement) override;
|
|
||||||
void visit(if_statement *statement) override;
|
|
||||||
void visit(assign_statement *statement) override;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,198 +0,0 @@
|
|||||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
||||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
||||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace elna
|
|
||||||
{
|
|
||||||
namespace source
|
|
||||||
{
|
|
||||||
class symbol_table;
|
|
||||||
class type_info;
|
|
||||||
class typed_info;
|
|
||||||
class constant_info;
|
|
||||||
class variable_info;
|
|
||||||
class parameter_info;
|
|
||||||
class intrinsic_info;
|
|
||||||
class procedure_info;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generic language entity information.
|
|
||||||
*/
|
|
||||||
class info
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~info() = 0;
|
|
||||||
|
|
||||||
virtual type_info *is_type_info() noexcept;
|
|
||||||
virtual typed_info *is_typed_info() noexcept;
|
|
||||||
virtual constant_info *is_constant_info() noexcept;
|
|
||||||
virtual variable_info *is_variable_info() noexcept;
|
|
||||||
virtual parameter_info *is_parameter_info() noexcept;
|
|
||||||
virtual intrinsic_info *is_intrinsic_info() noexcept;
|
|
||||||
virtual procedure_info *is_procedure_info() noexcept;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
info();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Type information.
|
|
||||||
*/
|
|
||||||
class type_info final : public info
|
|
||||||
{
|
|
||||||
std::shared_ptr<const class type> m_type;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit type_info(std::shared_ptr<class type> type);
|
|
||||||
~type_info() override;
|
|
||||||
|
|
||||||
virtual type_info *is_type_info() noexcept override;
|
|
||||||
std::shared_ptr<const class type> type() const noexcept;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Information for a typed symbol.
|
|
||||||
*/
|
|
||||||
class typed_info : public info
|
|
||||||
{
|
|
||||||
std::shared_ptr<const class type> m_type;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
typed_info(std::shared_ptr<const class type> type);
|
|
||||||
|
|
||||||
public:
|
|
||||||
~typed_info() override;
|
|
||||||
|
|
||||||
virtual typed_info *is_typed_info() noexcept override;
|
|
||||||
std::shared_ptr<const class type> type() const noexcept;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constant information.
|
|
||||||
*/
|
|
||||||
class constant_info final : public typed_info
|
|
||||||
{
|
|
||||||
std::int32_t m_value;
|
|
||||||
|
|
||||||
public:
|
|
||||||
constant_info(std::shared_ptr<const class type> type, const std::int32_t value);
|
|
||||||
|
|
||||||
virtual constant_info *is_constant_info() noexcept override;
|
|
||||||
std::int32_t value() const noexcept;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Variable information.
|
|
||||||
*/
|
|
||||||
class variable_info final : public typed_info
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
std::ptrdiff_t offset{ 0 };
|
|
||||||
|
|
||||||
explicit variable_info(std::shared_ptr<const class type> type);
|
|
||||||
|
|
||||||
virtual variable_info *is_variable_info() noexcept override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Procedure parameter information.
|
|
||||||
*/
|
|
||||||
class parameter_info final : public typed_info
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
std::ptrdiff_t offset{ 0 };
|
|
||||||
|
|
||||||
explicit parameter_info(std::shared_ptr<const class type> type);
|
|
||||||
|
|
||||||
virtual parameter_info *is_parameter_info() noexcept override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Intrinsic and external procedure information.
|
|
||||||
*/
|
|
||||||
class intrinsic_info : public info
|
|
||||||
{
|
|
||||||
std::shared_ptr<const class procedure_type> m_type;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit intrinsic_info(const class procedure_type& type);
|
|
||||||
~intrinsic_info() override;
|
|
||||||
|
|
||||||
std::shared_ptr<const class procedure_type> type() const noexcept;
|
|
||||||
std::size_t parameter_stack_size() const noexcept;
|
|
||||||
virtual intrinsic_info *is_intrinsic_info() noexcept override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Procedure information.
|
|
||||||
*/
|
|
||||||
class procedure_info final : public intrinsic_info
|
|
||||||
{
|
|
||||||
std::shared_ptr<symbol_table> local_table;
|
|
||||||
|
|
||||||
public:
|
|
||||||
std::size_t local_stack_size{ 0 };
|
|
||||||
std::size_t argument_stack_size{ 0 };
|
|
||||||
|
|
||||||
procedure_info(const class procedure_type& type, std::shared_ptr<symbol_table> outer_scope);
|
|
||||||
~procedure_info() override;
|
|
||||||
|
|
||||||
std::shared_ptr<symbol_table> scope();
|
|
||||||
std::size_t stack_size() const noexcept;
|
|
||||||
virtual procedure_info *is_procedure_info() noexcept override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Symbol table.
|
|
||||||
*/
|
|
||||||
class symbol_table
|
|
||||||
{
|
|
||||||
std::unordered_map<std::string, std::shared_ptr<info>> entries;
|
|
||||||
std::shared_ptr<symbol_table> outer_scope;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Constructs a new symbol with an optional outer scope.
|
|
||||||
*
|
|
||||||
* \param scope Outer scope.
|
|
||||||
*/
|
|
||||||
explicit symbol_table(std::shared_ptr<symbol_table> scope = nullptr);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Looks for symbol in the table by name. Returns nullptr if the symbol
|
|
||||||
* can not be found.
|
|
||||||
*
|
|
||||||
* \param name Symbol name.
|
|
||||||
* \return Symbol from the table if found.
|
|
||||||
*/
|
|
||||||
std::shared_ptr<info> lookup(const std::string& name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers new symbol.
|
|
||||||
*
|
|
||||||
* \param name Symbol name.
|
|
||||||
* \param entry Symbol information.
|
|
||||||
*/
|
|
||||||
void enter(const std::string& name, std::shared_ptr<info> entry);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the outer scope or nullptr if the this is the global scope.
|
|
||||||
*
|
|
||||||
* \return Outer scope.
|
|
||||||
*/
|
|
||||||
std::shared_ptr<symbol_table> scope();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a symbol table with predefined symbols.
|
|
||||||
*
|
|
||||||
* \return A symbol table with predefined symbols.
|
|
||||||
*/
|
|
||||||
std::shared_ptr<source::symbol_table> add_builtin_symbols();}
|
|
||||||
}
|
|
@ -280,11 +280,6 @@ namespace source
|
|||||||
return *m_base;
|
return *m_base;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& array_type_expression::base_name()
|
|
||||||
{
|
|
||||||
return base().base_name();
|
|
||||||
}
|
|
||||||
|
|
||||||
array_type_expression *array_type_expression::is_array()
|
array_type_expression *array_type_expression::is_array()
|
||||||
{
|
{
|
||||||
return this;
|
return this;
|
||||||
@ -310,11 +305,6 @@ namespace source
|
|||||||
return *m_base;
|
return *m_base;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& pointer_type_expression::base_name()
|
|
||||||
{
|
|
||||||
return base().base_name();
|
|
||||||
}
|
|
||||||
|
|
||||||
pointer_type_expression *pointer_type_expression::is_pointer()
|
pointer_type_expression *pointer_type_expression::is_pointer()
|
||||||
{
|
{
|
||||||
return this;
|
return this;
|
||||||
@ -346,6 +336,14 @@ namespace source
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
record_type_expression::~record_type_expression()
|
||||||
|
{
|
||||||
|
for (auto& field_declaration : fields())
|
||||||
|
{
|
||||||
|
delete field_declaration.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
declaration::declaration(const struct position position, const std::string& identifier,
|
declaration::declaration(const struct position position, const std::string& identifier,
|
||||||
type_expression *type)
|
type_expression *type)
|
||||||
: definition(position, identifier), m_type(type)
|
: definition(position, identifier), m_type(type)
|
||||||
@ -721,9 +719,6 @@ namespace source
|
|||||||
case '@':
|
case '@':
|
||||||
this->m_operator = unary_operator::reference;
|
this->m_operator = unary_operator::reference;
|
||||||
break;
|
break;
|
||||||
case '^':
|
|
||||||
this->m_operator = unary_operator::dereference;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
@ -99,6 +99,8 @@
|
|||||||
%type <elna::source::type_definition *> type_definition;
|
%type <elna::source::type_definition *> type_definition;
|
||||||
%type <std::vector<elna::source::type_definition *>> type_definitions type_part;
|
%type <std::vector<elna::source::type_definition *>> type_definitions type_part;
|
||||||
%type <elna::source::block *> block;
|
%type <elna::source::block *> block;
|
||||||
|
%type <std::pair<std::string, elna::source::type_expression *>> field_declaration;
|
||||||
|
%type <std::vector<std::pair<std::string, elna::source::type_expression *>>> field_list;
|
||||||
%%
|
%%
|
||||||
program:
|
program:
|
||||||
type_part constant_part procedure_part variable_part compound_statement DOT
|
type_part constant_part procedure_part variable_part compound_statement DOT
|
||||||
@ -223,37 +225,31 @@ summand:
|
|||||||
factor:
|
factor:
|
||||||
AT pointer
|
AT pointer
|
||||||
{
|
{
|
||||||
$$ = new elna::source::unary_expression(elna::source::make_position(@1),
|
$$ = new elna::source::unary_expression(elna::source::make_position(@1), $2, '@');
|
||||||
$2, '@');
|
|
||||||
}
|
}
|
||||||
| pointer { $$ = $1; }
|
| pointer { $$ = $1; }
|
||||||
comparand:
|
comparand:
|
||||||
summand PLUS summand
|
summand PLUS summand
|
||||||
{
|
{
|
||||||
$$ = new elna::source::binary_expression(elna::source::make_position(@1),
|
$$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '+');
|
||||||
$1, $3, '+');
|
|
||||||
}
|
}
|
||||||
| summand MINUS summand
|
| summand MINUS summand
|
||||||
{
|
{
|
||||||
$$ = new elna::source::binary_expression(elna::source::make_position(@1),
|
$$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '-');
|
||||||
$1, $3, '-');
|
|
||||||
}
|
}
|
||||||
| summand { $$ = std::move($1); }
|
| summand { $$ = std::move($1); }
|
||||||
expression:
|
expression:
|
||||||
comparand EQUALS comparand
|
comparand EQUALS comparand
|
||||||
{
|
{
|
||||||
$$ = new elna::source::binary_expression(elna::source::make_position(@1),
|
$$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '=');
|
||||||
$1, $3, '=');
|
|
||||||
}
|
}
|
||||||
| comparand NOT_EQUAL comparand
|
| comparand NOT_EQUAL comparand
|
||||||
{
|
{
|
||||||
$$ = new elna::source::binary_expression(elna::source::make_position(@1),
|
$$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, 'n');
|
||||||
$1, $3, 'n');
|
|
||||||
}
|
}
|
||||||
| comparand LESS_THAN comparand
|
| comparand LESS_THAN comparand
|
||||||
{
|
{
|
||||||
$$ = new elna::source::binary_expression(elna::source::make_position(@1),
|
$$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '<');
|
||||||
$1, $3, '<');
|
|
||||||
}
|
}
|
||||||
| comparand GREATER_THAN comparand
|
| comparand GREATER_THAN comparand
|
||||||
{
|
{
|
||||||
@ -305,12 +301,21 @@ statements:
|
|||||||
statement SEMICOLON statements
|
statement SEMICOLON statements
|
||||||
{
|
{
|
||||||
std::swap($$, $3);
|
std::swap($$, $3);
|
||||||
$$.emplace($$.cbegin(), std::move($1));
|
$$.emplace($$.cbegin(), $1);
|
||||||
}
|
}
|
||||||
| statement { $$.emplace_back($1); }
|
| statement { $$.push_back($1); }
|
||||||
optional_statements:
|
optional_statements:
|
||||||
statements { std::swap($$, $1); }
|
statements { std::swap($$, $1); }
|
||||||
| /* no statements */ {}
|
| /* no statements */ {}
|
||||||
|
field_declaration:
|
||||||
|
IDENTIFIER COLON type_expression { $$ = std::make_pair($1, $3); }
|
||||||
|
field_list:
|
||||||
|
field_declaration SEMICOLON field_list
|
||||||
|
{
|
||||||
|
std::swap($$, $3);
|
||||||
|
$$.emplace($$.cbegin(), $1);
|
||||||
|
}
|
||||||
|
| field_declaration { $$.emplace_back($1); }
|
||||||
type_expression:
|
type_expression:
|
||||||
ARRAY INTEGER OF type_expression
|
ARRAY INTEGER OF type_expression
|
||||||
{
|
{
|
||||||
@ -320,6 +325,10 @@ type_expression:
|
|||||||
{
|
{
|
||||||
$$ = new elna::source::pointer_type_expression(elna::source::make_position(@1), $2);
|
$$ = new elna::source::pointer_type_expression(elna::source::make_position(@1), $2);
|
||||||
}
|
}
|
||||||
|
| RECORD field_list END_BLOCK
|
||||||
|
{
|
||||||
|
$$ = new elna::source::record_type_expression(elna::source::make_position(@1), std::move($2));
|
||||||
|
}
|
||||||
| IDENTIFIER
|
| IDENTIFIER
|
||||||
{
|
{
|
||||||
$$ = new elna::source::basic_type_expression(elna::source::make_position(@1), $1);
|
$$ = new elna::source::basic_type_expression(elna::source::make_position(@1), $1);
|
||||||
|
@ -1,325 +0,0 @@
|
|||||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
||||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
||||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
#include "elna/source/semantic.h"
|
|
||||||
#include "elna/source/result.h"
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
namespace elna
|
|
||||||
{
|
|
||||||
namespace source
|
|
||||||
{
|
|
||||||
name_analysis_visitor::name_analysis_visitor(std::shared_ptr<symbol_table> table,
|
|
||||||
const char *filename, const std::size_t target_pointer_size)
|
|
||||||
: table(table), filename(filename), pointer_size(target_pointer_size)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void name_analysis_visitor::visit(constant_definition *definition)
|
|
||||||
{
|
|
||||||
auto constant_type = std::make_shared<const class primitive_type>(int_type);
|
|
||||||
this->table->enter(definition->identifier(),
|
|
||||||
std::make_shared<constant_info>(constant_type, definition->body().number()));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<const type> name_analysis_visitor::convert_declaration_type(const type_expression& ast_type) const
|
|
||||||
{
|
|
||||||
auto variable_type = table->lookup(ast_type.base())->is_type_info()->type();
|
|
||||||
std::shared_ptr<type> declaration_type;
|
|
||||||
|
|
||||||
if (ast_type.is_pointer())
|
|
||||||
{
|
|
||||||
return std::make_shared<pointer_type>(variable_type, 4);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return variable_type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void name_analysis_visitor::visit(declaration *declarationx)
|
|
||||||
{
|
|
||||||
std::shared_ptr<const type> declaration_type = convert_declaration_type(declarationx->type());
|
|
||||||
|
|
||||||
this->table->enter(declarationx->identifier(),
|
|
||||||
std::make_shared<variable_info>(declaration_type));
|
|
||||||
}
|
|
||||||
|
|
||||||
void name_analysis_visitor::visit(program *program)
|
|
||||||
{
|
|
||||||
class procedure_type main_type{ std::vector<std::shared_ptr<const class type>>(), this->pointer_size };
|
|
||||||
this->table->enter("_start", std::make_shared<procedure_info>(main_type, this->table));
|
|
||||||
empty_visitor::visit(program);
|
|
||||||
}
|
|
||||||
|
|
||||||
void name_analysis_visitor::visit(procedure_definition *procedure)
|
|
||||||
{
|
|
||||||
std::vector<std::shared_ptr<const type>> arguments;
|
|
||||||
|
|
||||||
for (auto& parameter : procedure->parameters())
|
|
||||||
{
|
|
||||||
auto declaration_type = convert_declaration_type(parameter->type());
|
|
||||||
arguments.push_back(declaration_type);
|
|
||||||
}
|
|
||||||
procedure_type definition_type{ std::move(arguments), this->pointer_size };
|
|
||||||
auto info = std::make_shared<procedure_info>(definition_type, this->table);
|
|
||||||
|
|
||||||
this->table->enter(procedure->identifier(), info);
|
|
||||||
this->table = info->scope();
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < procedure->parameters().size(); ++i)
|
|
||||||
{
|
|
||||||
this->table->enter(procedure->parameters().at(i)->identifier(),
|
|
||||||
std::make_shared<parameter_info>(definition_type.arguments.at(i)));
|
|
||||||
}
|
|
||||||
procedure->body().accept(this);
|
|
||||||
|
|
||||||
this->table = info->scope()->scope();
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::list<std::unique_ptr<error>>& name_analysis_visitor::errors() const noexcept
|
|
||||||
{
|
|
||||||
return m_errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
allocator_visitor::allocator_visitor(std::shared_ptr<symbol_table> table)
|
|
||||||
: table(table)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void allocator_visitor::visit(declaration *declaration)
|
|
||||||
{
|
|
||||||
auto declaration_info = this->table->lookup(declaration->identifier());
|
|
||||||
|
|
||||||
if (auto variable = declaration_info->is_variable_info())
|
|
||||||
{
|
|
||||||
this->local_offset -= sizeof(std::int32_t);
|
|
||||||
variable->offset = this->local_offset;
|
|
||||||
}
|
|
||||||
else if (auto parameter = declaration_info->is_parameter_info())
|
|
||||||
{
|
|
||||||
parameter->offset = this->argument_offset;
|
|
||||||
this->argument_offset += sizeof(std::int32_t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void allocator_visitor::visit(program *program)
|
|
||||||
{
|
|
||||||
this->local_offset = 0;
|
|
||||||
this->argument_offset = 0;
|
|
||||||
|
|
||||||
empty_visitor::visit(program);
|
|
||||||
table->lookup("_start")->is_procedure_info()->local_stack_size =
|
|
||||||
std::abs(this->local_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void allocator_visitor::visit(procedure_definition *procedure)
|
|
||||||
{
|
|
||||||
this->local_offset = 0;
|
|
||||||
this->argument_offset = 0;
|
|
||||||
auto info = this->table->lookup(procedure->identifier())->is_procedure_info();
|
|
||||||
this->table = info->scope();
|
|
||||||
|
|
||||||
empty_visitor::visit(procedure);
|
|
||||||
|
|
||||||
this->table = info->scope()->scope();
|
|
||||||
info->local_stack_size = std::abs(this->local_offset);
|
|
||||||
info->argument_stack_size = this->argument_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void allocator_visitor::visit(call_statement *statement)
|
|
||||||
{
|
|
||||||
auto call_info = this->table->lookup(statement->name())->is_intrinsic_info();
|
|
||||||
|
|
||||||
this->argument_offset = std::max(static_cast<std::size_t>(this->argument_offset),
|
|
||||||
call_info->parameter_stack_size());
|
|
||||||
}
|
|
||||||
|
|
||||||
type_analysis_visitor::type_analysis_visitor(std::shared_ptr<symbol_table> table,
|
|
||||||
const char *filename, const std::size_t target_pointer_size)
|
|
||||||
: table(table), filename(filename), pointer_size(target_pointer_size)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void type_analysis_visitor::visit(program *program)
|
|
||||||
{
|
|
||||||
for (auto& definition : program->definitions())
|
|
||||||
{
|
|
||||||
definition->accept(this);
|
|
||||||
}
|
|
||||||
program->body().accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void type_analysis_visitor::visit(procedure_definition *procedure)
|
|
||||||
{
|
|
||||||
auto info = this->table->lookup(procedure->identifier())->is_procedure_info();
|
|
||||||
this->table = info->scope();
|
|
||||||
|
|
||||||
procedure->body().accept(this);
|
|
||||||
|
|
||||||
this->table = info->scope()->scope();
|
|
||||||
}
|
|
||||||
|
|
||||||
void type_analysis_visitor::visit(integer_literal *literal)
|
|
||||||
{
|
|
||||||
literal->data_type = table->lookup("Int")->is_type_info()->type();
|
|
||||||
}
|
|
||||||
|
|
||||||
void type_analysis_visitor::visit(boolean_literal *literal)
|
|
||||||
{
|
|
||||||
literal->data_type = table->lookup("Boolean")->is_type_info()->type();
|
|
||||||
}
|
|
||||||
|
|
||||||
void type_analysis_visitor::visit(variable_expression *expression)
|
|
||||||
{
|
|
||||||
expression->data_type = table->lookup(expression->name())->is_typed_info()->type();
|
|
||||||
}
|
|
||||||
|
|
||||||
void type_analysis_visitor::visit(unary_expression *expression)
|
|
||||||
{
|
|
||||||
empty_visitor::visit(expression);
|
|
||||||
|
|
||||||
switch (expression->operation())
|
|
||||||
{
|
|
||||||
case unary_operator::reference:
|
|
||||||
expression->data_type = std::make_shared<const pointer_type>(expression->operand().data_type,
|
|
||||||
this->pointer_size);
|
|
||||||
break;
|
|
||||||
case unary_operator::dereference:
|
|
||||||
auto operand_type = expression->operand().data_type;
|
|
||||||
|
|
||||||
if (operand_type->is_pointer_type() != nullptr)
|
|
||||||
{
|
|
||||||
expression->data_type = operand_type;
|
|
||||||
}
|
|
||||||
else if (operand_type != nullptr)
|
|
||||||
{
|
|
||||||
auto new_error = std::make_unique<type_mismatch>(operand_type,
|
|
||||||
type_mismatch::operation::dereference, this->filename, expression->position());
|
|
||||||
m_errors.push_back(std::move(new_error));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void type_analysis_visitor::visit(binary_expression *expression)
|
|
||||||
{
|
|
||||||
empty_visitor::visit(expression);
|
|
||||||
|
|
||||||
switch (expression->operation())
|
|
||||||
{
|
|
||||||
case binary_operator::sum:
|
|
||||||
case binary_operator::subtraction:
|
|
||||||
case binary_operator::multiplication:
|
|
||||||
case binary_operator::division:
|
|
||||||
case binary_operator::less:
|
|
||||||
case binary_operator::greater:
|
|
||||||
case binary_operator::less_equal:
|
|
||||||
case binary_operator::greater_equal:
|
|
||||||
if (expression->lhs().data_type != nullptr && expression->rhs().data_type != nullptr)
|
|
||||||
{
|
|
||||||
std::unique_ptr<type_mismatch> new_error;
|
|
||||||
|
|
||||||
if (*expression->lhs().data_type != int_type)
|
|
||||||
{
|
|
||||||
new_error = std::make_unique<type_mismatch>(expression->lhs().data_type,
|
|
||||||
type_mismatch::operation::arithmetic, this->filename, expression->lhs().position());
|
|
||||||
}
|
|
||||||
if (*expression->rhs().data_type != int_type)
|
|
||||||
{
|
|
||||||
new_error = std::make_unique<type_mismatch>(expression->rhs().data_type,
|
|
||||||
type_mismatch::operation::arithmetic, this->filename, expression->rhs().position());
|
|
||||||
}
|
|
||||||
if (new_error != nullptr)
|
|
||||||
{
|
|
||||||
m_errors.push_back(std::move(new_error));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case binary_operator::equals:
|
|
||||||
case binary_operator::not_equals:
|
|
||||||
if (expression->lhs().data_type != nullptr && expression->rhs().data_type != nullptr)
|
|
||||||
{
|
|
||||||
if (expression->lhs().data_type != expression->rhs().data_type)
|
|
||||||
{
|
|
||||||
auto new_error = std::make_unique<type_mismatch>(expression->rhs().data_type,
|
|
||||||
type_mismatch::operation::comparison, this->filename, expression->rhs().position());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void type_analysis_visitor::visit(call_statement *statement)
|
|
||||||
{
|
|
||||||
auto call_info = this->table->lookup(statement->name())->is_intrinsic_info();
|
|
||||||
|
|
||||||
std::size_t i{ 0 };
|
|
||||||
for (const auto& argument : statement->arguments())
|
|
||||||
{
|
|
||||||
argument->accept(this);
|
|
||||||
|
|
||||||
if (argument->data_type != nullptr && i < call_info->type()->arguments.size()
|
|
||||||
&& call_info->type()->arguments[i] != argument->data_type)
|
|
||||||
{
|
|
||||||
auto new_error = std::make_unique<type_mismatch>(argument->data_type,
|
|
||||||
type_mismatch::operation::argument, this->filename, argument->position());
|
|
||||||
m_errors.push_back(std::move(new_error));
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void type_analysis_visitor::visit(constant_definition *definition)
|
|
||||||
{
|
|
||||||
definition->body().accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void type_analysis_visitor::visit(while_statement *statement)
|
|
||||||
{
|
|
||||||
statement->prerequisite().accept(this);
|
|
||||||
auto condition_type = statement->prerequisite().data_type;
|
|
||||||
|
|
||||||
if (condition_type != nullptr && *condition_type != boolean_type)
|
|
||||||
{
|
|
||||||
auto new_error = std::make_unique<type_mismatch>(condition_type,
|
|
||||||
type_mismatch::operation::condition, this->filename, statement->prerequisite().position());
|
|
||||||
m_errors.push_back(std::move(new_error));
|
|
||||||
}
|
|
||||||
statement->body().accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void type_analysis_visitor::visit(if_statement *statement)
|
|
||||||
{
|
|
||||||
statement->prerequisite().accept(this);
|
|
||||||
auto condition_type = statement->prerequisite().data_type;
|
|
||||||
|
|
||||||
if (condition_type != nullptr && *condition_type != boolean_type)
|
|
||||||
{
|
|
||||||
auto new_error = std::make_unique<type_mismatch>(condition_type,
|
|
||||||
type_mismatch::operation::condition, this->filename, statement->prerequisite().position());
|
|
||||||
m_errors.push_back(std::move(new_error));
|
|
||||||
}
|
|
||||||
statement->body().accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void type_analysis_visitor::visit(assign_statement *statement)
|
|
||||||
{
|
|
||||||
statement->rvalue().accept(this);
|
|
||||||
auto lvalue_info = this->table->lookup(statement->lvalue())->is_typed_info();
|
|
||||||
|
|
||||||
if (statement->rvalue().data_type != nullptr && lvalue_info->type() == statement->rvalue().data_type)
|
|
||||||
{
|
|
||||||
auto new_error = std::make_unique<type_mismatch>(statement->rvalue().data_type,
|
|
||||||
type_mismatch::operation::assignment, this->filename, statement->position());
|
|
||||||
m_errors.push_back(std::move(new_error));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::list<std::unique_ptr<error>>& type_analysis_visitor::errors() const noexcept
|
|
||||||
{
|
|
||||||
return m_errors;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,233 +0,0 @@
|
|||||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
||||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
||||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
#include "elna/source/types.h"
|
|
||||||
#include "elna/source/symbol_table.h"
|
|
||||||
|
|
||||||
namespace elna
|
|
||||||
{
|
|
||||||
namespace source
|
|
||||||
{
|
|
||||||
symbol_table::symbol_table(std::shared_ptr<symbol_table> scope)
|
|
||||||
: outer_scope(scope)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<info> symbol_table::lookup(const std::string& name)
|
|
||||||
{
|
|
||||||
auto entry = entries.find(name);
|
|
||||||
|
|
||||||
if (entry != entries.cend())
|
|
||||||
{
|
|
||||||
return entry->second;
|
|
||||||
}
|
|
||||||
if (this->outer_scope != nullptr)
|
|
||||||
{
|
|
||||||
return this->outer_scope->lookup(name);
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void symbol_table::enter(const std::string& name, std::shared_ptr<info> entry)
|
|
||||||
{
|
|
||||||
entries.insert({ name, entry });
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<symbol_table> symbol_table::scope()
|
|
||||||
{
|
|
||||||
return this->outer_scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
info::~info()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
type_info *info::is_type_info() noexcept
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
typed_info *info::is_typed_info() noexcept
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
constant_info *info::is_constant_info() noexcept
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
variable_info *info::is_variable_info() noexcept
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
parameter_info *info::is_parameter_info() noexcept
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
intrinsic_info *info::is_intrinsic_info() noexcept
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
procedure_info *info::is_procedure_info() noexcept
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
info::info()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
type_info::type_info(std::shared_ptr<class type> type)
|
|
||||||
: info(), m_type(type)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
type_info::~type_info()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<const class type> type_info::type() const noexcept
|
|
||||||
{
|
|
||||||
return m_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
type_info *type_info::is_type_info() noexcept
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
typed_info::typed_info(std::shared_ptr<const class type> type)
|
|
||||||
: m_type(type)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
typed_info::~typed_info()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
typed_info *typed_info::is_typed_info() noexcept
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<const class type> typed_info::type() const noexcept
|
|
||||||
{
|
|
||||||
return m_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
constant_info::constant_info(const std::shared_ptr<const class type> type, const std::int32_t value)
|
|
||||||
: typed_info(type), m_value(value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
constant_info *constant_info::is_constant_info() noexcept
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::int32_t constant_info::value() const noexcept
|
|
||||||
{
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
variable_info::variable_info(std::shared_ptr<const class type> type)
|
|
||||||
: typed_info(type)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
variable_info *variable_info::is_variable_info() noexcept
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
parameter_info::parameter_info(std::shared_ptr<const class type> type)
|
|
||||||
: typed_info(type)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
parameter_info *parameter_info::is_parameter_info() noexcept
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
intrinsic_info::intrinsic_info(const class procedure_type& type)
|
|
||||||
: m_type(std::make_shared<procedure_type>(type))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
intrinsic_info::~intrinsic_info()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<const class procedure_type> intrinsic_info::type() const noexcept
|
|
||||||
{
|
|
||||||
return m_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t intrinsic_info::parameter_stack_size() const noexcept
|
|
||||||
{
|
|
||||||
return type()->arguments.size() * sizeof(std::int32_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
intrinsic_info *intrinsic_info::is_intrinsic_info() noexcept
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
procedure_info::procedure_info(const class procedure_type& type, std::shared_ptr<symbol_table> outer_scope)
|
|
||||||
: intrinsic_info(type), local_table(std::make_shared<symbol_table>(outer_scope))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
procedure_info::~procedure_info()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<symbol_table> procedure_info::scope()
|
|
||||||
{
|
|
||||||
return local_table;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t procedure_info::stack_size() const noexcept
|
|
||||||
{
|
|
||||||
return local_stack_size + argument_stack_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
procedure_info *procedure_info::is_procedure_info() noexcept
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr std::size_t pointer_size = 4;
|
|
||||||
|
|
||||||
std::shared_ptr<source::symbol_table> add_builtin_symbols()
|
|
||||||
{
|
|
||||||
source::symbol_table result;
|
|
||||||
std::vector<std::shared_ptr<const source::type>> intrinsic_arguments;
|
|
||||||
|
|
||||||
auto prim = boolean_type;
|
|
||||||
auto boolean_info = std::make_shared<type_info>(std::make_shared<primitive_type>(boolean_type));
|
|
||||||
auto int_info = std::make_shared<source::type_info>(std::make_shared<primitive_type>(int_type));
|
|
||||||
result.enter("Boolean", boolean_info);
|
|
||||||
result.enter("Int", int_info);
|
|
||||||
|
|
||||||
intrinsic_arguments.push_back(int_info->type());
|
|
||||||
auto writei = std::make_shared<source::intrinsic_info>(
|
|
||||||
source::procedure_type{ intrinsic_arguments, pointer_size });
|
|
||||||
result.enter("writei", writei);
|
|
||||||
intrinsic_arguments.clear();
|
|
||||||
|
|
||||||
intrinsic_arguments.push_back(boolean_info->type());
|
|
||||||
auto writeb = std::make_shared<source::intrinsic_info>(
|
|
||||||
source::procedure_type{ intrinsic_arguments, pointer_size });
|
|
||||||
result.enter("writeb", writeb);
|
|
||||||
intrinsic_arguments.clear();
|
|
||||||
|
|
||||||
return std::make_shared<source::symbol_table>(std::move(result));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user