335 lines
12 KiB
Text
335 lines
12 KiB
Text
%skeleton "lalr1.cc"
|
|
%require "3.8.1"
|
|
%header
|
|
|
|
%language "C++"
|
|
%define api.namespace {pslang::parser::bison}
|
|
%define api.location.file "pslang/parser/location.hpp"
|
|
%define api.location.include "<pslang/parser/location.hpp>"
|
|
|
|
%define api.token.raw
|
|
%define api.token.constructor
|
|
%define api.value.type variant
|
|
%define api.value.automove
|
|
|
|
%define parse.assert
|
|
%define parse.trace
|
|
%define parse.error detailed
|
|
%define parse.lac full
|
|
|
|
%locations
|
|
|
|
%{
|
|
|
|
#include <stdio.h>
|
|
|
|
void yyerror(char const * s)
|
|
{
|
|
printf("error: %s\n", s);
|
|
}
|
|
|
|
%}
|
|
|
|
%code requires {
|
|
|
|
#include <pslang/ast/statement.hpp>
|
|
#include <pslang/parser/indented_statement.hpp>
|
|
|
|
namespace pslang::parser {
|
|
|
|
struct context;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
%code {
|
|
|
|
#include <pslang/parser/context.hpp>
|
|
#include <pslang/parser/error.hpp>
|
|
|
|
#include <stdexcept>
|
|
#include <sstream>
|
|
#include <charconv>
|
|
|
|
#define YY_DECL ::pslang::parser::bison::parser::symbol_type yylex(::pslang::parser::context& ctx)
|
|
YY_DECL;
|
|
|
|
template <typename T>
|
|
::pslang::ast::literal parse_numeric_literal(std::string const & str)
|
|
{
|
|
T value;
|
|
auto result = std::from_chars(str.data(), str.data() + str.size(), value);
|
|
if (result.ec != std::errc())
|
|
throw std::system_error(std::make_error_code(result.ec));
|
|
return ::pslang::ast::numeric_literal_base<T>{value};
|
|
}
|
|
|
|
}
|
|
|
|
%param { ::pslang::parser::context& ctx }
|
|
|
|
%define api.token.prefix {tok_}
|
|
|
|
%token newline "newline"
|
|
%token indent "indentation"
|
|
%token assignment "="
|
|
%token colon ":"
|
|
%token comma ","
|
|
%token lparen "("
|
|
%token rparen ")"
|
|
%token lbracket "["
|
|
%token rbracket "]"
|
|
%token plus "+"
|
|
%token minus "-"
|
|
%token asterisk "*"
|
|
%token slash "/"
|
|
%token percent "%"
|
|
%token ampersand "&"
|
|
%token vertical_bar "|"
|
|
%token circumflex "^"
|
|
%token exclamation "!"
|
|
%token equals "=="
|
|
%token not_equals "!="
|
|
%token less "<"
|
|
%token greater ">"
|
|
%token less_equals "<="
|
|
%token greater_equals ">="
|
|
%token arrow "->"
|
|
|
|
%token <std::string> lit_i8
|
|
%token <std::string> lit_u8
|
|
%token <std::string> lit_i16
|
|
%token <std::string> lit_u16
|
|
%token <std::string> lit_i32
|
|
%token <std::string> lit_u32
|
|
%token <std::string> lit_i64
|
|
%token <std::string> lit_u64
|
|
|
|
%token <std::string> lit_f8
|
|
%token <std::string> lit_f16
|
|
%token <std::string> lit_f32
|
|
%token <std::string> lit_f64
|
|
|
|
%token <std::string> name
|
|
|
|
%token const
|
|
%token let
|
|
%token mut
|
|
%token if
|
|
%token else
|
|
%token while
|
|
%token as
|
|
%token func
|
|
%token return
|
|
%token true
|
|
%token false
|
|
|
|
%token unit
|
|
%token bool
|
|
%token i8
|
|
%token u8
|
|
%token i16
|
|
%token u16
|
|
%token i32
|
|
%token u32
|
|
%token i64
|
|
%token u64
|
|
%token f32
|
|
%token f64
|
|
|
|
%token end 0
|
|
|
|
%type <indented_statement_list> indented_statement_list
|
|
%type <std::size_t> indentation
|
|
%type <ast::statement> statement
|
|
%type <std::vector<ast::function_definition::argument>> function_definition_argument_list
|
|
%type <std::vector<ast::function_definition::argument>> nonempty_function_definition_argument_list
|
|
%type <type::type_ptr> function_return_type
|
|
%type <ast::variable_declaration> variable_declaration
|
|
%type <ast::value_category> variable_keyword
|
|
%type <type::type> type_expression
|
|
%type <type::primitive_type> primitive_type
|
|
%type <ast::expression> expression
|
|
%type <ast::expression> bool_expression
|
|
%type <ast::expression> compare_expression
|
|
%type <ast::expression> as_expression
|
|
%type <ast::expression> negate_expression
|
|
%type <ast::expression> sum_expression
|
|
%type <ast::expression> mult_expression
|
|
%type <ast::expression> not_expression
|
|
%type <ast::expression> postfix_expression
|
|
%type <ast::expression> base_expression
|
|
%type <std::vector<ast::expression_ptr>> comma_separated_expression_list
|
|
%type <std::vector<ast::expression_ptr>> nonempty_comma_separated_expression_list
|
|
%type <ast::expression> literal
|
|
|
|
%%
|
|
|
|
module
|
|
: indented_statement_list end { ctx.result = $1; }
|
|
;
|
|
|
|
indented_statement_list
|
|
: indented_statement_list indentation statement newline { auto tmp = $1; tmp.statements.push_back({$2, std::make_unique<ast::statement>($3)}); $$ = std::move(tmp); }
|
|
| indented_statement_list indentation newline { $$ = $1; }
|
|
| %empty { $$ = {}; }
|
|
;
|
|
|
|
indentation
|
|
: indent indentation { $$ = $2 + 1ull; }
|
|
| %empty { $$ = 0ull; }
|
|
;
|
|
|
|
statement
|
|
: expression { $$ = std::make_unique<ast::expression>($1); }
|
|
| expression assignment expression { $$ = ast::assignment{ std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
|
|
| variable_declaration { $$ = $1; }
|
|
| if expression colon { $$ = ast::if_block{std::make_unique<ast::expression>($2), {}}; }
|
|
| else colon { $$ = ast::else_block{{}}; }
|
|
| else if expression colon { $$ = ast::else_if_block{std::make_unique<ast::expression>($3), {}}; }
|
|
| while expression colon { $$ = ast::while_block{std::make_unique<ast::expression>($2), {}}; }
|
|
| func name lparen function_definition_argument_list rparen function_return_type colon { $$ = ast::function_definition{$2, $4, $6, {}}; }
|
|
| return expression { $$ = ast::return_statement{std::make_unique<ast::expression>($2)}; }
|
|
| return { $$ = ast::return_statement{nullptr}; }
|
|
;
|
|
|
|
function_definition_argument_list
|
|
: %empty { std::vector<ast::function_definition::argument> tmp; $$ = std::move(tmp); }
|
|
| nonempty_function_definition_argument_list { $$ = $1; }
|
|
;
|
|
|
|
nonempty_function_definition_argument_list
|
|
: name colon type_expression { std::vector<ast::function_definition::argument> tmp; tmp.push_back({.name = $1, .type = std::make_unique<type::type>($3)}); $$ = std::move(tmp); }
|
|
| nonempty_function_definition_argument_list comma name colon type_expression { auto tmp = $1; tmp.push_back({.name = $3, .type = std::make_unique<type::type>($5)}); $$ = std::move(tmp); }
|
|
;
|
|
|
|
function_return_type
|
|
: arrow type_expression { $$ = std::make_unique<type::type>($2); }
|
|
| %empty { $$ = std::make_unique<type::type>(type::unit_type{}); }
|
|
;
|
|
|
|
variable_declaration
|
|
: variable_keyword name assignment expression { $$ = ast::variable_declaration{$1, $2, nullptr, std::make_unique<ast::expression>($4)}; }
|
|
| variable_keyword name colon type_expression assignment expression { $$ = ast::variable_declaration{$1, $2, std::make_unique<type::type>($4), std::make_unique<ast::expression>($6)}; }
|
|
;
|
|
|
|
variable_keyword
|
|
: const { $$ = ast::value_category::compile_time; }
|
|
| let { $$ = ast::value_category::constant; }
|
|
| mut { $$ = ast::value_category::_mutable; }
|
|
;
|
|
|
|
type_expression
|
|
: unit { $$ = type::type(type::unit_type{}); }
|
|
| primitive_type { $$ = type::type($1); }
|
|
| type_expression lbracket lit_i32 rbracket { $$ = type::array_type{std::make_unique<type::type>($1), std::stoull($3)}; }
|
|
;
|
|
|
|
primitive_type
|
|
: bool { $$ = type::bool_type{}; }
|
|
| i8 { $$ = type::i8_type{}; }
|
|
| u8 { $$ = type::u8_type{}; }
|
|
| i16 { $$ = type::i16_type{}; }
|
|
| u16 { $$ = type::u16_type{}; }
|
|
| i32 { $$ = type::i32_type{}; }
|
|
| u32 { $$ = type::u32_type{}; }
|
|
| i64 { $$ = type::i64_type{}; }
|
|
| u64 { $$ = type::u64_type{}; }
|
|
| f32 { $$ = type::f32_type{}; }
|
|
| f64 { $$ = type::f64_type{}; }
|
|
;
|
|
|
|
expression
|
|
: bool_expression { $$ = $1; }
|
|
;
|
|
|
|
bool_expression
|
|
: compare_expression { $$ = $1; }
|
|
| bool_expression ampersand compare_expression { $$ = ast::binary_operation{ast::binary_operation_type::logical_and, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
|
|
| bool_expression vertical_bar compare_expression { $$ = ast::binary_operation{ast::binary_operation_type::logical_or, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
|
|
| bool_expression circumflex compare_expression { $$ = ast::binary_operation{ast::binary_operation_type::logical_xor, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
|
|
;
|
|
|
|
compare_expression
|
|
: as_expression { $$ = $1; }
|
|
| compare_expression equals as_expression { $$ = ast::binary_operation{ast::binary_operation_type::equals, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
|
|
| compare_expression not_equals as_expression { $$ = ast::binary_operation{ast::binary_operation_type::not_equals, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
|
|
| compare_expression less as_expression { $$ = ast::binary_operation{ast::binary_operation_type::less, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
|
|
| compare_expression greater as_expression { $$ = ast::binary_operation{ast::binary_operation_type::greater, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
|
|
| compare_expression less_equals as_expression { $$ = ast::binary_operation{ast::binary_operation_type::less_equals, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
|
|
| compare_expression greater_equals as_expression { $$ = ast::binary_operation{ast::binary_operation_type::greater_equals, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
|
|
;
|
|
|
|
as_expression
|
|
: negate_expression { $$ = $1; }
|
|
| negate_expression as type_expression { $$ = ast::cast_operation{ std::make_unique<ast::expression>($1), std::make_unique<type::type>($3) }; }
|
|
;
|
|
|
|
negate_expression
|
|
: sum_expression { $$ = $1; }
|
|
| minus sum_expression { $$ = ast::unary_operation{ast::unary_operation_type::negation, std::make_unique<ast::expression>($2) }; }
|
|
;
|
|
|
|
sum_expression
|
|
: mult_expression { $$ = $1; }
|
|
| sum_expression plus mult_expression { $$ = ast::binary_operation{ast::binary_operation_type::addition, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
|
|
| sum_expression minus mult_expression { $$ = ast::binary_operation{ast::binary_operation_type::subtraction, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
|
|
;
|
|
|
|
mult_expression
|
|
: not_expression { $$ = $1; }
|
|
| mult_expression asterisk not_expression { $$ = ast::binary_operation{ast::binary_operation_type::multiplication, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
|
|
| mult_expression slash not_expression { $$ = ast::binary_operation{ast::binary_operation_type::division, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
|
|
| mult_expression percent not_expression { $$ = ast::binary_operation{ast::binary_operation_type::remainder, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
|
|
;
|
|
|
|
not_expression
|
|
: postfix_expression
|
|
| exclamation postfix_expression { $$ = ast::unary_operation{ast::unary_operation_type::logical_not, std::make_unique<ast::expression>($2) }; }
|
|
;
|
|
|
|
postfix_expression
|
|
: base_expression
|
|
| postfix_expression lbracket expression rbracket { $$ = ast::array_access{std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3)}; }
|
|
;
|
|
|
|
base_expression
|
|
: literal
|
|
| name { $$ = ast::identifier{$1}; }
|
|
| lparen expression rparen { $$ = $2; }
|
|
| name lparen comma_separated_expression_list rparen { $$ = ast::function_call{$1, $3}; }
|
|
| lbracket nonempty_comma_separated_expression_list rbracket { $$ = ast::array{$2}; }
|
|
;
|
|
|
|
comma_separated_expression_list
|
|
: %empty { std::vector<ast::expression_ptr> tmp; $$ = std::move(tmp); }
|
|
| nonempty_comma_separated_expression_list
|
|
;
|
|
|
|
nonempty_comma_separated_expression_list
|
|
: expression { std::vector<ast::expression_ptr> tmp; tmp.push_back(std::make_unique<ast::expression>($1)); $$ = std::move(tmp); }
|
|
| nonempty_comma_separated_expression_list comma expression { auto tmp = $1; tmp.push_back(std::make_unique<ast::expression>($3)); $$ = std::move(tmp); }
|
|
;
|
|
|
|
literal
|
|
: true { $$ = ast::literal(ast::bool_literal{true}); }
|
|
| false { $$ = ast::literal(ast::bool_literal{false}); }
|
|
| lit_i8 { $$ = parse_numeric_literal<std::int8_t>($1); }
|
|
| lit_u8 { $$ = parse_numeric_literal<std::uint8_t>($1); }
|
|
| lit_i16 { $$ = parse_numeric_literal<std::int16_t>($1); }
|
|
| lit_u16 { $$ = parse_numeric_literal<std::uint16_t>($1); }
|
|
| lit_i32 { $$ = parse_numeric_literal<std::int32_t>($1); }
|
|
| lit_u32 { $$ = parse_numeric_literal<std::uint32_t>($1); }
|
|
| lit_i64 { $$ = parse_numeric_literal<std::int64_t>($1); }
|
|
| lit_u64 { $$ = parse_numeric_literal<std::uint64_t>($1); }
|
|
| lit_f32 { $$ = parse_numeric_literal<float>($1); }
|
|
| lit_f64 { $$ = parse_numeric_literal<double>($1); }
|
|
;
|
|
|
|
%%
|
|
|
|
void pslang::parser::bison::parser::error(location_type const& location, std::string const& message)
|
|
{
|
|
throw ::pslang::parser::parse_error(message, location);
|
|
}
|