python2ruby/src/parser.y
2025-11-28 12:47:57 +01:00

109 lines
No EOL
3.3 KiB
Text

%skeleton "lalr1.cc"
%require "3.0"
%defines
%define api.value.type variant
%define api.token.raw
%define api.parser.class { parser }
%define api.namespace { yy }
%define api.token.prefix {TOK_}
%define parse.trace
%code requires {
#include <string>
#include "ast.hpp"
class Scanner;
}
%code {
#include <iostream>
#include "scanner.hpp"
#undef yylex
#define yylex scanner->lex
}
%parse-param { Scanner* scanner }
%parse-param { std::unique_ptr<Module>* result }
%token <std::string> IDENTIFIER STRING
%token <std::string> NUMBER
%left KW_OR
%left KW_AND
%right KW_NOT // unary logical NOT
%token KW_DEF KW_IF KW_RETURN KW_FOR KW_IN KW_PASS KW_ELSE KW_ELIF KW_CLASS
%token L_PAREN R_PAREN L_BRACKET R_BRACKET L_BRACE R_BRACE
%token DOT COLON SEMICOLON COMMA
%token INDENT DEDENT NEWLINE EOF
%left BIT_OR
%left BIT_XOR
%left BIT_AND
%left LSHIFT RSHIFT
%token BIT_NOT
%nonassoc EQ NE LT LTE GT GTE
%left PLUS MINUS
%left MULTIPLY DIVIDE MODULO
%right ASSIGN PLUS_ASSIGN MINUS_ASSIGN MULTIPLY_ASSIGN DIVIDE_ASSIGN MODULO_ASSIGN
%right BIT_AND_ASSIGN BIT_OR_ASSIGN BIT_XOR_ASSIGN LSHIFT_ASSIGN RSHIFT_ASSIGN
%type <std::unique_ptr<Expr>> expr
%type <std::unique_ptr<Stmt>> stmt
%type <std::vector<std::unique_ptr<Expr>>> args
%type <std::vector<std::unique_ptr<Stmt>>> stmt_list
%%
input:
stmt_list EOF { *result = std::make_unique<Module>(std::move($1));}
;
stmt_list:
/* empty */ { $$ = std::vector<std::unique_ptr<Stmt>>(); }
| stmt_list stmt { $1.push_back(std::move($2)); $$ = std::move($1); }
;
stmt:
expr NEWLINE { $$ = std::make_unique<ExprStmt>(std::move($1)); }
| expr ASSIGN expr NEWLINE { $$ = std::make_unique<Assign>(std::move($1), std::move($3));}
| KW_IF expr COLON NEWLINE INDENT stmt_list DEDENT {
$$ = std::make_unique<If>(std::move($2), std::move($6), std::vector<std::unique_ptr<Stmt>>());
}
| KW_IF expr COLON NEWLINE INDENT stmt_list DEDENT KW_ELSE COLON NEWLINE INDENT stmt_list DEDENT{
$$ = std::make_unique<If>(std::move($2), std::move($6), std::move($12));
}
;
expr:
NUMBER { $$ = std::make_unique<Number>($1); }
| IDENTIFIER { $$ = std::make_unique<Identifier>($1); }
| STRING { $$ = std::make_unique<String>($1); }
| expr PLUS expr { $$ = std::make_unique<BinOp>(
BinaryOperator(BinaryOperator::ADD),
std::move($1), std::move($3)); }
| expr MULTIPLY expr { $$ = std::make_unique<BinOp>(
BinaryOperator(BinaryOperator::MUL),
std::move($1), std::move($3)); }
| L_PAREN expr R_PAREN {$$ = std::move($2); /* #todo: test for precedence*/}
| expr L_PAREN args R_PAREN { $$ = std::make_unique<Call>(std::move($1), std::move($3));}
| expr DOT IDENTIFIER { $$ = std::make_unique<Attribute>(std::move($1), $3);}
;
args:
/* empty */ { $$ = std::vector<std::unique_ptr<Expr>>(); }
| expr { $$ = std::vector<std::unique_ptr<Expr>>();
$$.push_back(std::move($1)); }
| args COMMA expr { $1.push_back(std::move($3)); $$ = std::move($1); }
;
%%
namespace yy {
void parser::error(const std::string& msg)
{
std::cerr << "Error: " << msg << "\n";
}
}