Rename elna::source to elna:boot
This commit is contained in:
parent
45898bb95f
commit
4011adbe2b
@ -1,11 +1,11 @@
|
||||
// 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/ast.h"
|
||||
#include "elna/boot/ast.h"
|
||||
|
||||
namespace elna
|
||||
{
|
||||
namespace source
|
||||
namespace boot
|
||||
{
|
||||
void empty_visitor::visit(variable_declaration *)
|
||||
{
|
||||
@ -52,7 +52,7 @@ namespace source
|
||||
expression->body().accept(this);
|
||||
}
|
||||
|
||||
void empty_visitor::visit(expression_statement *statement)
|
||||
void empty_visitor::visit(call_statement *statement)
|
||||
{
|
||||
statement->body().accept(this);
|
||||
}
|
||||
@ -783,22 +783,22 @@ namespace source
|
||||
delete m_body;
|
||||
}
|
||||
|
||||
expression_statement::expression_statement(const struct position position, expression *body)
|
||||
call_statement::call_statement(const struct position position, call_expression *body)
|
||||
: statement(position), m_body(body)
|
||||
{
|
||||
}
|
||||
|
||||
void expression_statement::accept(parser_visitor *visitor)
|
||||
void call_statement::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
expression& expression_statement::body()
|
||||
call_expression& call_statement::body()
|
||||
{
|
||||
return *m_body;
|
||||
}
|
||||
|
||||
expression_statement::~expression_statement()
|
||||
call_statement::~call_statement()
|
||||
{
|
||||
delete m_body;
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
// 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/driver.h"
|
||||
#include "elna/boot/driver.h"
|
||||
|
||||
namespace elna
|
||||
{
|
||||
namespace source
|
||||
namespace boot
|
||||
{
|
||||
position make_position(const yy::location& location)
|
||||
{
|
||||
@ -33,7 +33,7 @@ namespace source
|
||||
|
||||
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));
|
||||
m_errors.emplace_back(std::make_unique<boot::syntax_error>(message, input_file, loc));
|
||||
}
|
||||
|
||||
const std::list<std::unique_ptr<struct error>>& driver::errors() const noexcept
|
@ -11,12 +11,12 @@
|
||||
#include "parser.hh"
|
||||
|
||||
#undef YY_DECL
|
||||
#define YY_DECL yy::parser::symbol_type elna::source::lexer::lex(elna::source::driver& driver)
|
||||
#define YY_DECL yy::parser::symbol_type elna::boot::lexer::lex(elna::boot::driver& driver)
|
||||
#define yyterminate() return yy::parser::make_YYEOF(this->location)
|
||||
%}
|
||||
|
||||
%option c++ noyywrap never-interactive
|
||||
%option yyclass="elna::source::lexer"
|
||||
%option yyclass="elna::boot::lexer"
|
||||
|
||||
%x IN_COMMENT
|
||||
|
||||
@ -155,7 +155,7 @@ sizeof {
|
||||
return yy::parser::make_CHARACTER(std::string(&character, 1), this->location);
|
||||
}
|
||||
'\\[0nabtfrv\\'"?]' {
|
||||
std::optional<char> escape = source::escape_char(yytext[2]);
|
||||
std::optional<char> escape = elna::boot::escape_char(yytext[2]);
|
||||
if (escape.has_value())
|
||||
{
|
||||
return yy::parser::make_CHARACTER(std::string(&escape.value(), 1), this->location);
|
||||
@ -191,7 +191,7 @@ sizeof {
|
||||
{
|
||||
++current_position;
|
||||
|
||||
std::optional<char> escape = source::escape_char(*current_position);
|
||||
std::optional<char> escape = elna::boot::escape_char(*current_position);
|
||||
if (escape.has_value())
|
||||
{
|
||||
result.push_back(escape.value());
|
482
boot/parser.yy
Normal file
482
boot/parser.yy
Normal file
@ -0,0 +1,482 @@
|
||||
/*
|
||||
* 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/.
|
||||
*/
|
||||
%require "3.2"
|
||||
%language "c++"
|
||||
|
||||
%code requires {
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include "elna/boot/driver.h"
|
||||
|
||||
#if !defined(yyFlexLexerOnce)
|
||||
#include <FlexLexer.h>
|
||||
#endif
|
||||
|
||||
namespace elna
|
||||
{
|
||||
namespace boot
|
||||
{
|
||||
class lexer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
%code provides {
|
||||
namespace elna
|
||||
{
|
||||
namespace boot
|
||||
{
|
||||
|
||||
class lexer: public yyFlexLexer
|
||||
{
|
||||
public:
|
||||
yy::location location;
|
||||
|
||||
lexer(std::istream& arg_yyin)
|
||||
: yyFlexLexer(&arg_yyin)
|
||||
{
|
||||
}
|
||||
|
||||
yy::parser::symbol_type lex(elna::boot::driver& driver);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
%define api.token.raw
|
||||
%define api.token.constructor
|
||||
%define api.value.type variant
|
||||
|
||||
%parse-param {elna::boot::lexer& lexer}
|
||||
%param {elna::boot::driver& driver}
|
||||
%locations
|
||||
|
||||
%header
|
||||
|
||||
%code {
|
||||
#define yylex lexer.lex
|
||||
}
|
||||
%start program;
|
||||
|
||||
%token <std::string> IDENTIFIER "identifier"
|
||||
%token <std::int32_t> INTEGER "integer"
|
||||
%token <std::uint32_t> WORD "word"
|
||||
%token <float> FLOAT "float"
|
||||
%token <std::string> CHARACTER "character"
|
||||
%token <std::string> STRING "string"
|
||||
%token <bool> BOOLEAN
|
||||
%token IF WHILE DO THEN ELSE ELSIF RETURN
|
||||
%token CONST VAR PROCEDURE ARRAY OF TYPE RECORD POINTER TO UNION
|
||||
%token BEGIN_BLOCK END_BLOCK EXTERN
|
||||
%token LEFT_PAREN RIGHT_PAREN LEFT_SQUARE RIGHT_SQUARE SEMICOLON DOT COMMA
|
||||
%token AND OR NOT CAST AS SIZEOF
|
||||
%token GREATER_EQUAL LESS_EQUAL LESS_THAN GREATER_THAN NOT_EQUAL EQUALS
|
||||
%token PLUS MINUS MULTIPLICATION DIVISION REMAINDER
|
||||
%token ASSIGNMENT COLON HAT AT NIL
|
||||
|
||||
%left OR AND
|
||||
%left EQUALS NOT_EQUAL LESS_THAN GREATER_THAN LESS_EQUAL GREATER_EQUAL
|
||||
%left PLUS MINUS
|
||||
%left MULTIPLICATION DIVISION REMAINDER
|
||||
|
||||
%type <elna::boot::literal *> literal;
|
||||
%type <elna::boot::constant_definition *> constant_definition;
|
||||
%type <std::vector<elna::boot::constant_definition *>> constant_part constant_definitions;
|
||||
%type <elna::boot::variable_declaration *> variable_declaration;
|
||||
%type <std::vector<elna::boot::variable_declaration *>> variable_declarations variable_part
|
||||
formal_parameter_list;
|
||||
%type <elna::boot::type_expression *> type_expression;
|
||||
%type <elna::boot::expression *> expression operand unary;
|
||||
%type <std::vector<elna::boot::expression *>> expressions actual_parameter_list;
|
||||
%type <elna::boot::designator_expression *> designator_expression;
|
||||
%type <elna::boot::assign_statement *> assign_statement;
|
||||
%type <elna::boot::call_expression *> call_expression;
|
||||
%type <elna::boot::while_statement *> while_statement;
|
||||
%type <elna::boot::if_statement *> if_statement;
|
||||
%type <elna::boot::return_statement *> return_statement;
|
||||
%type <elna::boot::statement *> statement;
|
||||
%type <std::vector<elna::boot::statement *>> statements optional_statements;
|
||||
%type <elna::boot::procedure_definition *> procedure_definition;
|
||||
%type <std::vector<elna::boot::procedure_definition *>> procedure_definitions procedure_part;
|
||||
%type <elna::boot::type_definition *> type_definition;
|
||||
%type <std::vector<elna::boot::type_definition *>> type_definitions type_part;
|
||||
%type <elna::boot::block *> block;
|
||||
%type <std::pair<std::string, elna::boot::type_expression *>> field_declaration;
|
||||
%type <std::vector<std::pair<std::string, elna::boot::type_expression *>>> field_list;
|
||||
%type <std::vector<elna::boot::conditional_statements *>> elsif_statement_list;
|
||||
%type <elna::boot::cast_expression *> cast_expression;
|
||||
%%
|
||||
program:
|
||||
type_part constant_part procedure_part variable_part BEGIN_BLOCK optional_statements END_BLOCK DOT
|
||||
{
|
||||
std::vector<elna::boot::definition *> definitions($1.size() + $3.size());
|
||||
std::vector<elna::boot::definition *>::iterator definition = definitions.begin();
|
||||
std::vector<elna::boot::definition *> value_definitions($2.size() + $4.size());
|
||||
std::vector<elna::boot::definition *>::iterator value_definition = value_definitions.begin();
|
||||
|
||||
for (auto type : $1)
|
||||
{
|
||||
*definition++ = type;
|
||||
}
|
||||
for (auto constant : $2)
|
||||
{
|
||||
*value_definition++ = constant;
|
||||
}
|
||||
for (auto procedure : $3)
|
||||
{
|
||||
*definition++ = procedure;
|
||||
}
|
||||
for (auto variable : $4)
|
||||
{
|
||||
*value_definition++ = variable;
|
||||
}
|
||||
auto tree = new elna::boot::program(elna::boot::make_position(@5),
|
||||
std::move(definitions), std::move(value_definitions), std::move($6));
|
||||
|
||||
driver.tree.reset(tree);
|
||||
}
|
||||
block: constant_part variable_part BEGIN_BLOCK optional_statements END_BLOCK
|
||||
{
|
||||
std::vector<elna::boot::definition *> definitions($1.size() + $2.size());
|
||||
std::vector<elna::boot::definition *>::iterator definition = definitions.begin();
|
||||
|
||||
for (auto constant : $1)
|
||||
{
|
||||
*definition++ = constant;
|
||||
}
|
||||
for (auto variable : $2)
|
||||
{
|
||||
*definition++ = variable;
|
||||
}
|
||||
$$ = new elna::boot::block(elna::boot::make_position(@3),
|
||||
std::move(definitions), std::move($4));
|
||||
}
|
||||
procedure_definition:
|
||||
PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON block SEMICOLON
|
||||
{
|
||||
$$ = new elna::boot::procedure_definition(elna::boot::make_position(@1),
|
||||
$2, std::move($3), nullptr, $5);
|
||||
}
|
||||
| PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON EXTERN SEMICOLON
|
||||
{
|
||||
$$ = new elna::boot::procedure_definition(elna::boot::make_position(@1),
|
||||
$2, std::move($3), nullptr, nullptr);
|
||||
}
|
||||
| PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON block SEMICOLON
|
||||
{
|
||||
$$ = new elna::boot::procedure_definition(elna::boot::make_position(@1),
|
||||
$2, std::move($3), $5, $7);
|
||||
}
|
||||
| PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON EXTERN SEMICOLON
|
||||
{
|
||||
$$ = new elna::boot::procedure_definition(elna::boot::make_position(@1),
|
||||
$2, std::move($3), $5, nullptr);
|
||||
}
|
||||
procedure_definitions:
|
||||
procedure_definition procedure_definitions
|
||||
{
|
||||
std::swap($$, $2);
|
||||
$$.emplace($$.cbegin(), std::move($1));
|
||||
}
|
||||
| procedure_definition { $$.emplace_back(std::move($1)); }
|
||||
procedure_part:
|
||||
/* no procedure definitions */ {}
|
||||
| procedure_definitions { std::swap($$, $1); }
|
||||
assign_statement: designator_expression ASSIGNMENT expression
|
||||
{
|
||||
$$ = new elna::boot::assign_statement(elna::boot::make_position(@1), $1, $3);
|
||||
}
|
||||
call_expression: IDENTIFIER actual_parameter_list
|
||||
{
|
||||
$$ = new elna::boot::call_expression(elna::boot::make_position(@1), $1);
|
||||
std::swap($$->arguments(), $2);
|
||||
}
|
||||
cast_expression: CAST LEFT_PAREN expression AS type_expression RIGHT_PAREN
|
||||
{
|
||||
$$ = new elna::boot::cast_expression(elna::boot::make_position(@1), $5, $3);
|
||||
}
|
||||
while_statement: WHILE expression DO optional_statements END_BLOCK
|
||||
{
|
||||
auto body = new elna::boot::conditional_statements($2);
|
||||
std::swap($4, body->statements);
|
||||
$$ = new elna::boot::while_statement(elna::boot::make_position(@1), body);
|
||||
}
|
||||
elsif_statement_list:
|
||||
ELSIF expression THEN optional_statements elsif_statement_list
|
||||
{
|
||||
elna::boot::conditional_statements *branch = new elna::boot::conditional_statements($2);
|
||||
std::swap(branch->statements, $4);
|
||||
std::swap($5, $$);
|
||||
$$.emplace($$.begin(), branch);
|
||||
}
|
||||
| {}
|
||||
if_statement:
|
||||
IF expression THEN optional_statements elsif_statement_list END_BLOCK
|
||||
{
|
||||
auto then = new elna::boot::conditional_statements($2);
|
||||
std::swap($4, then->statements);
|
||||
$$ = new elna::boot::if_statement(elna::boot::make_position(@1), then);
|
||||
std::swap($5, $$->branches);
|
||||
}
|
||||
| IF expression THEN optional_statements elsif_statement_list ELSE optional_statements END_BLOCK
|
||||
{
|
||||
auto then = new elna::boot::conditional_statements($2);
|
||||
std::swap($4, then->statements);
|
||||
auto _else = new std::vector<elna::boot::statement *>(std::move($7));
|
||||
$$ = new elna::boot::if_statement(elna::boot::make_position(@1), then, _else);
|
||||
std::swap($5, $$->branches);
|
||||
}
|
||||
return_statement:
|
||||
RETURN expression
|
||||
{
|
||||
$$ = new elna::boot::return_statement(elna::boot::make_position(@1), $2);
|
||||
}
|
||||
literal:
|
||||
INTEGER
|
||||
{
|
||||
$$ = new elna::boot::number_literal<std::int32_t>(elna::boot::make_position(@1), $1);
|
||||
}
|
||||
| WORD
|
||||
{
|
||||
$$ = new elna::boot::number_literal<std::uint32_t>(elna::boot::make_position(@1), $1);
|
||||
}
|
||||
| FLOAT
|
||||
{
|
||||
$$ = new elna::boot::number_literal<double>(elna::boot::make_position(@1), $1);
|
||||
}
|
||||
| BOOLEAN
|
||||
{
|
||||
$$ = new elna::boot::number_literal<bool>(elna::boot::make_position(@1), $1);
|
||||
}
|
||||
| CHARACTER
|
||||
{
|
||||
$$ = new elna::boot::number_literal<unsigned char>(elna::boot::make_position(@1), $1.at(0));
|
||||
}
|
||||
| NIL
|
||||
{
|
||||
$$ = new elna::boot::number_literal<std::nullptr_t>(elna::boot::make_position(@1), nullptr);
|
||||
}
|
||||
| STRING
|
||||
{
|
||||
$$ = new elna::boot::string_literal(elna::boot::make_position(@1), $1);
|
||||
}
|
||||
operand:
|
||||
literal { $$ = $1; }
|
||||
| designator_expression { $$ = $1; }
|
||||
| SIZEOF LEFT_PAREN type_expression RIGHT_PAREN
|
||||
{
|
||||
$$ = new elna::boot::size_of_expression(elna::boot::make_position(@1), $3);
|
||||
}
|
||||
| cast_expression { $$ = $1; }
|
||||
| call_expression { $$ = $1; }
|
||||
| LEFT_PAREN expression RIGHT_PAREN { $$ = $2; }
|
||||
expression:
|
||||
unary { $$ = $1; }
|
||||
| expression MULTIPLICATION expression
|
||||
{
|
||||
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
|
||||
elna::boot::binary_operator::multiplication);
|
||||
}
|
||||
| expression DIVISION expression
|
||||
{
|
||||
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
|
||||
elna::boot::binary_operator::division);
|
||||
}
|
||||
| expression REMAINDER expression
|
||||
{
|
||||
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
|
||||
elna::boot::binary_operator::remainder);
|
||||
}
|
||||
| expression PLUS expression
|
||||
{
|
||||
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
|
||||
elna::boot::binary_operator::sum);
|
||||
}
|
||||
| expression MINUS expression
|
||||
{
|
||||
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
|
||||
elna::boot::binary_operator::subtraction);
|
||||
}
|
||||
| expression EQUALS expression
|
||||
{
|
||||
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
|
||||
elna::boot::binary_operator::equals);
|
||||
}
|
||||
| expression NOT_EQUAL expression
|
||||
{
|
||||
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
|
||||
elna::boot::binary_operator::not_equals);
|
||||
}
|
||||
| expression LESS_THAN expression
|
||||
{
|
||||
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
|
||||
elna::boot::binary_operator::less);
|
||||
}
|
||||
| expression GREATER_THAN expression
|
||||
{
|
||||
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
|
||||
elna::boot::binary_operator::greater);
|
||||
}
|
||||
| expression LESS_EQUAL expression
|
||||
{
|
||||
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
|
||||
elna::boot::binary_operator::less_equal);
|
||||
}
|
||||
| expression GREATER_EQUAL expression
|
||||
{
|
||||
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
|
||||
elna::boot::binary_operator::greater_equal);
|
||||
}
|
||||
| expression AND expression
|
||||
{
|
||||
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
|
||||
elna::boot::binary_operator::conjunction);
|
||||
}
|
||||
| expression OR expression
|
||||
{
|
||||
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
|
||||
elna::boot::binary_operator::disjunction);
|
||||
}
|
||||
unary:
|
||||
AT operand
|
||||
{
|
||||
$$ = new elna::boot::unary_expression(elna::boot::make_position(@1), $2,
|
||||
elna::boot::unary_operator::reference);
|
||||
}
|
||||
| NOT operand
|
||||
{
|
||||
$$ = new elna::boot::unary_expression(elna::boot::make_position(@1), $2,
|
||||
elna::boot::unary_operator::negation);
|
||||
}
|
||||
| operand { $$ = $1; }
|
||||
expressions:
|
||||
expression COMMA expressions
|
||||
{
|
||||
std::swap($$, $3);
|
||||
$$.emplace($$.cbegin(), $1);
|
||||
}
|
||||
| expression { $$.emplace_back(std::move($1)); }
|
||||
designator_expression:
|
||||
designator_expression LEFT_SQUARE expression RIGHT_SQUARE
|
||||
{
|
||||
$$ = new elna::boot::array_access_expression(elna::boot::make_position(@1), $1, $3);
|
||||
}
|
||||
| designator_expression DOT IDENTIFIER
|
||||
{
|
||||
$$ = new elna::boot::field_access_expression(elna::boot::make_position(@2), $1, $3);
|
||||
}
|
||||
| designator_expression HAT
|
||||
{
|
||||
$$ = new elna::boot::dereference_expression(elna::boot::make_position(@1), $1);
|
||||
}
|
||||
| IDENTIFIER
|
||||
{
|
||||
$$ = new elna::boot::variable_expression(elna::boot::make_position(@1), $1);
|
||||
}
|
||||
statement:
|
||||
assign_statement { $$ = $1; }
|
||||
| while_statement { $$ = $1; }
|
||||
| if_statement { $$ = $1; }
|
||||
| return_statement { $$ = $1; }
|
||||
| call_expression
|
||||
{
|
||||
$$ = new elna::boot::call_statement(elna::boot::make_position(@1), $1);
|
||||
}
|
||||
statements:
|
||||
statement SEMICOLON statements
|
||||
{
|
||||
std::swap($$, $3);
|
||||
$$.emplace($$.cbegin(), $1);
|
||||
}
|
||||
| statement { $$.push_back($1); }
|
||||
optional_statements:
|
||||
statements { std::swap($$, $1); }
|
||||
| /* 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:
|
||||
ARRAY INTEGER OF type_expression
|
||||
{
|
||||
$$ = new elna::boot::array_type_expression(elna::boot::make_position(@1), $4, $2);
|
||||
}
|
||||
| POINTER TO type_expression
|
||||
{
|
||||
$$ = new elna::boot::pointer_type_expression(elna::boot::make_position(@1), $3);
|
||||
}
|
||||
| RECORD field_list END_BLOCK
|
||||
{
|
||||
$$ = new elna::boot::record_type_expression(elna::boot::make_position(@1), std::move($2));
|
||||
}
|
||||
| UNION field_list END_BLOCK
|
||||
{
|
||||
$$ = new elna::boot::union_type_expression(elna::boot::make_position(@1), std::move($2));
|
||||
}
|
||||
| IDENTIFIER
|
||||
{
|
||||
$$ = new elna::boot::basic_type_expression(elna::boot::make_position(@1), $1);
|
||||
}
|
||||
variable_declaration: IDENTIFIER COLON type_expression
|
||||
{
|
||||
$$ = new elna::boot::variable_declaration(elna::boot::make_position(@1), $1, $3);
|
||||
}
|
||||
variable_declarations:
|
||||
variable_declaration COMMA variable_declarations
|
||||
{
|
||||
std::swap($$, $3);
|
||||
$$.emplace($$.cbegin(), $1);
|
||||
}
|
||||
| variable_declaration { $$.emplace_back(std::move($1)); }
|
||||
variable_part:
|
||||
/* no variable declarations */ {}
|
||||
| VAR variable_declarations SEMICOLON { std::swap($$, $2); }
|
||||
constant_definition: IDENTIFIER EQUALS literal
|
||||
{
|
||||
$$ = new elna::boot::constant_definition(elna::boot::make_position(@1), $1, $3);
|
||||
}
|
||||
constant_definitions:
|
||||
constant_definition COMMA constant_definitions
|
||||
{
|
||||
std::swap($$, $3);
|
||||
$$.emplace($$.cbegin(), std::move($1));
|
||||
}
|
||||
| constant_definition { $$.emplace_back(std::move($1)); }
|
||||
constant_part:
|
||||
/* no constant definitions */ {}
|
||||
| CONST constant_definitions SEMICOLON { std::swap($$, $2); }
|
||||
type_definition: IDENTIFIER EQUALS type_expression
|
||||
{
|
||||
$$ = new elna::boot::type_definition(elna::boot::make_position(@1), $1, $3);
|
||||
}
|
||||
type_definitions:
|
||||
type_definition COMMA type_definitions
|
||||
{
|
||||
std::swap($$, $3);
|
||||
$$.emplace($$.cbegin(), std::move($1));
|
||||
}
|
||||
| type_definition { $$.emplace_back(std::move($1)); }
|
||||
type_part:
|
||||
/* no type definitions */ {}
|
||||
| TYPE type_definitions SEMICOLON { std::swap($$, $2); }
|
||||
formal_parameter_list:
|
||||
LEFT_PAREN RIGHT_PAREN {}
|
||||
| LEFT_PAREN variable_declarations RIGHT_PAREN { std::swap($$, $2); }
|
||||
actual_parameter_list:
|
||||
LEFT_PAREN RIGHT_PAREN {}
|
||||
| LEFT_PAREN expressions RIGHT_PAREN { std::swap($$, $2); }
|
||||
%%
|
||||
|
||||
void yy::parser::error(const location_type& loc, const std::string& message)
|
||||
{
|
||||
driver.error(loc, message);
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
// 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/result.h"
|
||||
#include "elna/boot/result.h"
|
||||
|
||||
namespace elna
|
||||
{
|
||||
namespace source
|
||||
namespace boot
|
||||
{
|
||||
error::error(const char *path, const struct position position)
|
||||
: position(position), path(path)
|
131
example.elna
131
example.elna
@ -1,12 +1,22 @@
|
||||
type
|
||||
Position = record
|
||||
line: Word;
|
||||
column: Word
|
||||
end,
|
||||
Location = record
|
||||
first: Position;
|
||||
last: Position
|
||||
end,
|
||||
TokenValue = union
|
||||
int_value: Int;
|
||||
string_value: pointer to Char;
|
||||
boolean_value: Bool
|
||||
boolean_value: Bool;
|
||||
char_value: Char
|
||||
end,
|
||||
Token = record
|
||||
kind: Int;
|
||||
value: TokenValue
|
||||
value: TokenValue;
|
||||
location: Location
|
||||
end,
|
||||
FILE = record
|
||||
dummy: Int
|
||||
@ -27,7 +37,8 @@ const
|
||||
TOKEN_SEMICOLON = 40, TOKEN_DOT = 41, TOKEN_COMMA = 42,
|
||||
TOKEN_PLUS = 43, TOKEN_MINUS = 44, TOKEN_MULTIPLICATION = 45, TOKEN_DIVISION = 46,
|
||||
TOKEN_REMAINDER = 47, TOKEN_ASSIGNMENT = 48, TOKEN_COLON = 49, TOKEN_HAT = 50,
|
||||
TOKEN_AT = 51, TOKEN_COMMENT = 52, TOKEN_INTEGER = 53;
|
||||
TOKEN_AT = 51, TOKEN_COMMENT = 52, TOKEN_INTEGER = 53, TOKEN_WORD = 54,
|
||||
TOKEN_CHARACTER = 55;
|
||||
|
||||
(*
|
||||
External procedures.
|
||||
@ -42,7 +53,7 @@ proc write(fd: Int, buf: pointer to Char, count: Int): Int; extern;
|
||||
proc malloc(size: Int): pointer to Char; extern;
|
||||
proc free(ptr: pointer to Char); extern;
|
||||
proc calloc(nmemb: Int, size: Int): pointer to Char; extern;
|
||||
proc realloc(ptr: pointer to Char, size: Int): pointer to Char; extern;
|
||||
proc realloc(ptr: pointer to Char, size: Word): pointer to Char; extern;
|
||||
|
||||
proc memset(ptr: pointer to Char, c: Int, n: Int): pointer to Char; extern;
|
||||
|
||||
@ -85,6 +96,9 @@ begin
|
||||
n := 9;
|
||||
buffer[9] := '0';
|
||||
|
||||
if value = 0 then
|
||||
write_c('0')
|
||||
end;
|
||||
while value <> 0 do
|
||||
digit := value % 10;
|
||||
value := value / 10;
|
||||
@ -120,7 +134,7 @@ end;
|
||||
|
||||
proc is_space(c: Char): Bool;
|
||||
begin
|
||||
return c = ' ' or c = '\n'
|
||||
return c = ' ' or c = '\n' or c = '\t'
|
||||
end;
|
||||
|
||||
(*
|
||||
@ -171,6 +185,49 @@ begin
|
||||
return input
|
||||
end;
|
||||
|
||||
proc escape_char(escape: Char, result: pointer to Char): Bool;
|
||||
begin
|
||||
if escape = 'n' then
|
||||
result^ := '\n';
|
||||
return true
|
||||
elsif escape = 'a' then
|
||||
result^ := '\a';
|
||||
return true
|
||||
elsif escape = 'b' then
|
||||
result^ := '\b';
|
||||
return true
|
||||
elsif escape = 't' then
|
||||
result^ := '\t';
|
||||
return true
|
||||
elsif escape = 'f' then
|
||||
result^ := '\f';
|
||||
return true
|
||||
elsif escape = 'r' then
|
||||
result^ := '\r';
|
||||
return true
|
||||
elsif escape = 'v' then
|
||||
result^ := '\v';
|
||||
return true
|
||||
elsif escape = '\\' then
|
||||
result^ := '\\';
|
||||
return true
|
||||
elsif escape = '\'' then
|
||||
result^ := '\'';
|
||||
return true
|
||||
elsif escape = '"' then
|
||||
result^ := '"';
|
||||
return true
|
||||
elsif escape = '?' then
|
||||
result^ := '\?';
|
||||
return true
|
||||
elsif escape = '0' then
|
||||
result^ := '\0';
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end;
|
||||
|
||||
proc skip_spaces(input: pointer to Char): pointer to Char;
|
||||
begin
|
||||
while is_space(input^) do
|
||||
@ -203,12 +260,12 @@ begin
|
||||
return nil
|
||||
end;
|
||||
|
||||
proc print_tokens(tokens: pointer to Token, tokens_size: Int);
|
||||
proc print_tokens(tokens: pointer to Token, tokens_size: Word);
|
||||
var
|
||||
current_token: pointer to Token,
|
||||
i: Int;
|
||||
i: Word;
|
||||
begin
|
||||
i := 0;
|
||||
i := 0u;
|
||||
while i < tokens_size do
|
||||
current_token := tokens + i;
|
||||
|
||||
@ -295,35 +352,43 @@ begin
|
||||
elsif current_token^.kind = TOKEN_NOT_EQUAL then
|
||||
write_s("<>")
|
||||
elsif current_token^.kind = TOKEN_SEMICOLON then
|
||||
write_s(";")
|
||||
write_c(';')
|
||||
elsif current_token^.kind = TOKEN_DOT then
|
||||
write_s(".")
|
||||
write_c('.')
|
||||
elsif current_token^.kind = TOKEN_COMMA then
|
||||
write_s(",")
|
||||
write_c(',')
|
||||
elsif current_token^.kind = TOKEN_PLUS then
|
||||
write_s("+")
|
||||
write_c('+')
|
||||
elsif current_token^.kind = TOKEN_MINUS then
|
||||
write_s("-")
|
||||
write_c('-')
|
||||
elsif current_token^.kind = TOKEN_MULTIPLICATION then
|
||||
write_s("*")
|
||||
write_c('*')
|
||||
elsif current_token^.kind = TOKEN_DIVISION then
|
||||
write_s("/")
|
||||
write_c('/')
|
||||
elsif current_token^.kind = TOKEN_REMAINDER then
|
||||
write_s("%")
|
||||
write_c('%')
|
||||
elsif current_token^.kind = TOKEN_ASSIGNMENT then
|
||||
write_s(":=")
|
||||
elsif current_token^.kind = TOKEN_COLON then
|
||||
write_s(":")
|
||||
write_c(':')
|
||||
elsif current_token^.kind = TOKEN_HAT then
|
||||
write_s("^")
|
||||
write_c('^')
|
||||
elsif current_token^.kind = TOKEN_AT then
|
||||
write_s("@")
|
||||
write_c('@')
|
||||
elsif current_token^.kind = TOKEN_COMMENT then
|
||||
write_s("COMMENT")
|
||||
elsif current_token^.kind = TOKEN_INTEGER then
|
||||
write_c('<');
|
||||
write_i(current_token^.value.int_value);
|
||||
write_c('>')
|
||||
elsif current_token^.kind = TOKEN_WORD then
|
||||
write_c('<');
|
||||
write_i(current_token^.value.int_value);
|
||||
write_s("u>")
|
||||
elsif current_token^.kind = TOKEN_CHARACTER then
|
||||
write_c('<');
|
||||
write_i(current_token^.value.char_value);
|
||||
write_s("c>")
|
||||
else
|
||||
write_s("UNKNOWN<");
|
||||
write_i(current_token^.kind);
|
||||
@ -416,9 +481,9 @@ var
|
||||
token_length: Int,
|
||||
tokens: pointer to Token,
|
||||
current_token: pointer to Token,
|
||||
tokens_size: Int;
|
||||
tokens_size: Word;
|
||||
begin
|
||||
tokens_size := 0;
|
||||
tokens_size := 0u;
|
||||
tokens := cast(nil as pointer to Token);
|
||||
|
||||
input := read_source("example.elna");
|
||||
@ -439,8 +504,14 @@ begin
|
||||
elsif is_digit(input_pointer^) then
|
||||
token_end := cast(nil as pointer to Char);
|
||||
current_token^.value.int_value := strtol(input_pointer, @token_end, 10);
|
||||
current_token^.kind := TOKEN_INTEGER;
|
||||
input_pointer := token_end
|
||||
|
||||
if token_end^ = 'u' then
|
||||
current_token^.kind := TOKEN_WORD;
|
||||
input_pointer := token_end + 1
|
||||
else
|
||||
current_token^.kind := TOKEN_INTEGER;
|
||||
input_pointer := token_end
|
||||
end
|
||||
elsif input_pointer^ = '(' then
|
||||
input_pointer := input_pointer + 1;
|
||||
if input_pointer^ = '*' then
|
||||
@ -462,6 +533,20 @@ begin
|
||||
elsif input_pointer^ = ')' then
|
||||
current_token^.kind := TOKEN_RIGHT_PAREN;
|
||||
input_pointer := input_pointer + 1
|
||||
elsif input_pointer^ = '\'' then
|
||||
input_pointer := input_pointer + 1;
|
||||
if input_pointer^ = '\\' then
|
||||
input_pointer := input_pointer + 1;
|
||||
if escape_char(input_pointer^, @current_token^.value.char_value) then
|
||||
input_pointer := input_pointer + 1
|
||||
end
|
||||
elsif input_pointer^ <> '\0' then
|
||||
current_token^.value.char_value := input_pointer^
|
||||
end;
|
||||
if input_pointer^ = '\'' then
|
||||
current_token^.kind := TOKEN_CHARACTER;
|
||||
input_pointer := input_pointer + 1
|
||||
end
|
||||
elsif input_pointer^ = '[' then
|
||||
current_token^.kind := TOKEN_LEFT_SQUARE;
|
||||
input_pointer := input_pointer + 1
|
||||
|
@ -88,7 +88,7 @@ elna.stagefeedback: stagefeedback-start
|
||||
|
||||
ELNA_INCLUDES = -I $(srcdir)/elna/include -I elna/generated
|
||||
|
||||
elna/%.o: elna/source/%.cc elna/generated/parser.hh elna/generated/location.hh
|
||||
elna/%.o: elna/boot/%.cc elna/generated/parser.hh elna/generated/location.hh
|
||||
$(COMPILE) $(ELNA_INCLUDES) $<
|
||||
$(POSTCOMPILE)
|
||||
|
||||
@ -100,13 +100,13 @@ elna/%.o: elna/gcc/%.cc elna/generated/parser.hh elna/generated/location.hh
|
||||
$(COMPILE) $(ELNA_INCLUDES) $<
|
||||
$(POSTCOMPILE)
|
||||
|
||||
elna/generated/parser.cc: elna/source/parser.yy
|
||||
elna/generated/parser.cc: elna/boot/parser.yy
|
||||
mkdir -p $(dir $@)
|
||||
$(BISON) -d -o $@ $<
|
||||
|
||||
elna/generated/parser.hh elna/generated/location.hh: elna/generated/parser.cc
|
||||
@touch $@
|
||||
|
||||
elna/generated/lexer.cc: elna/source/lexer.ll
|
||||
elna/generated/lexer.cc: elna/boot/lexer.ll
|
||||
mkdir -p $(dir $@)
|
||||
$(FLEX) -o $@ $<
|
||||
|
@ -5,7 +5,7 @@ namespace elna
|
||||
{
|
||||
namespace gcc
|
||||
{
|
||||
location_t get_location(const elna::source::position *position)
|
||||
location_t get_location(const boot::position *position)
|
||||
{
|
||||
linemap_line_start(line_table, position->line, 0);
|
||||
|
||||
|
@ -16,12 +16,12 @@ namespace elna
|
||||
{
|
||||
namespace gcc
|
||||
{
|
||||
generic_visitor::generic_visitor(std::shared_ptr<source::symbol_table<tree>> symbol_table)
|
||||
generic_visitor::generic_visitor(std::shared_ptr<boot::symbol_table<tree>> symbol_table)
|
||||
{
|
||||
this->symbol_map = symbol_table;
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::call_expression *expression)
|
||||
void generic_visitor::visit(boot::call_expression *expression)
|
||||
{
|
||||
if (auto symbol = this->symbol_map->lookup(expression->name()))
|
||||
{
|
||||
@ -57,7 +57,7 @@ namespace gcc
|
||||
}
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::cast_expression *expression)
|
||||
void generic_visitor::visit(boot::cast_expression *expression)
|
||||
{
|
||||
tree cast_target = build_type(expression->target());
|
||||
gcc_assert(cast_target != NULL_TREE);
|
||||
@ -68,14 +68,23 @@ namespace gcc
|
||||
cast_target, this->current_expression);
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::size_of_expression *expression)
|
||||
void generic_visitor::visit(boot::size_of_expression *expression)
|
||||
{
|
||||
auto body_type = build_type(expression->body());
|
||||
|
||||
this->current_expression = build1(CONVERT_EXPR, integer_type_node, TYPE_SIZE_UNIT(body_type));
|
||||
this->current_expression = build1(CONVERT_EXPR,
|
||||
this->symbol_map->lookup("Word")->payload, TYPE_SIZE_UNIT(body_type));
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::program *program)
|
||||
bool generic_visitor::is_integral_type(tree type)
|
||||
{
|
||||
gcc_assert(TYPE_P(type));
|
||||
|
||||
return type == this->symbol_map->lookup("Int")->payload
|
||||
|| type == this->symbol_map->lookup("Word")->payload;
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::program *program)
|
||||
{
|
||||
for (const auto definition : program->value_definitions)
|
||||
{
|
||||
@ -119,7 +128,7 @@ namespace gcc
|
||||
cgraph_node::finalize_function(this->main_fndecl, true);
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::procedure_definition *definition)
|
||||
void generic_visitor::visit(boot::procedure_definition *definition)
|
||||
{
|
||||
std::vector<tree> parameter_types(definition->parameters.size());
|
||||
|
||||
@ -133,7 +142,7 @@ namespace gcc
|
||||
tree declaration_type = build_function_type_array(return_type,
|
||||
definition->parameters.size(), parameter_types.data());
|
||||
this->main_fndecl = build_fn_decl(definition->identifier().c_str(), declaration_type);
|
||||
this->symbol_map->enter(definition->identifier(), source::make_info(this->main_fndecl));
|
||||
this->symbol_map->enter(definition->identifier(), boot::make_info(this->main_fndecl));
|
||||
|
||||
if (definition->body() != nullptr)
|
||||
{
|
||||
@ -155,7 +164,7 @@ namespace gcc
|
||||
|
||||
if (definition->body() != nullptr)
|
||||
{
|
||||
this->symbol_map->enter(parameter->identifier(), source::make_info(declaration_tree));
|
||||
this->symbol_map->enter(parameter->identifier(), boot::make_info(declaration_tree));
|
||||
}
|
||||
argument_chain.append(declaration_tree);
|
||||
}
|
||||
@ -187,7 +196,7 @@ namespace gcc
|
||||
{
|
||||
this->current_statements = alloc_stmt_list();
|
||||
this->variable_chain = tree_chain();
|
||||
this->symbol_map = std::make_shared<source::symbol_table<tree>>(this->symbol_map);
|
||||
this->symbol_map = std::make_shared<boot::symbol_table<tree>>(this->symbol_map);
|
||||
}
|
||||
|
||||
tree_symbol_mapping generic_visitor::leave_scope()
|
||||
@ -201,17 +210,21 @@ namespace gcc
|
||||
return tree_symbol_mapping{ bind_expr, new_block };
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::number_literal<std::int32_t> *literal)
|
||||
void generic_visitor::visit(boot::number_literal<std::int32_t> *literal)
|
||||
{
|
||||
this->current_expression = build_int_cst(integer_type_node, literal->number());
|
||||
auto symbol = this->symbol_map->lookup("Int");
|
||||
|
||||
this->current_expression = build_int_cst(symbol->payload, literal->number());
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::number_literal<std::uint32_t> *literal)
|
||||
void generic_visitor::visit(boot::number_literal<std::uint32_t> *literal)
|
||||
{
|
||||
this->current_expression = build_int_cstu(unsigned_type_node, literal->number());
|
||||
auto symbol = this->symbol_map->lookup("Word");
|
||||
|
||||
this->current_expression = build_int_cstu(symbol->payload, literal->number());
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::number_literal<double> *literal)
|
||||
void generic_visitor::visit(boot::number_literal<double> *literal)
|
||||
{
|
||||
REAL_VALUE_TYPE real_value1;
|
||||
|
||||
@ -226,27 +239,27 @@ namespace gcc
|
||||
mpfr_clear(number);
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::number_literal<bool> *boolean)
|
||||
void generic_visitor::visit(boot::number_literal<bool> *boolean)
|
||||
{
|
||||
this->current_expression = build_int_cst_type(boolean_type_node, boolean->number());
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::number_literal<unsigned char> *character)
|
||||
void generic_visitor::visit(boot::number_literal<unsigned char> *character)
|
||||
{
|
||||
this->current_expression = build_int_cstu(elna_char_type_node, character->number());
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::number_literal<nullptr_t> *)
|
||||
void generic_visitor::visit(boot::number_literal<nullptr_t> *)
|
||||
{
|
||||
this->current_expression = null_pointer_node;
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::string_literal *string)
|
||||
void generic_visitor::visit(boot::string_literal *string)
|
||||
{
|
||||
this->current_expression = build_string_literal(string->string().size() + 1, string->string().c_str());
|
||||
}
|
||||
|
||||
void generic_visitor::build_binary_operation(bool condition, source::binary_expression *expression,
|
||||
void generic_visitor::build_binary_operation(bool condition, boot::binary_expression *expression,
|
||||
tree_code operator_code, tree left, tree right, tree target_type)
|
||||
{
|
||||
auto expression_location = get_location(&expression->position());
|
||||
@ -263,12 +276,12 @@ namespace gcc
|
||||
error_at(expression_location,
|
||||
"invalid operands of type %s and %s for operator %s",
|
||||
print_type(left_type), print_type(right_type),
|
||||
elna::source::print_binary_operator(expression->operation()));
|
||||
elna::boot::print_binary_operator(expression->operation()));
|
||||
this->current_expression = error_mark_node;
|
||||
}
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::binary_expression *expression)
|
||||
void generic_visitor::visit(boot::binary_expression *expression)
|
||||
{
|
||||
expression->lhs().accept(this);
|
||||
auto left = this->current_expression;
|
||||
@ -282,9 +295,8 @@ namespace gcc
|
||||
tree_code operator_code = ERROR_MARK;
|
||||
tree target_type = error_mark_node;
|
||||
|
||||
if (is_pointer_type(left_type)
|
||||
&& (right_type == integer_type_node || right_type == unsigned_type_node)
|
||||
&& expression->operation() == source::binary_operator::sum)
|
||||
if (is_pointer_type(left_type) && is_integral_type(right_type)
|
||||
&& expression->operation() == boot::binary_operator::sum)
|
||||
{
|
||||
tree convert_expression = build1_loc(expression_location, CONVERT_EXPR,
|
||||
sizetype, right);
|
||||
@ -297,45 +309,45 @@ namespace gcc
|
||||
error_at(expression_location,
|
||||
"invalid operands of type %s and %s for operator %s",
|
||||
print_type(left_type), print_type(right_type),
|
||||
elna::source::print_binary_operator(expression->operation()));
|
||||
boot::print_binary_operator(expression->operation()));
|
||||
this->current_expression = error_mark_node;
|
||||
return;
|
||||
}
|
||||
switch (expression->operation())
|
||||
{
|
||||
case source::binary_operator::sum:
|
||||
case boot::binary_operator::sum:
|
||||
operator_code = PLUS_EXPR;
|
||||
target_type = left_type;
|
||||
break;
|
||||
case source::binary_operator::subtraction:
|
||||
case boot::binary_operator::subtraction:
|
||||
operator_code = MINUS_EXPR;
|
||||
target_type = left_type;
|
||||
break;
|
||||
case source::binary_operator::division:
|
||||
case boot::binary_operator::division:
|
||||
operator_code = TRUNC_DIV_EXPR;
|
||||
target_type = left_type;
|
||||
break;
|
||||
case source::binary_operator::remainder:
|
||||
case boot::binary_operator::remainder:
|
||||
operator_code = TRUNC_MOD_EXPR;
|
||||
target_type = left_type;
|
||||
break;
|
||||
case source::binary_operator::multiplication:
|
||||
case boot::binary_operator::multiplication:
|
||||
operator_code = MULT_EXPR;
|
||||
target_type = left_type;
|
||||
break;
|
||||
case source::binary_operator::less:
|
||||
case boot::binary_operator::less:
|
||||
operator_code = LT_EXPR;
|
||||
target_type = boolean_type_node;
|
||||
break;
|
||||
case source::binary_operator::greater:
|
||||
case boot::binary_operator::greater:
|
||||
operator_code = GT_EXPR;
|
||||
target_type = boolean_type_node;
|
||||
break;
|
||||
case source::binary_operator::less_equal:
|
||||
case boot::binary_operator::less_equal:
|
||||
operator_code = LE_EXPR;
|
||||
target_type = boolean_type_node;
|
||||
break;
|
||||
case source::binary_operator::greater_equal:
|
||||
case boot::binary_operator::greater_equal:
|
||||
operator_code = GE_EXPR;
|
||||
target_type = boolean_type_node;
|
||||
break;
|
||||
@ -344,17 +356,17 @@ namespace gcc
|
||||
}
|
||||
if (operator_code != ERROR_MARK) // An arithmetic operation.
|
||||
{
|
||||
build_binary_operation(left_type == integer_type_node || left_type == double_type_node,
|
||||
build_binary_operation(is_integral_type(left_type) || left_type == double_type_node,
|
||||
expression, operator_code, left, right, target_type);
|
||||
return;
|
||||
}
|
||||
switch (expression->operation())
|
||||
{
|
||||
case source::binary_operator::conjunction:
|
||||
case boot::binary_operator::conjunction:
|
||||
operator_code = TRUTH_ANDIF_EXPR;
|
||||
target_type = boolean_type_node;
|
||||
break;
|
||||
case source::binary_operator::disjunction:
|
||||
case boot::binary_operator::disjunction:
|
||||
operator_code = TRUTH_ORIF_EXPR;
|
||||
target_type = boolean_type_node;
|
||||
break;
|
||||
@ -369,11 +381,11 @@ namespace gcc
|
||||
}
|
||||
switch (expression->operation())
|
||||
{
|
||||
case source::binary_operator::equals:
|
||||
case boot::binary_operator::equals:
|
||||
operator_code = EQ_EXPR;
|
||||
target_type = boolean_type_node;
|
||||
break;
|
||||
case source::binary_operator::not_equals:
|
||||
case boot::binary_operator::not_equals:
|
||||
operator_code = NE_EXPR;
|
||||
target_type = boolean_type_node;
|
||||
break;
|
||||
@ -387,34 +399,34 @@ namespace gcc
|
||||
operator_code, target_type, left, right);
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::unary_expression *expression)
|
||||
void generic_visitor::visit(boot::unary_expression *expression)
|
||||
{
|
||||
expression->operand().accept(this);
|
||||
|
||||
switch (expression->operation())
|
||||
{
|
||||
case source::unary_operator::reference:
|
||||
case boot::unary_operator::reference:
|
||||
TREE_ADDRESSABLE(this->current_expression) = 1;
|
||||
this->current_expression = build_fold_addr_expr_with_type_loc(get_location(&expression->position()),
|
||||
this->current_expression,
|
||||
build_pointer_type_for_mode(TREE_TYPE(this->current_expression), VOIDmode, true));
|
||||
TREE_NO_TRAMPOLINE(this->current_expression) = 1;
|
||||
break;
|
||||
case source::unary_operator::negation:
|
||||
case boot::unary_operator::negation:
|
||||
this->current_expression = build1_loc(get_location(&expression->position()), TRUTH_NOT_EXPR,
|
||||
boolean_type_node, this->current_expression);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::constant_definition *definition)
|
||||
void generic_visitor::visit(boot::constant_definition *definition)
|
||||
{
|
||||
location_t definition_location = get_location(&definition->position());
|
||||
definition->body().accept(this);
|
||||
|
||||
tree definition_tree = build_decl(definition_location, CONST_DECL,
|
||||
get_identifier(definition->identifier().c_str()), TREE_TYPE(this->current_expression));
|
||||
auto result = this->symbol_map->enter(definition->identifier(), source::make_info(definition_tree));
|
||||
auto result = this->symbol_map->enter(definition->identifier(), boot::make_info(definition_tree));
|
||||
|
||||
if (result)
|
||||
{
|
||||
@ -435,7 +447,7 @@ namespace gcc
|
||||
this->current_expression = NULL_TREE;
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::type_definition *definition)
|
||||
void generic_visitor::visit(boot::type_definition *definition)
|
||||
{
|
||||
tree tree_type = build_type(definition->body());
|
||||
|
||||
@ -446,7 +458,7 @@ namespace gcc
|
||||
location_t definition_location = get_location(&definition->position());
|
||||
tree definition_tree = build_decl(definition_location, TYPE_DECL,
|
||||
get_identifier(definition->identifier().c_str()), tree_type);
|
||||
auto result = this->symbol_map->enter(definition->identifier(), source::make_info(tree_type));
|
||||
auto result = this->symbol_map->enter(definition->identifier(), boot::make_info(tree_type));
|
||||
|
||||
if (result)
|
||||
{
|
||||
@ -465,9 +477,9 @@ namespace gcc
|
||||
}
|
||||
}
|
||||
|
||||
tree generic_visitor::build_type(source::type_expression& type)
|
||||
tree generic_visitor::build_type(boot::type_expression& type)
|
||||
{
|
||||
if (source::basic_type_expression *basic_type = type.is_basic())
|
||||
if (boot::basic_type_expression *basic_type = type.is_basic())
|
||||
{
|
||||
auto symbol = this->symbol_map->lookup(basic_type->base_name());
|
||||
|
||||
@ -480,7 +492,7 @@ namespace gcc
|
||||
|
||||
return error_mark_node;
|
||||
}
|
||||
else if (source::array_type_expression *array_type = type.is_array())
|
||||
else if (boot::array_type_expression *array_type = type.is_array())
|
||||
{
|
||||
tree lower_bound = build_int_cst_type(integer_type_node, 0);
|
||||
tree upper_bound = build_int_cst_type(integer_type_node, array_type->size);
|
||||
@ -494,7 +506,7 @@ namespace gcc
|
||||
|
||||
return build_array_type(base_type, range_type);
|
||||
}
|
||||
else if (source::pointer_type_expression *pointer_type = type.is_pointer())
|
||||
else if (boot::pointer_type_expression *pointer_type = type.is_pointer())
|
||||
{
|
||||
tree base_type = build_type(pointer_type->base());
|
||||
|
||||
@ -504,7 +516,7 @@ namespace gcc
|
||||
}
|
||||
return build_pointer_type_for_mode(base_type, VOIDmode, true);
|
||||
}
|
||||
else if (source::record_type_expression *record_type = type.is_record())
|
||||
else if (boot::record_type_expression *record_type = type.is_record())
|
||||
{
|
||||
std::set<std::string> field_names;
|
||||
tree record_type_node = make_node(RECORD_TYPE);
|
||||
@ -536,7 +548,7 @@ namespace gcc
|
||||
|
||||
return record_type_node;
|
||||
}
|
||||
else if (source::union_type_expression *union_type = type.is_union())
|
||||
else if (boot::union_type_expression *union_type = type.is_union())
|
||||
{
|
||||
std::set<std::string> field_names;
|
||||
tree union_type_node = make_node(UNION_TYPE);
|
||||
@ -571,7 +583,7 @@ namespace gcc
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::variable_declaration *declaration)
|
||||
void generic_visitor::visit(boot::variable_declaration *declaration)
|
||||
{
|
||||
tree declaration_type = build_type(declaration->type());
|
||||
gcc_assert(declaration_type != NULL_TREE);
|
||||
@ -579,7 +591,7 @@ namespace gcc
|
||||
auto declaration_location = get_location(&declaration->position());
|
||||
tree declaration_tree = build_decl(declaration_location, VAR_DECL,
|
||||
get_identifier(declaration->identifier().c_str()), declaration_type);
|
||||
auto result = this->symbol_map->enter(declaration->identifier(), source::make_info(declaration_tree));
|
||||
auto result = this->symbol_map->enter(declaration->identifier(), boot::make_info(declaration_tree));
|
||||
|
||||
if (result)
|
||||
{
|
||||
@ -598,7 +610,7 @@ namespace gcc
|
||||
}
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::variable_expression *expression)
|
||||
void generic_visitor::visit(boot::variable_expression *expression)
|
||||
{
|
||||
auto symbol = this->symbol_map->lookup(expression->name());
|
||||
|
||||
@ -613,7 +625,7 @@ namespace gcc
|
||||
this->current_expression = symbol->payload;
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::array_access_expression *expression)
|
||||
void generic_visitor::visit(boot::array_access_expression *expression)
|
||||
{
|
||||
expression->base().accept(this);
|
||||
tree designator = this->current_expression;
|
||||
@ -627,7 +639,7 @@ namespace gcc
|
||||
ARRAY_REF, element_type, designator, index, NULL_TREE, NULL_TREE);
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::field_access_expression *expression)
|
||||
void generic_visitor::visit(boot::field_access_expression *expression)
|
||||
{
|
||||
expression->base().accept(this);
|
||||
tree field_declaration = TYPE_FIELDS(TREE_TYPE(this->current_expression));
|
||||
@ -659,7 +671,7 @@ namespace gcc
|
||||
}
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::dereference_expression *expression)
|
||||
void generic_visitor::visit(boot::dereference_expression *expression)
|
||||
{
|
||||
expression->base().accept(this);
|
||||
|
||||
@ -667,7 +679,7 @@ namespace gcc
|
||||
TREE_TYPE(TREE_TYPE(this->current_expression)), this->current_expression);
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::assign_statement *statement)
|
||||
void generic_visitor::visit(boot::assign_statement *statement)
|
||||
{
|
||||
statement->lvalue().accept(this);
|
||||
|
||||
@ -699,7 +711,7 @@ namespace gcc
|
||||
this->current_expression = NULL_TREE;
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::if_statement *statement)
|
||||
void generic_visitor::visit(boot::if_statement *statement)
|
||||
{
|
||||
tree endif_label_decl = build_label_decl("endif", UNKNOWN_LOCATION);
|
||||
tree goto_endif = build1(GOTO_EXPR, void_type_node, endif_label_decl);
|
||||
@ -723,7 +735,7 @@ namespace gcc
|
||||
this->current_expression = NULL_TREE;
|
||||
}
|
||||
|
||||
void generic_visitor::make_if_branch(source::conditional_statements& branch, tree goto_endif)
|
||||
void generic_visitor::make_if_branch(boot::conditional_statements& branch, tree goto_endif)
|
||||
{
|
||||
branch.prerequisite().accept(this);
|
||||
|
||||
@ -767,7 +779,7 @@ namespace gcc
|
||||
return label_decl;
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::while_statement *statement)
|
||||
void generic_visitor::visit(boot::while_statement *statement)
|
||||
{
|
||||
statement->body().prerequisite().accept(this);
|
||||
|
||||
@ -816,15 +828,15 @@ namespace gcc
|
||||
this->current_expression = NULL_TREE;
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::expression_statement *statement)
|
||||
void generic_visitor::visit(boot::call_statement *statement)
|
||||
{
|
||||
statement->body().accept(this);
|
||||
append_to_statement_list(this->current_expression, &this->current_statements);
|
||||
}
|
||||
|
||||
void generic_visitor::visit(source::return_statement *statement)
|
||||
void generic_visitor::visit(boot::return_statement *statement)
|
||||
{
|
||||
source::expression *return_expression = statement->return_expression();
|
||||
boot::expression *return_expression = statement->return_expression();
|
||||
|
||||
if (return_expression == nullptr)
|
||||
{
|
||||
|
@ -28,12 +28,6 @@ namespace gcc
|
||||
&& TYPE_MAIN_VARIANT(TREE_TYPE(type)) == char_type_node;
|
||||
}
|
||||
|
||||
bool is_integral_type(tree type)
|
||||
{
|
||||
gcc_assert(TYPE_P(type));
|
||||
return type == integer_type_node || type == unsigned_type_node;
|
||||
}
|
||||
|
||||
tree tree_chain_base::head()
|
||||
{
|
||||
return first;
|
||||
@ -74,17 +68,17 @@ namespace gcc
|
||||
return m_block;
|
||||
}
|
||||
|
||||
std::shared_ptr<elna::source::symbol_table<tree>> builtin_symbol_table()
|
||||
std::shared_ptr<boot::symbol_table<tree>> builtin_symbol_table()
|
||||
{
|
||||
std::shared_ptr<elna::source::symbol_table<tree>> initial_table =
|
||||
std::make_shared<elna::source::symbol_table<tree>>();
|
||||
std::shared_ptr<boot::symbol_table<tree>> initial_table =
|
||||
std::make_shared<boot::symbol_table<tree>>();
|
||||
|
||||
initial_table->enter("Int", source::make_info(integer_type_node));
|
||||
initial_table->enter("Word", source::make_info(unsigned_type_node));
|
||||
initial_table->enter("Bool", source::make_info(boolean_type_node));
|
||||
initial_table->enter("Float", source::make_info(double_type_node));
|
||||
initial_table->enter("Char", source::make_info(elna_char_type_node));
|
||||
initial_table->enter("String", source::make_info(elna_string_type_node));
|
||||
initial_table->enter("Int", boot::make_info(long_integer_type_node));
|
||||
initial_table->enter("Word", boot::make_info(size_type_node));
|
||||
initial_table->enter("Bool", boot::make_info(boolean_type_node));
|
||||
initial_table->enter("Float", boot::make_info(double_type_node));
|
||||
initial_table->enter("Char", boot::make_info(elna_char_type_node));
|
||||
initial_table->enter("String", boot::make_info(elna_string_type_node));
|
||||
|
||||
return initial_table;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include "common/common-target.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <elna/source/driver.h>
|
||||
#include <elna/boot/driver.h>
|
||||
#include "elna/gcc/elna-tree.h"
|
||||
#include "elna/gcc/elna-generic.h"
|
||||
#include "elna/gcc/elna-diagnostic.h"
|
||||
@ -84,8 +84,8 @@ static void elna_parse_file(const char *filename)
|
||||
fatal_error(UNKNOWN_LOCATION, "cannot open filename %s: %m", filename);
|
||||
}
|
||||
|
||||
elna::source::driver driver{ filename };
|
||||
elna::source::lexer lexer(file);
|
||||
elna::boot::driver driver{ filename };
|
||||
elna::boot::lexer lexer(file);
|
||||
yy::parser parser(lexer, driver);
|
||||
|
||||
linemap_add(line_table, LC_ENTER, 0, filename, 1);
|
||||
|
@ -7,11 +7,11 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "elna/source/result.h"
|
||||
#include "elna/boot/result.h"
|
||||
|
||||
namespace elna
|
||||
{
|
||||
namespace source
|
||||
namespace boot
|
||||
{
|
||||
enum class binary_operator
|
||||
{
|
||||
@ -47,7 +47,7 @@ namespace source
|
||||
class if_statement;
|
||||
class while_statement;
|
||||
class return_statement;
|
||||
class expression_statement;
|
||||
class call_statement;
|
||||
class block;
|
||||
class program;
|
||||
class binary_expression;
|
||||
@ -77,7 +77,7 @@ namespace source
|
||||
virtual void visit(call_expression *) = 0;
|
||||
virtual void visit(cast_expression *) = 0;
|
||||
virtual void visit(size_of_expression *) = 0;
|
||||
virtual void visit(expression_statement *) = 0;
|
||||
virtual void visit(call_statement *) = 0;
|
||||
virtual void visit(assign_statement *) = 0;
|
||||
virtual void visit(if_statement *) = 0;
|
||||
virtual void visit(while_statement *) = 0;
|
||||
@ -116,7 +116,7 @@ namespace source
|
||||
virtual void visit(call_expression *expression) override;
|
||||
virtual void visit(cast_expression *expression) override;
|
||||
virtual void visit(size_of_expression *expression) override;
|
||||
virtual void visit(expression_statement *statement) override;
|
||||
virtual void visit(call_statement *statement) override;
|
||||
virtual void visit(assign_statement *statement) override;
|
||||
virtual void visit(if_statement *) override;
|
||||
virtual void visit(while_statement *) override;
|
||||
@ -458,17 +458,17 @@ namespace source
|
||||
virtual ~size_of_expression() override;
|
||||
};
|
||||
|
||||
class expression_statement : public statement
|
||||
class call_statement : public statement
|
||||
{
|
||||
expression *m_body;
|
||||
call_expression *m_body;
|
||||
|
||||
public:
|
||||
expression_statement(const struct position position, expression *body);
|
||||
call_statement(const struct position position, call_expression *body);
|
||||
virtual void accept(parser_visitor *visitor) override;
|
||||
|
||||
expression& body();
|
||||
call_expression& body();
|
||||
|
||||
virtual ~expression_statement() override;
|
||||
virtual ~call_statement() override;
|
||||
};
|
||||
|
||||
/**
|
@ -5,12 +5,12 @@
|
||||
|
||||
#include <list>
|
||||
#include <optional>
|
||||
#include "elna/source/ast.h"
|
||||
#include "elna/boot/ast.h"
|
||||
#include "location.hh"
|
||||
|
||||
namespace elna
|
||||
{
|
||||
namespace source
|
||||
namespace boot
|
||||
{
|
||||
position make_position(const yy::location& location);
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
namespace elna
|
||||
{
|
||||
namespace source
|
||||
namespace boot
|
||||
{
|
||||
/**
|
||||
* Position in the source text.
|
@ -10,7 +10,7 @@
|
||||
|
||||
namespace elna
|
||||
{
|
||||
namespace source
|
||||
namespace boot
|
||||
{
|
||||
/**
|
||||
* Generic language entity information.
|
@ -6,13 +6,13 @@
|
||||
#include "input.h"
|
||||
#include "tree.h"
|
||||
|
||||
#include "elna/source/result.h"
|
||||
#include "elna/boot/result.h"
|
||||
|
||||
namespace elna
|
||||
{
|
||||
namespace gcc
|
||||
{
|
||||
location_t get_location(const elna::source::position *position);
|
||||
location_t get_location(const boot::position *position);
|
||||
|
||||
const char *print_type(tree type);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "elna/source/ast.h"
|
||||
#include "elna/source/symbol.h"
|
||||
#include "elna/boot/ast.h"
|
||||
#include "elna/boot/symbol.h"
|
||||
#include "elna/gcc/elna-tree.h"
|
||||
|
||||
#include "config.h"
|
||||
@ -17,54 +17,56 @@ namespace elna
|
||||
{
|
||||
namespace gcc
|
||||
{
|
||||
class generic_visitor final : public source::empty_visitor
|
||||
class generic_visitor final : public boot::empty_visitor
|
||||
{
|
||||
tree current_statements{ NULL_TREE };
|
||||
tree current_expression{ NULL_TREE };
|
||||
std::shared_ptr<source::symbol_table<tree>> symbol_map;
|
||||
std::shared_ptr<boot::symbol_table<tree>> symbol_map;
|
||||
tree main_fndecl{ NULL_TREE };
|
||||
tree_chain variable_chain;
|
||||
|
||||
tree build_label_decl(const char *name, location_t loc);
|
||||
tree build_type(source::type_expression& type);
|
||||
tree build_type(boot::type_expression& type);
|
||||
|
||||
void enter_scope();
|
||||
tree_symbol_mapping leave_scope();
|
||||
|
||||
void build_binary_operation(bool condition, source::binary_expression *expression,
|
||||
void build_binary_operation(bool condition, boot::binary_expression *expression,
|
||||
tree_code operator_code, tree left, tree right, tree target_type);
|
||||
|
||||
void make_if_branch(source::conditional_statements& branch, tree goto_endif);
|
||||
void make_if_branch(boot::conditional_statements& branch, tree goto_endif);
|
||||
|
||||
bool is_integral_type(tree type);
|
||||
|
||||
public:
|
||||
generic_visitor(std::shared_ptr<source::symbol_table<tree>> symbol_table);
|
||||
generic_visitor(std::shared_ptr<boot::symbol_table<tree>> symbol_table);
|
||||
|
||||
void visit(source::program *program) override;
|
||||
void visit(source::procedure_definition *definition) override;
|
||||
void visit(source::call_expression *expression) override;
|
||||
void visit(source::cast_expression *expression) override;
|
||||
void visit(source::size_of_expression *expression) override;
|
||||
void visit(source::number_literal<std::int32_t> *literal) override;
|
||||
void visit(source::number_literal<std::uint32_t> *literal) override;
|
||||
void visit(source::number_literal<double> *literal) override;
|
||||
void visit(source::number_literal<bool> *boolean) override;
|
||||
void visit(source::number_literal<unsigned char> *character) override;
|
||||
void visit(source::number_literal<std::nullptr_t> *) override;
|
||||
void visit(source::string_literal *string) 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::type_definition *definition) override;
|
||||
void visit(source::variable_declaration *declaration) override;
|
||||
void visit(source::variable_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::if_statement *statement) override;
|
||||
void visit(source::while_statement *statement) override;
|
||||
void visit(source::expression_statement *statement) override;
|
||||
void visit(source::return_statement *statement) override;
|
||||
void visit(boot::program *program) override;
|
||||
void visit(boot::procedure_definition *definition) override;
|
||||
void visit(boot::call_expression *expression) override;
|
||||
void visit(boot::cast_expression *expression) override;
|
||||
void visit(boot::size_of_expression *expression) override;
|
||||
void visit(boot::number_literal<std::int32_t> *literal) override;
|
||||
void visit(boot::number_literal<std::uint32_t> *literal) override;
|
||||
void visit(boot::number_literal<double> *literal) override;
|
||||
void visit(boot::number_literal<bool> *boolean) override;
|
||||
void visit(boot::number_literal<unsigned char> *character) override;
|
||||
void visit(boot::number_literal<std::nullptr_t> *) override;
|
||||
void visit(boot::string_literal *string) override;
|
||||
void visit(boot::binary_expression *expression) override;
|
||||
void visit(boot::unary_expression *expression) override;
|
||||
void visit(boot::constant_definition *definition) override;
|
||||
void visit(boot::type_definition *definition) override;
|
||||
void visit(boot::variable_declaration *declaration) override;
|
||||
void visit(boot::variable_expression *expression) override;
|
||||
void visit(boot::array_access_expression *expression) override;
|
||||
void visit(boot::field_access_expression *expression) override;
|
||||
void visit(boot::dereference_expression *expression) override;
|
||||
void visit(boot::assign_statement *statement) override;
|
||||
void visit(boot::if_statement *statement) override;
|
||||
void visit(boot::while_statement *statement) override;
|
||||
void visit(boot::call_statement *statement) override;
|
||||
void visit(boot::return_statement *statement) override;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "tree.h"
|
||||
#include "tree.h"
|
||||
|
||||
#include "elna/source/symbol.h"
|
||||
#include "elna/boot/symbol.h"
|
||||
|
||||
enum elna_tree_index
|
||||
{
|
||||
@ -27,7 +27,6 @@ namespace gcc
|
||||
void init_ttree();
|
||||
bool is_pointer_type(tree type);
|
||||
bool is_string_type(tree type);
|
||||
bool is_integral_type(tree type);
|
||||
|
||||
class tree_chain_base
|
||||
{
|
||||
@ -60,6 +59,6 @@ namespace gcc
|
||||
tree block();
|
||||
};
|
||||
|
||||
std::shared_ptr<source::symbol_table<tree>> builtin_symbol_table();
|
||||
std::shared_ptr<boot::symbol_table<tree>> builtin_symbol_table();
|
||||
}
|
||||
}
|
||||
|
474
source/parser.yy
474
source/parser.yy
@ -1,474 +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/.
|
||||
*/
|
||||
%require "3.2"
|
||||
%language "c++"
|
||||
|
||||
%code requires {
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include "elna/source/driver.h"
|
||||
|
||||
#if !defined(yyFlexLexerOnce)
|
||||
#include <FlexLexer.h>
|
||||
#endif
|
||||
|
||||
namespace elna::source
|
||||
{
|
||||
class lexer;
|
||||
}
|
||||
}
|
||||
|
||||
%code provides {
|
||||
namespace elna::source
|
||||
{
|
||||
|
||||
class lexer: public yyFlexLexer
|
||||
{
|
||||
public:
|
||||
yy::location location;
|
||||
|
||||
lexer(std::istream& arg_yyin)
|
||||
: yyFlexLexer(&arg_yyin)
|
||||
{
|
||||
}
|
||||
|
||||
yy::parser::symbol_type lex(elna::source::driver& driver);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
%define api.token.raw
|
||||
%define api.token.constructor
|
||||
%define api.value.type variant
|
||||
|
||||
%parse-param {elna::source::lexer& lexer}
|
||||
%param {elna::source::driver& driver}
|
||||
%locations
|
||||
|
||||
%header
|
||||
|
||||
%code {
|
||||
#define yylex lexer.lex
|
||||
}
|
||||
%start program;
|
||||
|
||||
%token <std::string> IDENTIFIER "identifier"
|
||||
%token <std::int32_t> INTEGER "integer"
|
||||
%token <std::uint32_t> WORD "word"
|
||||
%token <float> FLOAT "float"
|
||||
%token <std::string> CHARACTER "character"
|
||||
%token <std::string> STRING "string"
|
||||
%token <bool> BOOLEAN
|
||||
%token IF WHILE DO THEN ELSE ELSIF RETURN
|
||||
%token CONST VAR PROCEDURE ARRAY OF TYPE RECORD POINTER TO UNION
|
||||
%token BEGIN_BLOCK END_BLOCK EXTERN
|
||||
%token LEFT_PAREN RIGHT_PAREN LEFT_SQUARE RIGHT_SQUARE SEMICOLON DOT COMMA
|
||||
%token AND OR NOT CAST AS SIZEOF
|
||||
%token GREATER_EQUAL LESS_EQUAL LESS_THAN GREATER_THAN NOT_EQUAL EQUALS
|
||||
%token PLUS MINUS MULTIPLICATION DIVISION REMAINDER
|
||||
%token ASSIGNMENT COLON HAT AT NIL
|
||||
|
||||
%type <elna::source::literal *> literal;
|
||||
%type <elna::source::constant_definition *> constant_definition;
|
||||
%type <std::vector<elna::source::constant_definition *>> constant_part constant_definitions;
|
||||
%type <elna::source::variable_declaration *> variable_declaration;
|
||||
%type <std::vector<elna::source::variable_declaration *>> variable_declarations variable_part
|
||||
formal_parameter_list;
|
||||
%type <elna::source::type_expression *> type_expression;
|
||||
%type <elna::source::expression *> expression pointer summand factor comparand logical_operand;
|
||||
%type <std::vector<elna::source::expression *>> expressions actual_parameter_list;
|
||||
%type <elna::source::designator_expression *> designator_expression;
|
||||
%type <elna::source::assign_statement *> assign_statement;
|
||||
%type <elna::source::call_expression *> call_expression;
|
||||
%type <elna::source::while_statement *> while_statement;
|
||||
%type <elna::source::if_statement *> if_statement;
|
||||
%type <elna::source::return_statement *> return_statement;
|
||||
%type <elna::source::statement *> statement;
|
||||
%type <std::vector<elna::source::statement *>> statements optional_statements;
|
||||
%type <elna::source::procedure_definition *> procedure_definition;
|
||||
%type <std::vector<elna::source::procedure_definition *>> procedure_definitions procedure_part;
|
||||
%type <elna::source::type_definition *> type_definition;
|
||||
%type <std::vector<elna::source::type_definition *>> type_definitions type_part;
|
||||
%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;
|
||||
%type <std::vector<elna::source::conditional_statements *>> elsif_statement_list;
|
||||
%type <elna::source::cast_expression *> cast_expression;
|
||||
%%
|
||||
program:
|
||||
type_part constant_part procedure_part variable_part BEGIN_BLOCK optional_statements END_BLOCK DOT
|
||||
{
|
||||
std::vector<elna::source::definition *> definitions($1.size() + $3.size());
|
||||
std::vector<elna::source::definition *>::iterator definition = definitions.begin();
|
||||
std::vector<elna::source::definition *> value_definitions($2.size() + $4.size());
|
||||
std::vector<elna::source::definition *>::iterator value_definition = value_definitions.begin();
|
||||
|
||||
for (auto type : $1)
|
||||
{
|
||||
*definition++ = type;
|
||||
}
|
||||
for (auto constant : $2)
|
||||
{
|
||||
*value_definition++ = constant;
|
||||
}
|
||||
for (auto procedure : $3)
|
||||
{
|
||||
*definition++ = procedure;
|
||||
}
|
||||
for (auto variable : $4)
|
||||
{
|
||||
*value_definition++ = variable;
|
||||
}
|
||||
auto tree = new elna::source::program(elna::source::make_position(@5),
|
||||
std::move(definitions), std::move(value_definitions), std::move($6));
|
||||
|
||||
driver.tree.reset(tree);
|
||||
}
|
||||
block: constant_part variable_part BEGIN_BLOCK optional_statements END_BLOCK
|
||||
{
|
||||
std::vector<elna::source::definition *> definitions($1.size() + $2.size());
|
||||
std::vector<elna::source::definition *>::iterator definition = definitions.begin();
|
||||
|
||||
for (auto constant : $1)
|
||||
{
|
||||
*definition++ = constant;
|
||||
}
|
||||
for (auto variable : $2)
|
||||
{
|
||||
*definition++ = variable;
|
||||
}
|
||||
$$ = new elna::source::block(elna::source::make_position(@3),
|
||||
std::move(definitions), std::move($4));
|
||||
}
|
||||
procedure_definition:
|
||||
PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON block SEMICOLON
|
||||
{
|
||||
$$ = new elna::source::procedure_definition(elna::source::make_position(@1),
|
||||
$2, std::move($3), nullptr, $5);
|
||||
}
|
||||
| PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON EXTERN SEMICOLON
|
||||
{
|
||||
$$ = new elna::source::procedure_definition(elna::source::make_position(@1),
|
||||
$2, std::move($3), nullptr, nullptr);
|
||||
}
|
||||
| PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON block SEMICOLON
|
||||
{
|
||||
$$ = new elna::source::procedure_definition(elna::source::make_position(@1),
|
||||
$2, std::move($3), $5, $7);
|
||||
}
|
||||
| PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON EXTERN SEMICOLON
|
||||
{
|
||||
$$ = new elna::source::procedure_definition(elna::source::make_position(@1),
|
||||
$2, std::move($3), $5, nullptr);
|
||||
}
|
||||
procedure_definitions:
|
||||
procedure_definition procedure_definitions
|
||||
{
|
||||
std::swap($$, $2);
|
||||
$$.emplace($$.cbegin(), std::move($1));
|
||||
}
|
||||
| procedure_definition { $$.emplace_back(std::move($1)); }
|
||||
procedure_part:
|
||||
/* no procedure definitions */ {}
|
||||
| procedure_definitions { std::swap($$, $1); }
|
||||
assign_statement: designator_expression ASSIGNMENT expression
|
||||
{
|
||||
$$ = new elna::source::assign_statement(elna::source::make_position(@1), $1, $3);
|
||||
}
|
||||
call_expression: IDENTIFIER actual_parameter_list
|
||||
{
|
||||
$$ = new elna::source::call_expression(elna::source::make_position(@1), $1);
|
||||
std::swap($$->arguments(), $2);
|
||||
}
|
||||
cast_expression: CAST LEFT_PAREN expression AS type_expression RIGHT_PAREN
|
||||
{
|
||||
$$ = new elna::source::cast_expression(elna::source::make_position(@1), $5, $3);
|
||||
}
|
||||
while_statement: WHILE expression DO optional_statements END_BLOCK
|
||||
{
|
||||
auto body = new elna::source::conditional_statements($2);
|
||||
std::swap($4, body->statements);
|
||||
$$ = new elna::source::while_statement(elna::source::make_position(@1), body);
|
||||
}
|
||||
elsif_statement_list:
|
||||
ELSIF expression THEN optional_statements elsif_statement_list
|
||||
{
|
||||
elna::source::conditional_statements *branch = new elna::source::conditional_statements($2);
|
||||
std::swap(branch->statements, $4);
|
||||
std::swap($5, $$);
|
||||
$$.emplace($$.begin(), branch);
|
||||
}
|
||||
| {}
|
||||
if_statement:
|
||||
IF expression THEN optional_statements elsif_statement_list END_BLOCK
|
||||
{
|
||||
auto then = new elna::source::conditional_statements($2);
|
||||
std::swap($4, then->statements);
|
||||
$$ = new elna::source::if_statement(elna::source::make_position(@1), then);
|
||||
std::swap($5, $$->branches);
|
||||
}
|
||||
| IF expression THEN optional_statements elsif_statement_list ELSE optional_statements END_BLOCK
|
||||
{
|
||||
auto then = new elna::source::conditional_statements($2);
|
||||
std::swap($4, then->statements);
|
||||
auto _else = new std::vector<elna::source::statement *>(std::move($7));
|
||||
$$ = new elna::source::if_statement(elna::source::make_position(@1), then, _else);
|
||||
std::swap($5, $$->branches);
|
||||
}
|
||||
return_statement:
|
||||
RETURN expression
|
||||
{
|
||||
$$ = new elna::source::return_statement(elna::source::make_position(@1), $2);
|
||||
}
|
||||
literal:
|
||||
INTEGER
|
||||
{
|
||||
$$ = new elna::source::number_literal<std::int32_t>(elna::source::make_position(@1), $1);
|
||||
}
|
||||
| WORD
|
||||
{
|
||||
$$ = new elna::source::number_literal<std::uint32_t>(elna::source::make_position(@1), $1);
|
||||
}
|
||||
| FLOAT
|
||||
{
|
||||
$$ = new elna::source::number_literal<double>(elna::source::make_position(@1), $1);
|
||||
}
|
||||
| BOOLEAN
|
||||
{
|
||||
$$ = new elna::source::number_literal<bool>(elna::source::make_position(@1), $1);
|
||||
}
|
||||
| CHARACTER
|
||||
{
|
||||
$$ = new elna::source::number_literal<unsigned char>(elna::source::make_position(@1), $1.at(0));
|
||||
}
|
||||
| NIL
|
||||
{
|
||||
$$ = new elna::source::number_literal<std::nullptr_t>(elna::source::make_position(@1), nullptr);
|
||||
}
|
||||
| STRING
|
||||
{
|
||||
$$ = new elna::source::string_literal(elna::source::make_position(@1), $1);
|
||||
}
|
||||
pointer:
|
||||
literal { $$ = $1; }
|
||||
| designator_expression { $$ = $1; }
|
||||
| SIZEOF LEFT_PAREN type_expression RIGHT_PAREN
|
||||
{
|
||||
$$ = new elna::source::size_of_expression(elna::source::make_position(@1), $3);
|
||||
}
|
||||
| cast_expression { $$ = $1; }
|
||||
| call_expression { $$ = $1; }
|
||||
| LEFT_PAREN expression RIGHT_PAREN { $$ = $2; }
|
||||
summand:
|
||||
factor { $$ = std::move($1); }
|
||||
| factor MULTIPLICATION factor
|
||||
{
|
||||
$$ = new elna::source::binary_expression(elna::source::make_position(@2), $1, $3,
|
||||
elna::source::binary_operator::multiplication);
|
||||
}
|
||||
| factor DIVISION factor
|
||||
{
|
||||
$$ = new elna::source::binary_expression(elna::source::make_position(@2), $1, $3,
|
||||
elna::source::binary_operator::division);
|
||||
}
|
||||
| factor REMAINDER factor
|
||||
{
|
||||
$$ = new elna::source::binary_expression(elna::source::make_position(@2), $1, $3,
|
||||
elna::source::binary_operator::remainder);
|
||||
}
|
||||
factor:
|
||||
AT pointer
|
||||
{
|
||||
$$ = new elna::source::unary_expression(elna::source::make_position(@1), $2,
|
||||
elna::source::unary_operator::reference);
|
||||
}
|
||||
| NOT pointer
|
||||
{
|
||||
$$ = new elna::source::unary_expression(elna::source::make_position(@1), $2,
|
||||
elna::source::unary_operator::negation);
|
||||
}
|
||||
| pointer { $$ = $1; }
|
||||
comparand:
|
||||
summand PLUS summand
|
||||
{
|
||||
$$ = new elna::source::binary_expression(elna::source::make_position(@2), $1, $3,
|
||||
elna::source::binary_operator::sum);
|
||||
}
|
||||
| summand MINUS summand
|
||||
{
|
||||
$$ = new elna::source::binary_expression(elna::source::make_position(@2), $1, $3,
|
||||
elna::source::binary_operator::subtraction);
|
||||
}
|
||||
| summand { $$ = std::move($1); }
|
||||
logical_operand:
|
||||
comparand EQUALS comparand
|
||||
{
|
||||
$$ = new elna::source::binary_expression(elna::source::make_position(@2), $1, $3,
|
||||
elna::source::binary_operator::equals);
|
||||
}
|
||||
| comparand NOT_EQUAL comparand
|
||||
{
|
||||
$$ = new elna::source::binary_expression(elna::source::make_position(@2), $1, $3,
|
||||
elna::source::binary_operator::not_equals);
|
||||
}
|
||||
| comparand LESS_THAN comparand
|
||||
{
|
||||
$$ = new elna::source::binary_expression(elna::source::make_position(@2), $1, $3,
|
||||
elna::source::binary_operator::less);
|
||||
}
|
||||
| comparand GREATER_THAN comparand
|
||||
{
|
||||
$$ = new elna::source::binary_expression(elna::source::make_position(@2), $1, $3,
|
||||
elna::source::binary_operator::greater);
|
||||
}
|
||||
| comparand LESS_EQUAL comparand
|
||||
{
|
||||
$$ = new elna::source::binary_expression(elna::source::make_position(@2), $1, $3,
|
||||
elna::source::binary_operator::less_equal);
|
||||
}
|
||||
| comparand GREATER_EQUAL comparand
|
||||
{
|
||||
$$ = new elna::source::binary_expression(elna::source::make_position(@2), $1, $3,
|
||||
elna::source::binary_operator::greater_equal);
|
||||
}
|
||||
| comparand { $$ = $1; }
|
||||
expression:
|
||||
logical_operand AND logical_operand
|
||||
{
|
||||
$$ = new elna::source::binary_expression(elna::source::make_position(@2), $1, $3,
|
||||
elna::source::binary_operator::conjunction);
|
||||
}
|
||||
| logical_operand OR logical_operand
|
||||
{
|
||||
$$ = new elna::source::binary_expression(elna::source::make_position(@2), $1, $3,
|
||||
elna::source::binary_operator::disjunction);
|
||||
}
|
||||
| logical_operand { $$ = $1; }
|
||||
expressions:
|
||||
expression COMMA expressions
|
||||
{
|
||||
std::swap($$, $3);
|
||||
$$.emplace($$.cbegin(), $1);
|
||||
}
|
||||
| expression { $$.emplace_back(std::move($1)); }
|
||||
designator_expression:
|
||||
designator_expression LEFT_SQUARE expression RIGHT_SQUARE
|
||||
{
|
||||
$$ = new elna::source::array_access_expression(elna::source::make_position(@1), $1, $3);
|
||||
}
|
||||
| designator_expression DOT IDENTIFIER
|
||||
{
|
||||
$$ = new elna::source::field_access_expression(elna::source::make_position(@2), $1, $3);
|
||||
}
|
||||
| designator_expression HAT
|
||||
{
|
||||
$$ = new elna::source::dereference_expression(elna::source::make_position(@1), $1);
|
||||
}
|
||||
| IDENTIFIER
|
||||
{
|
||||
$$ = new elna::source::variable_expression(elna::source::make_position(@1), $1);
|
||||
}
|
||||
statement:
|
||||
assign_statement { $$ = $1; }
|
||||
| while_statement { $$ = $1; }
|
||||
| if_statement { $$ = $1; }
|
||||
| return_statement { $$ = $1; }
|
||||
| expression { $$ = new elna::source::expression_statement(elna::source::make_position(@1), $1); }
|
||||
statements:
|
||||
statement SEMICOLON statements
|
||||
{
|
||||
std::swap($$, $3);
|
||||
$$.emplace($$.cbegin(), $1);
|
||||
}
|
||||
| statement { $$.push_back($1); }
|
||||
optional_statements:
|
||||
statements { std::swap($$, $1); }
|
||||
| /* 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:
|
||||
ARRAY INTEGER OF type_expression
|
||||
{
|
||||
$$ = new elna::source::array_type_expression(elna::source::make_position(@1), $4, $2);
|
||||
}
|
||||
| POINTER TO type_expression
|
||||
{
|
||||
$$ = new elna::source::pointer_type_expression(elna::source::make_position(@1), $3);
|
||||
}
|
||||
| RECORD field_list END_BLOCK
|
||||
{
|
||||
$$ = new elna::source::record_type_expression(elna::source::make_position(@1), std::move($2));
|
||||
}
|
||||
| UNION field_list END_BLOCK
|
||||
{
|
||||
$$ = new elna::source::union_type_expression(elna::source::make_position(@1), std::move($2));
|
||||
}
|
||||
| IDENTIFIER
|
||||
{
|
||||
$$ = new elna::source::basic_type_expression(elna::source::make_position(@1), $1);
|
||||
}
|
||||
variable_declaration: IDENTIFIER COLON type_expression
|
||||
{
|
||||
$$ = new elna::source::variable_declaration(elna::source::make_position(@1), $1, $3);
|
||||
}
|
||||
variable_declarations:
|
||||
variable_declaration COMMA variable_declarations
|
||||
{
|
||||
std::swap($$, $3);
|
||||
$$.emplace($$.cbegin(), $1);
|
||||
}
|
||||
| variable_declaration { $$.emplace_back(std::move($1)); }
|
||||
variable_part:
|
||||
/* no variable declarations */ {}
|
||||
| VAR variable_declarations SEMICOLON { std::swap($$, $2); }
|
||||
constant_definition: IDENTIFIER EQUALS literal
|
||||
{
|
||||
$$ = new elna::source::constant_definition(elna::source::make_position(@1), $1, $3);
|
||||
}
|
||||
constant_definitions:
|
||||
constant_definition COMMA constant_definitions
|
||||
{
|
||||
std::swap($$, $3);
|
||||
$$.emplace($$.cbegin(), std::move($1));
|
||||
}
|
||||
| constant_definition { $$.emplace_back(std::move($1)); }
|
||||
constant_part:
|
||||
/* no constant definitions */ {}
|
||||
| CONST constant_definitions SEMICOLON { std::swap($$, $2); }
|
||||
type_definition: IDENTIFIER EQUALS type_expression
|
||||
{
|
||||
$$ = new elna::source::type_definition(elna::source::make_position(@1), $1, $3);
|
||||
}
|
||||
type_definitions:
|
||||
type_definition COMMA type_definitions
|
||||
{
|
||||
std::swap($$, $3);
|
||||
$$.emplace($$.cbegin(), std::move($1));
|
||||
}
|
||||
| type_definition { $$.emplace_back(std::move($1)); }
|
||||
type_part:
|
||||
/* no type definitions */ {}
|
||||
| TYPE type_definitions SEMICOLON { std::swap($$, $2); }
|
||||
formal_parameter_list:
|
||||
LEFT_PAREN RIGHT_PAREN {}
|
||||
| LEFT_PAREN variable_declarations RIGHT_PAREN { std::swap($$, $2); }
|
||||
actual_parameter_list:
|
||||
LEFT_PAREN RIGHT_PAREN {}
|
||||
| LEFT_PAREN expressions RIGHT_PAREN { std::swap($$, $2); }
|
||||
%%
|
||||
|
||||
void yy::parser::error(const location_type& loc, const std::string& message)
|
||||
{
|
||||
driver.error(loc, message);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user