Untitled

mail@pastecode.io avatar
unknown
plain_text
7 months ago
3.8 kB
4
Indexable
Never
%skeleton "lalr1.cc"
%require "2.5"
%defines
%define api.namespace {calc}
%define api.value.type variant
%define api.parser.class {Parser}

%code requires {
    #include <iostream>
    #include <memory>
    #include "ast.h"
    namespace calc {class Lexer;}
}

%parse-param {calc::Lexer& lexer} {std::shared_ptr<Ast>& result} {std::string& message}

%code {
    #include "lexer.h"
    #define yylex lexer.lex
}

%token END 0 "end of file"
%token ERROR
%token EOL "\n"

%token <int> NUM

%token <std::string> NAME

%token ASSIGN "="
%token PLUS "+"
%token MINUS "-"
%token MUL "*"
%token DIV "/"
%token LPAR "("
%token RPAR ")"
%token FUNC "def"
%token COLON ":"
%token COMMA ","

%token DO "do"
%token DONE "done"

%token IF "if"
%token ELSE "else"
%token WHILE "while"

%token OR "||"
%token AND "&&"
%token NOT "!"
%token EQUAL "=="
%token NOT_EQUAL "!="
%token LESS "<"
%token LESS_OR_EQUAL "<="
%token GREATER ">"
%token GREATER_OR_EQUAL ">="

%type <std::shared_ptr<Ast>> expr stmt
%type <std::vector<std::string>> params
%type <std::vector<std::shared_ptr<Ast>>> arguments
%type <std::vector<std::shared_ptr<Ast>>> block

%left "+" "-"
%left "*" "/"
%left "||"
%left "&&"
%left "==" "!=" "<" "<=" ">" ">="

%nonassoc UMINUS
%nonassoc NOT_EXPR
%right "then" "else"
%%

input: stmt "\n" { result = $1; }
;

params : NAME { $$ = std::vector<std::string>{$1}; }
    | params "," NAME { $1.push_back($3); $$ = std::move($1); }

;

arguments : expr { $$ = std::vector<std::shared_ptr<Ast>>{$1}; }
    | arguments "," expr { $1.push_back($3); $$ = std::move($1); }

;

block : stmt { $$ = std::vector<std::shared_ptr<Ast>>{$1}; }
    | block "\n" stmt { $1.push_back($3); $$ = std::move($1); }

;

stmt: expr { $$ = $1; }
    | "def" NAME "(" params ")" ":" stmt { $$ = new_definition($2, $4, std::vector<std::shared_ptr<Ast>>{$7}); }
    | "def" NAME "(" params ")" ":" "do" "\n" block "\n" "done" {$$ = new_definition($2, $4, $9); }
    | NAME "=" expr { $$ = new_assignment($1, $3); }
    | NAME "(" arguments ")" { $$ = new_function($1, $3); }
    | "if" expr ":" "do" "\n" block "\n" "done" %prec "then" { $$ = new_condition($2, $6); }
    | "if" expr ":" stmt %prec "then" { $$ = new_condition($2, std::vector<std::shared_ptr<Ast>>{$4}); }
    | "if" expr ":" stmt "\n" "else" ":" stmt { $$ = new_condition($2, std::vector<std::shared_ptr<Ast>>{$4}, std::vector<std::shared_ptr<Ast>>{$8}); }
    | "if" expr ":" "do" "\n" block "\n" "done" "\n" "else" ":" "do" "\n" block "\n" "done" { $$ = new_condition($2, $6, $14); }
    | "while" stmt ":" stmt { $$ = new_while($2, std::vector<std::shared_ptr<Ast>>{$4}); }
    | "while" stmt ":" "do" "\n" block "\n" "done" { $$ = new_while($2, $6); }
;


expr: NUM { $$ = new_number($1); }
    | NAME { $$ = new_variable($1); }
    | expr "+" expr { $$ = new_binary(Opcode::plus, $1, $3); }
    | expr "-" expr { $$ = new_binary(Opcode::minus, $1, $3); }
    | expr "*" expr { $$ = new_binary(Opcode::mul, $1, $3); }
    | expr "/" expr { $$ = new_binary(Opcode::div, $1, $3); }
    | "(" expr ")" { $$ = $2; }
    | "-" %prec UMINUS expr { $$ = new_unary(Opcode::uminus, $2); }
    | expr "||" expr { $$ = new_binary(Opcode::or_expr, $1, $3); }
    | expr "&&" expr { $$ = new_binary(Opcode::and_expr, $1, $3); }
    | "!" %prec NOT_EXPR expr { $$ = new_unary(Opcode::not_expr, $2); }
    | expr "==" expr { $$ = new_binary(Opcode::equal, $1, $3); }
    | expr "!=" expr { $$ = new_binary(Opcode::not_equal, $1, $3); }
    | expr "<" expr { $$ = new_binary(Opcode::less, $1, $3); }
    | expr "<=" expr { $$ = new_binary(Opcode::less_or_equal, $1, $3); }
    | expr ">" expr { $$ = new_binary(Opcode::greater, $1, $3); }
    | expr ">=" expr { $$ = new_binary(Opcode::greater_or_equal, $1, $3); }
;
%%

void calc::Parser::error(const std::string& err)
{
    message = err;
}