Parse variable declarations
This commit is contained in:
		| @@ -18,6 +18,7 @@ add_flex_bison_dependency(lexer parser) | |||||||
| add_executable(elna cli/main.cpp | add_executable(elna cli/main.cpp | ||||||
| 	source/ast.cpp include/elna/source/ast.hpp | 	source/ast.cpp include/elna/source/ast.hpp | ||||||
| 	source/types.cpp include/elna/source/types.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 | 	source/result.cpp include/elna/source/result.hpp | ||||||
| 	${BISON_parser_OUTPUTS} ${FLEX_lexer_OUTPUTS} | 	${BISON_parser_OUTPUTS} ${FLEX_lexer_OUTPUTS} | ||||||
| ) | ) | ||||||
|   | |||||||
							
								
								
									
										31
									
								
								cli/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								cli/main.cpp
									
									
									
									
									
								
							| @@ -1,22 +1,37 @@ | |||||||
|  | #include <elna/source/driver.hpp> | ||||||
| #include "parser.hpp" | #include "parser.hpp" | ||||||
| #include <sstream> | #include <sstream> | ||||||
|  |  | ||||||
| int main() | 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::source::lexer lexer(inp); | ||||||
|  |     yy::parser parser(lexer, driver); | ||||||
|      |      | ||||||
|     elna::syntax::FooLexer lexer(inp); |     if (auto result = parser()) | ||||||
|     yy::parser parser(lexer, program); |     { | ||||||
|     auto result = parser(); |         for (const auto& error : driver.errors()) | ||||||
|  |         { | ||||||
|     for (auto& definition : program->definitions()) |             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()); |         auto const_definition = dynamic_cast<elna::source::constant_definition *>(definition.get()); | ||||||
|  |  | ||||||
|         std::cout << "const " << const_definition->identifier() << " = " |         std::cout << "const " << const_definition->identifier() << " = " | ||||||
|             << const_definition->body().number() << std::endl; |             << 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" | #include "parser.hpp" | ||||||
|  |  | ||||||
| #undef YY_DECL | #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) | #define yyterminate() return yy::parser::make_YYEOF(this->location) | ||||||
| %} | %} | ||||||
|  |  | ||||||
| %option c++ noyywrap never-interactive | %option c++ noyywrap never-interactive | ||||||
| %option yyclass="elna::syntax::FooLexer" | %option yyclass="elna::source::lexer" | ||||||
|  |  | ||||||
| %% | %% | ||||||
| %{ | %{ | ||||||
| @@ -125,7 +125,7 @@ False                   { | |||||||
| .                       { | .                       { | ||||||
|                             std::stringstream ss; |                             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()); |                             throw yy::parser::syntax_error(this->location, ss.str()); | ||||||
|                         } |                         } | ||||||
| %% | %% | ||||||
|   | |||||||
| @@ -4,29 +4,28 @@ | |||||||
| %code requires { | %code requires { | ||||||
|     #include <cstdint> |     #include <cstdint> | ||||||
|     #include <iostream> |     #include <iostream> | ||||||
|     #include "elna/source/ast.hpp" |     #include "elna/source/driver.hpp" | ||||||
|  |  | ||||||
|  |  | ||||||
|     #if !defined(yyFlexLexerOnce) |     #if !defined(yyFlexLexerOnce) | ||||||
|         #include <FlexLexer.h> |         #include <FlexLexer.h> | ||||||
|     #endif |     #endif | ||||||
|  |  | ||||||
|     namespace elna::syntax |     namespace elna::source | ||||||
|     { |     { | ||||||
|     class FooLexer; |     class lexer; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| %code provides { | %code provides { | ||||||
|     namespace elna::syntax |     namespace elna::source | ||||||
|     { |     { | ||||||
|  |  | ||||||
|     class FooLexer : public yyFlexLexer |     class lexer: public yyFlexLexer | ||||||
|     { |     { | ||||||
|     public: |     public: | ||||||
|         yy::location location; |         yy::location location; | ||||||
|  |  | ||||||
|         FooLexer(std::istream& arg_yyin) |         lexer(std::istream& arg_yyin) | ||||||
|             : yyFlexLexer(&arg_yyin) |             : yyFlexLexer(&arg_yyin) | ||||||
|         { |         { | ||||||
|         } |         } | ||||||
| @@ -42,8 +41,8 @@ | |||||||
| %define api.value.type variant | %define api.value.type variant | ||||||
| %define parse.assert | %define parse.assert | ||||||
|  |  | ||||||
| %parse-param {elna::syntax::FooLexer& lexer} | %parse-param {elna::source::lexer& lexer} | ||||||
| %parse-param {std::unique_ptr<elna::source::program>& program} | %parse-param {elna::source::driver& driver} | ||||||
| %locations | %locations | ||||||
|  |  | ||||||
| %header | %header | ||||||
| @@ -68,12 +67,13 @@ | |||||||
| %type <std::unique_ptr<elna::source::integer_literal>> integer_literal; | %type <std::unique_ptr<elna::source::integer_literal>> integer_literal; | ||||||
| %type <std::unique_ptr<elna::source::constant_definition>> constant_definition; | %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::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::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>> definitions($1.size()); | ||||||
|             std::vector<std::unique_ptr<elna::source::definition>>::iterator definition = definitions.begin(); |             std::vector<std::unique_ptr<elna::source::definition>>::iterator definition = definitions.begin(); | ||||||
|  |  | ||||||
| @@ -81,46 +81,45 @@ program: constant_definition_part | |||||||
|             { |             { | ||||||
|                 *definition++ = std::move(constant); |                 *definition++ = std::move(constant); | ||||||
|             } |             } | ||||||
|             program = std::make_unique<elna::source::program>(position, |             driver.tree = std::make_unique<elna::source::program>(elna::source::position{}, | ||||||
|                  std::move(definitions), std::move(declarations), |                  std::move(definitions), std::move($2), | ||||||
|                  std::make_unique<elna::source::compound_statement>(position)); |                  std::move($3)); | ||||||
|         } |         } | ||||||
| integer_literal: NUMBER | integer_literal: NUMBER | ||||||
|         { |         { | ||||||
|             elna::source::position position{ |             $$ = std::make_unique<elna::source::integer_literal>(elna::source::make_position(@1), $1);  | ||||||
|                 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);  | statement: BEGIN_BLOCK END_BLOCK | ||||||
|  |         { | ||||||
|  |             $$ = std::make_unique<elna::source::compound_statement>(elna::source::make_position(@1)); | ||||||
|         }; |         }; | ||||||
| type_expression: | type_expression: | ||||||
|         HAT IDENTIFIER |         HAT IDENTIFIER | ||||||
|             { |             { | ||||||
|                 elna::source::position position{ |                 $$ = std::make_unique<elna::source::type_expression>(elna::source::make_position(@1), $2, true); | ||||||
|                     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); |  | ||||||
|             } |             } | ||||||
|         | IDENTIFIER |         | IDENTIFIER | ||||||
|             { |             { | ||||||
|                 elna::source::position position{ |                 $$ = std::make_unique<elna::source::type_expression>(elna::source::make_position(@1), $1, false); | ||||||
|                     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); |  | ||||||
|             } |             } | ||||||
| variable_declaration: IDENTIFIER COLON type_expression | variable_declaration: IDENTIFIER COLON type_expression | ||||||
|  |         { | ||||||
|  |             $$ = std::make_unique<elna::source::declaration>(elna::source::make_position(@1), | ||||||
|  |                 $1, std::move($3));  | ||||||
|  |         }; | ||||||
| variable_declarations: | variable_declarations: | ||||||
|     variable_declaration COMMA variable_declarations |     variable_declaration COMMA variable_declarations | ||||||
|         | variable_declaration |         { | ||||||
|  |             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 | constant_definition: IDENTIFIER EQUALS integer_literal | ||||||
|         { |         { | ||||||
|             elna::source::position position{ |             $$ = std::make_unique<elna::source::constant_definition>(elna::source::make_position(@1), | ||||||
|                 static_cast<std::size_t>(@1.begin.line), |  | ||||||
|                 static_cast<std::size_t>(@1.begin.column) |  | ||||||
|             }; |  | ||||||
|             $$ = std::make_unique<elna::source::constant_definition>(position, |  | ||||||
|                 $1, std::move($3));  |                 $1, std::move($3));  | ||||||
|         }; |         }; | ||||||
| constant_definitions: | constant_definitions: | ||||||
| @@ -137,5 +136,5 @@ constant_definition_part: | |||||||
|  |  | ||||||
| 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