diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ad72d2..a1d5c5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,13 +3,15 @@ project(Elna) set(CMAKE_EXPORT_COMPILE_COMMANDS 1) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 14) -find_package(Boost CONFIG COMPONENTS process program_options REQUIRED) +# find_package(Boost CONFIG COMPONENTS process program_options REQUIRED) find_package(FLEX REQUIRED) find_package(BISON REQUIRED) -include_directories(${Boost_INCLUDE_DIR}) +# include_directories(${Boost_INCLUDE_DIR}) + +link_libraries(stdc++fs) FLEX_TARGET(lexer source/lexer.ll ${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp) BISON_TARGET(parser source/parser.yy ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp) @@ -22,7 +24,8 @@ add_executable(elna cli/main.cpp source/symbol_table.cpp include/elna/source/symbol_table.hpp source/result.cpp include/elna/source/result.hpp source/semantic.cpp include/elna/source/semantic.hpp + cli/cl.cpp include/elna/cli/cl.hpp ${BISON_parser_OUTPUTS} ${FLEX_lexer_OUTPUTS} ) target_include_directories(elna PRIVATE ${CMAKE_CURRENT_BINARY_DIR} include) -target_link_libraries(elna LINK_PUBLIC ${Boost_LIBRARIES}) +# target_link_libraries(elna LINK_PUBLIC ${Boost_LIBRARIES}) diff --git a/cli/cl.cpp b/cli/cl.cpp new file mode 100644 index 0000000..c27aff5 --- /dev/null +++ b/cli/cl.cpp @@ -0,0 +1,43 @@ +#include "elna/cli/cl.hpp" +#include "elna/source/types.hpp" +#include + +namespace elna +{ +namespace cli +{ + void print_error(const std::unique_ptr& compile_error) + { + std::cerr << compile_error->path().string() << ":" + << compile_error->line() << ':' << compile_error->column() + << ": " << compile_error->what() << std::endl; + } + + constexpr std::size_t pointer_size = 4; + + std::shared_ptr add_builtin_symbols() + { + source::symbol_table result; + std::vector> intrinsic_arguments; + + auto boolean_info = std::make_shared(source::boolean_type); + auto int_info = std::make_shared(source::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::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::procedure_type{ intrinsic_arguments, pointer_size }); + result.enter("writeb", writeb); + intrinsic_arguments.clear(); + + return std::make_shared(std::move(result)); + } +} +} diff --git a/cli/main.cpp b/cli/main.cpp index 6da37e7..085ae2f 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -1,21 +1,22 @@ #include +#include "elna/source/semantic.hpp" +#include "elna/cli/cl.hpp" #include "parser.hpp" #include +constexpr std::size_t pointer_size = 4; + int main() { elna::source::driver driver{ "-" }; std::istringstream inp(R"( - const world = 5, hello = 7; - var x: int, y: boolean; + var x: Int; proc f(); begin - x := 8 end; begin - while false do inc(5) end. )"); @@ -33,6 +34,12 @@ int main() } return result; } + auto symbol_table = elna::cli::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()) { if (auto const_definition = dynamic_cast(definition.get())) diff --git a/include/elna/cli/cl.hpp b/include/elna/cli/cl.hpp new file mode 100644 index 0000000..9943304 --- /dev/null +++ b/include/elna/cli/cl.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include +#include "elna/source/symbol_table.hpp" +#include "elna/source/result.hpp" + +namespace elna +{ +namespace cli +{ + /** + * Formats and prints the given error. + * + * \param compile_error The error to print. + */ + void print_error(const std::unique_ptr& compile_error); + + /** + * Prints the given errors to the standard output. + * + * \param begin Pointer to the first error. + * \param end Pointer pass the last error. + */ + template + void print_errors(I begin, I end) + { + std::for_each(begin, end, &print_error); + } + + /** + * Creates a symbol table with predefined symbols. + * + * \return A symbol table with predefined symbols. + */ + std::shared_ptr add_builtin_symbols(); +} +} diff --git a/include/elna/source/ast.hpp b/include/elna/source/ast.hpp index c58effb..7fa0681 100644 --- a/include/elna/source/ast.hpp +++ b/include/elna/source/ast.hpp @@ -4,7 +4,9 @@ #include "elna/source/result.hpp" #include "elna/source/types.hpp" -namespace elna::source +namespace elna +{ +namespace source { enum class binary_operator { @@ -481,3 +483,4 @@ namespace elna::source unary_operator operation() const noexcept; }; } +} diff --git a/include/elna/source/driver.hpp b/include/elna/source/driver.hpp index e91938f..f1b99fd 100644 --- a/include/elna/source/driver.hpp +++ b/include/elna/source/driver.hpp @@ -4,7 +4,9 @@ #include "elna/source/ast.hpp" #include "location.hh" -namespace elna::source +namespace elna +{ +namespace source { position make_position(const yy::location& location); @@ -14,7 +16,7 @@ namespace elna::source public: syntax_error(const std::string& message, - const std::filesystem::path& input_file, const yy::location& location); + const std::experimental::filesystem::path& input_file, const yy::location& location); virtual std::string what() const override; }; @@ -22,14 +24,15 @@ namespace elna::source class driver { std::list> m_errors; - const std::filesystem::path input_file; + const std::experimental::filesystem::path input_file; public: std::unique_ptr tree; - driver(const std::filesystem::path& input_file); + driver(const std::experimental::filesystem::path& input_file); void error(const yy::location& loc, const std::string& message); const std::list>& errors() const noexcept; }; } +} diff --git a/include/elna/source/result.hpp b/include/elna/source/result.hpp index 2dc9a69..0063fe4 100644 --- a/include/elna/source/result.hpp +++ b/include/elna/source/result.hpp @@ -1,10 +1,12 @@ #pragma once #include -#include +#include #include "elna/source/types.hpp" -namespace elna::source +namespace elna +{ +namespace source { /** * Position in the source text. @@ -24,7 +26,7 @@ namespace elna::source class error { position m_position; - std::filesystem::path m_path; + std::experimental::filesystem::path m_path; protected: /** @@ -33,7 +35,7 @@ namespace elna::source * \param path Source file name. * \param position Error position in the source text. */ - error(const std::filesystem::path& path, const position position); + error(const std::experimental::filesystem::path& path, const position position); public: virtual ~error() noexcept = default; @@ -48,7 +50,7 @@ namespace elna::source std::size_t column() const noexcept; /// Source file name. - const std::filesystem::path& path() const noexcept; + const std::experimental::filesystem::path& path() const noexcept; }; class name_collision final : public error @@ -63,7 +65,7 @@ namespace elna::source * \param current Current symbol position. * \param previous Position of the previously defined symbol. */ - name_collision(const std::string& name, const std::filesystem::path& path, + name_collision(const std::string& name, const std::experimental::filesystem::path& path, const position current, const position previous); std::string what() const override; @@ -90,7 +92,7 @@ namespace elna::source * \param path Source file name. * \param position Operation position. */ - type_mismatch(std::shared_ptr got, operation kind, const std::filesystem::path& path, + type_mismatch(std::shared_ptr got, operation kind, const std::experimental::filesystem::path& path, const struct position position); std::string what() const override; @@ -100,3 +102,4 @@ namespace elna::source operation kind; }; } +} diff --git a/include/elna/source/semantic.hpp b/include/elna/source/semantic.hpp index 752c596..12210db 100644 --- a/include/elna/source/semantic.hpp +++ b/include/elna/source/semantic.hpp @@ -4,12 +4,14 @@ #include "elna/source/ast.hpp" #include "elna/source/symbol_table.hpp" -namespace elna::source +namespace elna +{ +namespace source { class name_analysis_visitor final : public empty_visitor { std::shared_ptr table; - const std::filesystem::path filename; + const std::experimental::filesystem::path filename; std::list> m_errors; const std::size_t pointer_size; @@ -21,7 +23,7 @@ namespace elna::source * \param path Source filename. * \param target_pointer_size Pointer size on the target platform. */ - name_analysis_visitor(std::shared_ptr table, const std::filesystem::path& filename, + name_analysis_visitor(std::shared_ptr table, const std::experimental::filesystem::path& filename, const std::size_t target_pointer_size); /** @@ -60,7 +62,7 @@ namespace elna::source class type_analysis_visitor final : public empty_visitor { std::shared_ptr table; - const std::filesystem::path filename; + const std::experimental::filesystem::path filename; const std::size_t pointer_size; std::list> m_errors; @@ -70,7 +72,7 @@ namespace elna::source * \param path Source filename. * \param target_pointer_size Pointer size on the target platform. */ - type_analysis_visitor(std::shared_ptr table, const std::filesystem::path& filename, + type_analysis_visitor(std::shared_ptr table, const std::experimental::filesystem::path& filename, const std::size_t target_pointer_size); /** @@ -92,3 +94,4 @@ namespace elna::source void visit(assign_statement *statement) override; }; } +} diff --git a/include/elna/source/symbol_table.hpp b/include/elna/source/symbol_table.hpp index f0eb9fa..6e4ef9a 100644 --- a/include/elna/source/symbol_table.hpp +++ b/include/elna/source/symbol_table.hpp @@ -5,7 +5,9 @@ #include #include -namespace elna::source +namespace elna +{ +namespace source { class symbol_table; @@ -159,3 +161,4 @@ namespace elna::source std::shared_ptr scope(); }; } +} diff --git a/include/elna/source/types.hpp b/include/elna/source/types.hpp index 917ddda..d002f18 100644 --- a/include/elna/source/types.hpp +++ b/include/elna/source/types.hpp @@ -4,7 +4,9 @@ #include #include -namespace elna::source +namespace elna +{ +namespace source { /** * Type representation. @@ -94,6 +96,7 @@ namespace elna::source bool operator==(const type& lhs, const type& rhs) noexcept; bool operator!=(const type& lhs, const type& rhs) noexcept; - inline const primitive_type boolean_type{ "Boolean", 1 }; - inline const primitive_type int_type{ "Int", 4 }; + extern const primitive_type boolean_type; + extern const primitive_type int_type; +} } diff --git a/source/ast.cpp b/source/ast.cpp index c6871df..c258549 100644 --- a/source/ast.cpp +++ b/source/ast.cpp @@ -1,7 +1,9 @@ #include "elna/source/ast.hpp" #include -namespace elna::source +namespace elna +{ +namespace source { void empty_visitor::visit(declaration *declaration) { @@ -522,3 +524,4 @@ namespace elna::source return *m_body; } } +} diff --git a/source/driver.cpp b/source/driver.cpp index a83ea8b..d1355ca 100644 --- a/source/driver.cpp +++ b/source/driver.cpp @@ -1,6 +1,8 @@ #include "elna/source/driver.hpp" -namespace elna::source +namespace elna +{ +namespace source { position make_position(const yy::location& location) { @@ -11,7 +13,7 @@ namespace elna::source } syntax_error::syntax_error(const std::string& message, - const std::filesystem::path& input_file, const yy::location& location) + const std::experimental::filesystem::path& input_file, const yy::location& location) : error(input_file, make_position(location)), message(message) { } @@ -21,7 +23,7 @@ namespace elna::source return message; } - driver::driver(const std::filesystem::path& input_file) + driver::driver(const std::experimental::filesystem::path& input_file) : input_file(input_file) { } @@ -36,3 +38,4 @@ namespace elna::source return m_errors; } } +} diff --git a/source/result.cpp b/source/result.cpp index f79e85f..2362d2b 100644 --- a/source/result.cpp +++ b/source/result.cpp @@ -1,8 +1,10 @@ #include "elna/source/result.hpp" -namespace elna::source +namespace elna { - error::error(const std::filesystem::path& path, const position position) +namespace source +{ + error::error(const std::experimental::filesystem::path& path, const position position) : m_position(position), m_path(path) { } @@ -17,12 +19,12 @@ namespace elna::source return this->m_position.column; } - const std::filesystem::path& error::path() const noexcept + const std::experimental::filesystem::path& error::path() const noexcept { return this->m_path; } - name_collision::name_collision(const std::string& name, const std::filesystem::path& path, + name_collision::name_collision(const std::string& name, const std::experimental::filesystem::path& path, const position current, const position previous) : error(path, current), name(name), previous(previous) { @@ -33,8 +35,8 @@ namespace elna::source return "Name '" + name + "' was already defined"; } - type_mismatch::type_mismatch(std::shared_ptr got, operation kind, const std::filesystem::path& path, - const struct position position) + type_mismatch::type_mismatch(std::shared_ptr got, operation kind, + const std::experimental::filesystem::path& path, const struct position position) : error(path, position), kind(kind), got(got) { } @@ -44,3 +46,4 @@ namespace elna::source return "Type cannot be used here."; } } +} diff --git a/source/semantic.cpp b/source/semantic.cpp index 789fd48..6734a01 100644 --- a/source/semantic.cpp +++ b/source/semantic.cpp @@ -2,10 +2,12 @@ #include "elna/source/result.hpp" #include -namespace elna::source +namespace elna +{ +namespace source { name_analysis_visitor::name_analysis_visitor(std::shared_ptr table, - const std::filesystem::path& filename, const std::size_t target_pointer_size) + const std::experimental::filesystem::path& filename, const std::size_t target_pointer_size) : table(table), filename(filename), pointer_size(target_pointer_size) { } @@ -33,11 +35,11 @@ namespace elna::source } } - void name_analysis_visitor::visit(declaration *declaration) + void name_analysis_visitor::visit(declaration *declarationx) { - std::shared_ptr declaration_type = convert_declaration_type(declaration->type()); + std::shared_ptr declaration_type = convert_declaration_type(declarationx->type()); - this->table->enter(declaration->identifier(), + this->table->enter(declarationx->identifier(), std::make_shared(declaration_type)); } @@ -132,7 +134,7 @@ namespace elna::source } type_analysis_visitor::type_analysis_visitor(std::shared_ptr table, - const std::filesystem::path& filename, const std::size_t target_pointer_size) + const std::experimental::filesystem::path& filename, const std::size_t target_pointer_size) : table(table), filename(filename), pointer_size(target_pointer_size) { } @@ -323,3 +325,4 @@ namespace elna::source return m_errors; } } +} diff --git a/source/symbol_table.cpp b/source/symbol_table.cpp index 8801fa7..d404ccb 100644 --- a/source/symbol_table.cpp +++ b/source/symbol_table.cpp @@ -1,7 +1,9 @@ #include "elna/source/types.hpp" #include "elna/source/symbol_table.hpp" -namespace elna::source +namespace elna +{ +namespace source { symbol_table::symbol_table(std::shared_ptr scope) : outer_scope(scope) @@ -25,7 +27,7 @@ namespace elna::source void symbol_table::enter(const std::string& name, std::shared_ptr entry) { - entries.insert_or_assign(name, entry); + entries.insert({ name, entry }); } std::shared_ptr symbol_table::scope() @@ -127,3 +129,4 @@ namespace elna::source return local_stack_size + argument_stack_size; } } +} diff --git a/source/types.cpp b/source/types.cpp index dbc96a9..b99685e 100644 --- a/source/types.cpp +++ b/source/types.cpp @@ -1,6 +1,8 @@ #include -namespace elna::source +namespace elna +{ +namespace source { type::type(const std::size_t byte_size) : byte_size(byte_size) @@ -93,4 +95,8 @@ namespace elna::source { return !(lhs == rhs); } + + const primitive_type boolean_type{ "Boolean", 1 }; + const primitive_type int_type{ "Int", 4 }; +} }