From 40a28059cac4077174719c88acb46d9f901e2e28 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Sat, 21 Dec 2024 14:05:27 +0100 Subject: [PATCH] Parse variable declarations --- CMakeLists.txt | 1 + cli/main.cpp | 33 ++++++++++---- include/elna/source/driver.hpp | 35 +++++++++++++++ source/driver.cpp | 38 ++++++++++++++++ source/lexer.ll | 6 +-- source/parser.yy | 79 +++++++++++++++++----------------- 6 files changed, 140 insertions(+), 52 deletions(-) create mode 100644 include/elna/source/driver.hpp create mode 100644 source/driver.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a3126c..135ff85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,7 @@ add_flex_bison_dependency(lexer parser) add_executable(elna cli/main.cpp source/ast.cpp include/elna/source/ast.hpp source/types.cpp include/elna/source/types.hpp + source/driver.cpp include/elna/source/driver.hpp source/result.cpp include/elna/source/result.hpp ${BISON_parser_OUTPUTS} ${FLEX_lexer_OUTPUTS} ) diff --git a/cli/main.cpp b/cli/main.cpp index 0caf149..0290c04 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -1,22 +1,37 @@ +#include #include "parser.hpp" #include int main() { - std::istringstream inp("const world = 5, hello = 7;"); + elna::source::driver driver{ "-" }; + std::istringstream inp(R"( + const world = 5, hello = 7; + var x: int; + begin + end. + )"); - std::unique_ptr program; - - elna::syntax::FooLexer lexer(inp); - yy::parser parser(lexer, program); - auto result = parser(); - - for (auto& definition : program->definitions()) + elna::source::lexer lexer(inp); + yy::parser parser(lexer, driver); + + if (auto result = parser()) + { + for (const auto& error : driver.errors()) + { + std::cerr << error->path().string() << ':' + << error->line() << ':' << error->column() + << ": error: " << error->what() + << '.' << std::endl; + } + return result; + } + for (auto& definition : driver.tree->definitions()) { auto const_definition = dynamic_cast(definition.get()); std::cout << "const " << const_definition->identifier() << " = " << const_definition->body().number() << std::endl; } - return result; + return 0; } diff --git a/include/elna/source/driver.hpp b/include/elna/source/driver.hpp new file mode 100644 index 0000000..e91938f --- /dev/null +++ b/include/elna/source/driver.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include +#include "elna/source/ast.hpp" +#include "location.hh" + +namespace elna::source +{ + position make_position(const yy::location& location); + + class syntax_error final : public error + { + std::string message; + + public: + syntax_error(const std::string& message, + const std::filesystem::path& input_file, const yy::location& location); + + virtual std::string what() const override; + }; + + class driver + { + std::list> m_errors; + const std::filesystem::path input_file; + + public: + std::unique_ptr tree; + + driver(const std::filesystem::path& input_file); + + void error(const yy::location& loc, const std::string& message); + const std::list>& errors() const noexcept; + }; +} diff --git a/source/driver.cpp b/source/driver.cpp new file mode 100644 index 0000000..a83ea8b --- /dev/null +++ b/source/driver.cpp @@ -0,0 +1,38 @@ +#include "elna/source/driver.hpp" + +namespace elna::source +{ + position make_position(const yy::location& location) + { + return position{ + static_cast(location.begin.line), + static_cast(location.begin.column) + }; + } + + syntax_error::syntax_error(const std::string& message, + const std::filesystem::path& input_file, const yy::location& location) + : error(input_file, make_position(location)), message(message) + { + } + + std::string syntax_error::what() const + { + return message; + } + + driver::driver(const std::filesystem::path& input_file) + : input_file(input_file) + { + } + + void driver::error(const yy::location& loc, const std::string& message) + { + m_errors.emplace_back(std::make_unique(message, input_file, loc)); + } + + const std::list>& driver::errors() const noexcept + { + return m_errors; + } +} diff --git a/source/lexer.ll b/source/lexer.ll index 9485abd..5add29d 100644 --- a/source/lexer.ll +++ b/source/lexer.ll @@ -6,12 +6,12 @@ #include "parser.hpp" #undef YY_DECL -#define YY_DECL yy::parser::symbol_type elna::syntax::FooLexer::lex() +#define YY_DECL yy::parser::symbol_type elna::source::lexer::lex() #define yyterminate() return yy::parser::make_YYEOF(this->location) %} %option c++ noyywrap never-interactive -%option yyclass="elna::syntax::FooLexer" +%option yyclass="elna::source::lexer" %% %{ @@ -125,7 +125,7 @@ False { . { std::stringstream ss; - ss << "Illegal character 0x" << std::hex << static_cast(yytext[0]); + ss << "Illegal character 0x" << std::hex << static_cast(yytext[0]); throw yy::parser::syntax_error(this->location, ss.str()); } %% diff --git a/source/parser.yy b/source/parser.yy index 3447ea9..b48ec07 100644 --- a/source/parser.yy +++ b/source/parser.yy @@ -4,29 +4,28 @@ %code requires { #include #include - #include "elna/source/ast.hpp" + #include "elna/source/driver.hpp" - - #if ! defined(yyFlexLexerOnce) + #if !defined(yyFlexLexerOnce) #include #endif - namespace elna::syntax + namespace elna::source { - class FooLexer; + class lexer; } } %code provides { - namespace elna::syntax + namespace elna::source { - class FooLexer : public yyFlexLexer + class lexer: public yyFlexLexer { public: yy::location location; - FooLexer(std::istream& arg_yyin) + lexer(std::istream& arg_yyin) : yyFlexLexer(&arg_yyin) { } @@ -42,8 +41,8 @@ %define api.value.type variant %define parse.assert -%parse-param {elna::syntax::FooLexer& lexer} -%parse-param {std::unique_ptr& program} +%parse-param {elna::source::lexer& lexer} +%parse-param {elna::source::driver& driver} %locations %header @@ -68,12 +67,13 @@ %type > integer_literal; %type > constant_definition; %type >> constant_definition_part constant_definitions; +%type > variable_declaration; +%type >> variable_declarations variable_declaration_part; %type > type_expression; +%type > statement; %% -program: constant_definition_part +program: constant_definition_part variable_declaration_part statement DOT { - elna::source::position position; - std::vector> declarations; std::vector> definitions($1.size()); std::vector>::iterator definition = definitions.begin(); @@ -81,46 +81,45 @@ program: constant_definition_part { *definition++ = std::move(constant); } - program = std::make_unique(position, - std::move(definitions), std::move(declarations), - std::make_unique(position)); + driver.tree = std::make_unique(elna::source::position{}, + std::move(definitions), std::move($2), + std::move($3)); } integer_literal: NUMBER { - elna::source::position position{ - static_cast(@1.begin.line), - static_cast(@1.begin.column) - }; - $$ = std::make_unique(position, $1); + $$ = std::make_unique(elna::source::make_position(@1), $1); + }; +statement: BEGIN_BLOCK END_BLOCK + { + $$ = std::make_unique(elna::source::make_position(@1)); }; type_expression: HAT IDENTIFIER { - elna::source::position position{ - static_cast(@1.begin.line), - static_cast(@1.begin.column) - }; - $$ = std::make_unique(position, $2, true); + $$ = std::make_unique(elna::source::make_position(@1), $2, true); } | IDENTIFIER { - elna::source::position position{ - static_cast(@1.begin.line), - static_cast(@1.begin.column) - }; - $$ = std::make_unique(position, $1, false); + $$ = std::make_unique(elna::source::make_position(@1), $1, false); } variable_declaration: IDENTIFIER COLON type_expression + { + $$ = std::make_unique(elna::source::make_position(@1), + $1, std::move($3)); + }; variable_declarations: - variable_declaration COMMA variable_declarations - | variable_declaration + variable_declaration COMMA variable_declarations + { + std::swap($$, $3); + $$.emplace($$.cbegin(), std::move($1)); + } + | variable_declaration { $$.emplace_back(std::move($1)); } +variable_declaration_part: + /* no variable declarations */ {} + | VAR variable_declarations SEMICOLON { std::swap($$, $2); } constant_definition: IDENTIFIER EQUALS integer_literal { - elna::source::position position{ - static_cast(@1.begin.line), - static_cast(@1.begin.column) - }; - $$ = std::make_unique(position, + $$ = std::make_unique(elna::source::make_position(@1), $1, std::move($3)); }; constant_definitions: @@ -135,7 +134,7 @@ constant_definition_part: | CONST constant_definitions SEMICOLON { std::swap($$, $2); }; %% -void yy::parser::error(const location_type& loc, const std::string &message) +void yy::parser::error(const location_type& loc, const std::string& message) { - std::cerr << "Error: " << message << std::endl; + driver.error(loc, message); }