Parse variable declarations
This commit is contained in:
		| @@ -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} | ||||
| ) | ||||
|   | ||||
							
								
								
									
										33
									
								
								cli/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								cli/main.cpp
									
									
									
									
									
								
							| @@ -1,22 +1,37 @@ | ||||
| #include <elna/source/driver.hpp> | ||||
| #include "parser.hpp" | ||||
| #include <sstream> | ||||
|  | ||||
| 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<elna::source::program> 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<elna::source::constant_definition *>(definition.get()); | ||||
|  | ||||
|         std::cout << "const " << const_definition->identifier() << " = " | ||||
|             << const_definition->body().number() << std::endl; | ||||
|     } | ||||
|     return result; | ||||
|     return 0; | ||||
| } | ||||
|   | ||||
							
								
								
									
										35
									
								
								include/elna/source/driver.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								include/elna/source/driver.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <list> | ||||
| #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<std::unique_ptr<struct error>> m_errors; | ||||
|         const std::filesystem::path input_file; | ||||
|  | ||||
|     public: | ||||
|         std::unique_ptr<program> tree; | ||||
|  | ||||
|         driver(const std::filesystem::path& input_file); | ||||
|  | ||||
|         void error(const yy::location& loc, const std::string& message); | ||||
|         const std::list<std::unique_ptr<struct error>>& errors() const noexcept; | ||||
|     }; | ||||
| } | ||||
							
								
								
									
										38
									
								
								source/driver.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								source/driver.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| #include "elna/source/driver.hpp" | ||||
|  | ||||
| namespace elna::source | ||||
| { | ||||
|     position make_position(const yy::location& location) | ||||
|     { | ||||
|         return position{ | ||||
|             static_cast<std::size_t>(location.begin.line), | ||||
|             static_cast<std::size_t>(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<elna::source::syntax_error>(message, input_file, loc)); | ||||
|     } | ||||
|  | ||||
|     const std::list<std::unique_ptr<struct error>>& driver::errors() const noexcept | ||||
|     { | ||||
|         return m_errors; | ||||
|     } | ||||
| } | ||||
| @@ -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<unsigned char>(yytext[0]); | ||||
|                             ss << "Illegal character 0x" << std::hex << static_cast<unsigned int>(yytext[0]); | ||||
|                             throw yy::parser::syntax_error(this->location, ss.str()); | ||||
|                         } | ||||
| %% | ||||
|   | ||||
| @@ -4,29 +4,28 @@ | ||||
| %code requires { | ||||
|     #include <cstdint> | ||||
|     #include <iostream> | ||||
|     #include "elna/source/ast.hpp" | ||||
|     #include "elna/source/driver.hpp" | ||||
|  | ||||
|  | ||||
|     #if ! defined(yyFlexLexerOnce) | ||||
|     #if !defined(yyFlexLexerOnce) | ||||
|         #include <FlexLexer.h> | ||||
|     #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<elna::source::program>& program} | ||||
| %parse-param {elna::source::lexer& lexer} | ||||
| %parse-param {elna::source::driver& driver} | ||||
| %locations | ||||
|  | ||||
| %header | ||||
| @@ -68,12 +67,13 @@ | ||||
| %type <std::unique_ptr<elna::source::integer_literal>> integer_literal; | ||||
| %type <std::unique_ptr<elna::source::constant_definition>> constant_definition; | ||||
| %type <std::vector<std::unique_ptr<elna::source::constant_definition>>> constant_definition_part constant_definitions; | ||||
| %type <std::unique_ptr<elna::source::declaration>> variable_declaration; | ||||
| %type <std::vector<std::unique_ptr<elna::source::declaration>>> variable_declarations variable_declaration_part; | ||||
| %type <std::unique_ptr<elna::source::type_expression>> type_expression; | ||||
| %type <std::unique_ptr<elna::source::statement>> statement; | ||||
| %% | ||||
| program: constant_definition_part | ||||
| program: constant_definition_part variable_declaration_part statement DOT | ||||
|         { | ||||
|             elna::source::position position; | ||||
|             std::vector<std::unique_ptr<elna::source::declaration>> declarations; | ||||
|             std::vector<std::unique_ptr<elna::source::definition>> definitions($1.size()); | ||||
|             std::vector<std::unique_ptr<elna::source::definition>>::iterator definition = definitions.begin(); | ||||
|  | ||||
| @@ -81,46 +81,45 @@ program: constant_definition_part | ||||
|             { | ||||
|                 *definition++ = std::move(constant); | ||||
|             } | ||||
|             program = std::make_unique<elna::source::program>(position, | ||||
|                  std::move(definitions), std::move(declarations), | ||||
|                  std::make_unique<elna::source::compound_statement>(position)); | ||||
|             driver.tree = std::make_unique<elna::source::program>(elna::source::position{}, | ||||
|                  std::move(definitions), std::move($2), | ||||
|                  std::move($3)); | ||||
|         } | ||||
| integer_literal: NUMBER | ||||
|         { | ||||
|             elna::source::position position{ | ||||
|                 static_cast<std::size_t>(@1.begin.line), | ||||
|                 static_cast<std::size_t>(@1.begin.column) | ||||
|             }; | ||||
|             $$ = std::make_unique<elna::source::integer_literal>(position, $1);  | ||||
|             $$ = std::make_unique<elna::source::integer_literal>(elna::source::make_position(@1), $1);  | ||||
|         }; | ||||
| statement: BEGIN_BLOCK END_BLOCK | ||||
|         { | ||||
|             $$ = std::make_unique<elna::source::compound_statement>(elna::source::make_position(@1)); | ||||
|         }; | ||||
| type_expression: | ||||
|         HAT IDENTIFIER | ||||
|             { | ||||
|                 elna::source::position position{ | ||||
|                     static_cast<std::size_t>(@1.begin.line), | ||||
|                     static_cast<std::size_t>(@1.begin.column) | ||||
|                 }; | ||||
|                 $$ = std::make_unique<elna::source::type_expression>(position, $2, true); | ||||
|                 $$ = std::make_unique<elna::source::type_expression>(elna::source::make_position(@1), $2, true); | ||||
|             } | ||||
|         | IDENTIFIER | ||||
|             { | ||||
|                 elna::source::position position{ | ||||
|                     static_cast<std::size_t>(@1.begin.line), | ||||
|                     static_cast<std::size_t>(@1.begin.column) | ||||
|                 }; | ||||
|                 $$ = std::make_unique<elna::source::type_expression>(position, $1, false); | ||||
|                 $$ = std::make_unique<elna::source::type_expression>(elna::source::make_position(@1), $1, false); | ||||
|             } | ||||
| variable_declaration: IDENTIFIER COLON type_expression | ||||
|         { | ||||
|             $$ = std::make_unique<elna::source::declaration>(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<std::size_t>(@1.begin.line), | ||||
|                 static_cast<std::size_t>(@1.begin.column) | ||||
|             }; | ||||
|             $$ = std::make_unique<elna::source::constant_definition>(position, | ||||
|             $$ = std::make_unique<elna::source::constant_definition>(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); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user