Created
February 1, 2019 22:20
-
-
Save antonijn/6626c2b17659cbb69c6c64e32bfdd64f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%code requires { | |
#include "types.h" | |
#include <stddef.h> | |
#include <stdio.h> | |
} | |
%code { | |
int yylex(); | |
void yyerror(ASTFileElement **f, const char *msg); | |
} | |
/* dangling else */ | |
%expect 1 | |
%define parse.error verbose | |
%define api.pure full | |
%parse-param { ASTFileElement **result } | |
%union { | |
Token tok; | |
VarKind varkind; | |
ASTType *type; | |
ASTEnumerator *enumerator; | |
ASTTypeNode *typenode; | |
ASTVarSpec *varspec; | |
ASTVarNode *varnode; | |
ASTVarDecl *vardecl; | |
ASTDeclarator *declarator; | |
ASTFileElement *file_elt; | |
ASTStat *stat; | |
ASTStatNode *statnode; | |
ASTSwitchCase *switch_case; | |
ASTMatchCase *match_case; | |
ASTExpr *expr; | |
ASTExprNode *exprnode; | |
} | |
%token <tok> TOK_STRING | |
%token <tok> TOK_ID | |
%token <tok> TOK_INTEGER | |
%token <tok> TOK_FLOAT | |
%token <tok> TOK_BREAK "break" | |
%token <tok> TOK_CASE "case" | |
%token <tok> TOK_CHOICE "choice" | |
%token <tok> TOK_CONST "const" | |
%token <tok> TOK_CONTINUE "continue" | |
%token <tok> TOK_DEFAULT "default" | |
%token <tok> TOK_DO "do" | |
%token <tok> TOK_ENUM "enum" | |
%token <tok> TOK_FALSE "false" | |
%token <tok> TOK_FOR "for" | |
%token <tok> TOK_FUNC "func" | |
%token <tok> TOK_IF "if" | |
%token <tok> TOK_IMPORT "import" | |
%token <tok> TOK_MATCH "match" | |
%token <tok> TOK_NULL "null" | |
%token <tok> TOK_RETURN "return" | |
%token <tok> TOK_SIZEOF "sizeof" | |
%token <tok> TOK_STRUCT "struct" | |
%token <tok> TOK_SWITCH "switch" | |
%token <tok> TOK_TRUE "true" | |
%token <tok> TOK_TYPE "type" | |
%token <tok> TOK_UNION "union" | |
%token <tok> TOK_VAR "var" | |
%token <tok> TOK_WHILE "while" | |
%token <tok> TOK_ELLIPSIS "..." | |
%token <tok> TOK_SHREQ ">>=" | |
%token <tok> TOK_SHLEQ "<<=" | |
%token <tok> TOK_PLUSEQ "+=" | |
%token <tok> TOK_MINEQ "-=" | |
%token <tok> TOK_ASTERISKEQ "*=" | |
%token <tok> TOK_SLASHEQ "/=" | |
%token <tok> TOK_PERCENTEQ "%=" | |
%token <tok> TOK_ANDEQ "&=" | |
%token <tok> TOK_CARETEQ "^=" | |
%token <tok> TOK_PIPEEQ "|=" | |
%token <tok> TOK_SHR ">>" | |
%token <tok> TOK_SHL "<<" | |
%token <tok> TOK_PLUSPLUS "++" | |
%token <tok> TOK_MINMIN "--" | |
%token <tok> TOK_ARROW "->" | |
%token <tok> TOK_ANDAND "&&" | |
%token <tok> TOK_PIPEPIPE "||" | |
%token <tok> TOK_LTE "<=" | |
%token <tok> TOK_GTE ">=" | |
%token <tok> TOK_EQEQ "==" | |
%token <tok> TOK_NOTEQ "!=" | |
%token <tok> TOK_SEMI ";" | |
%token <tok> TOK_LBRACK "{" | |
%token <tok> TOK_RBRACK "}" | |
%token <tok> TOK_COMMA "," | |
%token <tok> TOK_COLON ":" | |
%token <tok> TOK_EQ "=" | |
%token <tok> TOK_LPAR "(" | |
%token <tok> TOK_RPAR ")" | |
%token <tok> TOK_LSQR "[" | |
%token <tok> TOK_RSQR "]" | |
%token <tok> TOK_DOT "." | |
%token <tok> TOK_AND "&" | |
%token <tok> TOK_NOT "!" | |
%token <tok> TOK_TILDE "~" | |
%token <tok> TOK_MIN "-" | |
%token <tok> TOK_PLUS "+" | |
%token <tok> TOK_ASTERISK "*" | |
%token <tok> TOK_SLASH "/" | |
%token <tok> TOK_PERCENT "%" | |
%token <tok> TOK_LT "<" | |
%token <tok> TOK_GT ">" | |
%token <tok> TOK_CARET "^" | |
%token <tok> TOK_PIPE "|" | |
%token <tok> TOK_QUESTION "?" | |
%type <varkind> varconst | |
%type <type> type maybe_type | |
%type <enumerator> enumerator enumerators enumerators_ | |
%type <vardecl> vardecl | |
%type <declarator> declarator declarators | |
%type <typenode> typearg typearglist typearglist_ | |
%type <varspec> varspec varspecs | |
%type <varnode> field fields arg arglist arglist_ | |
%type <file_elt> file file_element function global typedef import | |
%type <expr> expr maybe_expr assignment ternary_expr scor_expr scand_expr or_expr xor_expr and_expr eq_expr cmp_expr shift_expr add_expr mul_expr basic_expr2 basic_expr terminal_expr | |
%type <exprnode> exprnode exprlist expr_arglist | |
%type <stat> stat simple_stat control block for if while dowhile switch match | |
%type <statnode> stats stat_node | |
%type <switch_case> switch_case switch_caselist | |
%type <match_case> match_case match_caselist | |
%% | |
file : { *result = $$ = NULL; } | |
| file_element[F] file[X] { $F->next = $X; *result = $$ = $F; } | |
; | |
file_element : function | |
| global | |
| typedef | |
| import | |
; | |
typedef : "type" TOK_ID[I] type[T] ";" { $$ = ast_typedef($I.str, $T); } | |
; | |
maybe_type : { $$ = NULL; } | |
| type | |
; | |
type : TOK_ID[I] { $$ = ast_named_type($I.str); } | |
| "func" "(" typearglist[A] ")" maybe_type[T] { $$ = ast_func_type($A, $T); } | |
| "*" type[T] { $$ = ast_ptr($T); } | |
| "struct" "{" fields[F] "}" { $$ = ast_struct($F); } | |
| "union" "{" fields[F] "}" { $$ = ast_union($F); } | |
| "choice" "{" fields[F] "}" { $$ = ast_choice($F); } | |
| "enum" "{" enumerators[E] "}" { $$ = ast_enum($E); } | |
; | |
fields : { $$ = NULL; } | |
| field[F] fields[X] { $F->next = $X; $$ = $F; } | |
; | |
field : varspecs[V] ";" { $$ = ast_var_node($V); } | |
; | |
declarator : TOK_ID { $$ = ast_declarator($1.str); } | |
; | |
declarators : declarator | |
| declarator[D] "," declarators[X] { $D->next = $X; $$ = $D; } | |
; | |
varspec : declarator[D] type[T] { $$ = ast_var_spec($D, $T); } | |
; | |
varspecs : declarators[D] type[T] { $$ = ast_var_spec($D, $T); } | |
; | |
enumerators : { $$ = NULL; } | |
| enumerators_ | |
| enumerators_ "," | |
; | |
enumerator : TOK_ID[I] { $$ = ast_enumerator($I.str, NULL); } | |
| TOK_ID[I] "=" expr[E] { $$ = ast_enumerator($I.str, $E); } | |
; | |
enumerators_ : enumerator | |
| enumerators_[X] "," enumerator[E] { $E->prev = $X; $$ = $E; } | |
; | |
typearglist : { $$ = NULL; } | |
| typearglist_ | |
; | |
typearg : type[T] { $$ = ast_type_node($T); } | |
; | |
typearglist_ : typearg[T] | |
| typearg[T] "," typearglist_[X] { $T->next = $X; $$ = $T; } | |
; | |
function : "func" TOK_ID[I] "(" arglist[A] ")" maybe_type[T] block[B] { $$ = ast_function($I.str, $A, $T, $B); } | |
; | |
arglist : { $$ = NULL; } | |
| arglist_ | |
; | |
arglist_ : arg[A] | |
| arg[A] "," arglist_[X] { $A->next = $X; } | |
; | |
arg : varspecs[V] { $$ = ast_var_node($V); } | |
; | |
global : vardecl { $$ = ast_global($1); } | |
; | |
import : "import" TOK_STRING[S] ";" { $$ = ast_import($S.str); } | |
; | |
varconst : "var" { $$ = AST_VAR; } | |
| "const" { $$ = AST_CONST; } | |
; | |
vardecl : varconst[M] varspecs[V] ";" | |
{ $$ = ast_var_decl($M, $V, NULL) ; } | |
| varconst[M] declarators[D] maybe_type[T] "=" exprlist[E] ";" | |
{ $$ = ast_var_decl($M, ast_var_spec($D, $T), $E); } | |
; | |
stat : simple_stat | |
| control | |
| "break" ";" { $$ = ast_break(); } | |
| "continue" ";" { $$ = ast_continue(); } | |
| "return" maybe_expr[E] ";" { $$ = ast_return($E); } | |
| block | |
; | |
simple_stat : expr ";" { $$ = ast_expr_stat($1); } | |
| ";" { $$ = ast_empty_stat(); } | |
| vardecl { $$ = ast_local_var($1); } | |
; | |
maybe_expr : { $$ = NULL; } | |
| expr | |
; | |
control : for | |
| if | |
| while | |
| dowhile | |
| switch | |
| match | |
; | |
for : "for" "(" simple_stat[I] maybe_expr[C] ";" maybe_expr[F] ")" stat[S] | |
{ $$ = ast_for($I, $C, $F, $S); } | |
; | |
if : "if" "(" expr[C] ")" stat[S] { $$ = ast_if($C, $S, NULL); } | |
| "if" "(" expr[C] ")" stat[S] "else" stat[E] { $$ = ast_if($C, $S, $E); } | |
; | |
while : "while" "(" expr[C] ")" stat[S] { $$ = ast_while($C, $S); } | |
; | |
dowhile : "do" stat[S] "while" "(" expr[C] ")" { $$ = ast_dowhile($C, $S); } | |
; | |
switch : "switch" "(" expr[E] ")" "{" switch_caselist[C] "}" { $$ = ast_switch($E, $C); } | |
; | |
switch_caselist : { $$ = NULL; } | |
| switch_case[C] switch_caselist[X] { $C->next = $X; $$ = $C; } | |
; | |
switch_case : "case" expr[C] ":" stats[S] { $$ = ast_switch_case($C, $S); } | |
| "default" ":" stats[S] { $$ = ast_switch_case(NULL, $S); } | |
; | |
match : "match" "(" expr[E] ")" "{" match_caselist[C] "}" { $$ = ast_match($E, $C); } | |
; | |
match_caselist : { $$ = NULL; } | |
| match_case[C] match_caselist[X] { $C->next = $X; $$ = $C; } | |
; | |
match_case : "case" varspec[V] ":" stats[S] { $$ = ast_match_case($V, $S); } | |
| "default" ":" stats[S] { $$ = ast_match_case(NULL, $S); } | |
; | |
block : "{" stats[S] "}" { $$ = ast_block($S); } | |
; | |
stat_node : stat { $$ = ast_stat_node($1); } | |
; | |
stats : { $$ = NULL; } | |
| stat_node[S] stats[X] { $S->next = $X; $$ = $S; } | |
; | |
expr : assignment ; | |
terminal_expr : TOK_ID { $$ = ast_terminal(AST_ID, $1.str); } | |
| TOK_INTEGER { $$ = ast_terminal(AST_INTEGER, $1.str); } | |
| TOK_FLOAT { $$ = ast_terminal(AST_FLOAT, $1.str); } | |
| TOK_STRING { $$ = ast_terminal(AST_STRING, $1.str); } | |
| "true" { $$ = ast_terminal(AST_TRUE, $1.str); } | |
| "false" { $$ = ast_terminal(AST_FALSE, $1.str); } | |
| "null" { $$ = ast_terminal(AST_NULL, $1.str); } | |
; | |
basic_expr : terminal_expr | |
| "(" expr[E] ")" { $$ = $E; } | |
| basic_expr[E] "++" { $$ = ast_unop(UNOP_POST_INC, $E); } | |
| basic_expr[E] "--" { $$ = ast_unop(UNOP_POST_DEC, $E); } | |
| basic_expr[E] "(" expr_arglist[A] ")" { $$ = ast_fcall($E, $A); } | |
| basic_expr[E] "[" expr[I] "]" { $$ = ast_index($E, $I); } | |
| basic_expr[E] "." TOK_ID[I] { $$ = ast_access($E, $I.str, false); } | |
| basic_expr[E] "->" TOK_ID[I] { $$ = ast_access($E, $I.str, true); } | |
; | |
basic_expr2 : basic_expr | |
| "++" basic_expr2[E] { $$ = ast_unop(UNOP_PRE_INC, $E); } | |
| "--" basic_expr2[E] { $$ = ast_unop(UNOP_PRE_DEC, $E); } | |
| "+" basic_expr2[E] { $$ = ast_unop(UNOP_PROMOTE, $E); } | |
| "-" basic_expr2[E] { $$ = ast_unop(UNOP_MINUS, $E); } | |
| "!" basic_expr2[E] { $$ = ast_unop(UNOP_NOT, $E); } | |
| "~" basic_expr2[E] { $$ = ast_unop(UNOP_INV, $E); } | |
| "[" type[T] "]" basic_expr2[E] { $$ = ast_cast($T, $E); } | |
| "*" basic_expr2[E] { $$ = ast_unop(UNOP_DEREF, $E); } | |
| "&" basic_expr2[E] { $$ = ast_unop(UNOP_REF, $E); } | |
| "sizeof" "(" expr[E] ")" { $$ = ast_sizeof_expr($E); } | |
| "sizeof" "[" type[T] "]" { $$ = ast_sizeof_type($T); } | |
; | |
mul_expr : basic_expr2 | |
| mul_expr[L] "*" basic_expr2[R] { $$ = ast_binop(BINOP_MUL, $L, $R); } | |
| mul_expr[L] "/" basic_expr2[R] { $$ = ast_binop(BINOP_DIV, $L, $R); } | |
| mul_expr[L] "%" basic_expr2[R] { $$ = ast_binop(BINOP_MOD, $L, $R); } | |
; | |
add_expr : mul_expr | |
| add_expr[L] "+" mul_expr[R] { $$ = ast_binop(BINOP_ADD, $L, $R); } | |
| add_expr[L] "-" mul_expr[R] { $$ = ast_binop(BINOP_SUB, $L, $R); } | |
; | |
shift_expr : add_expr | |
| shift_expr[L] "<<" add_expr[R] { $$ = ast_binop(BINOP_SHL, $L, $R); } | |
| shift_expr[L] ">>" add_expr[R] { $$ = ast_binop(BINOP_SHR, $L, $R); } | |
; | |
cmp_expr : shift_expr | |
| cmp_expr[L] "<" shift_expr[R] { $$ = ast_binop(BINOP_LT, $L, $R); } | |
| cmp_expr[L] ">" shift_expr[R] { $$ = ast_binop(BINOP_GT, $L, $R); } | |
| cmp_expr[L] "<=" shift_expr[R] { $$ = ast_binop(BINOP_LTE, $L, $R); } | |
| cmp_expr[L] ">=" shift_expr[R] { $$ = ast_binop(BINOP_GTE, $L, $R); } | |
; | |
eq_expr : cmp_expr | |
| eq_expr[L] "==" cmp_expr[R] { $$ = ast_binop(BINOP_EQ, $L, $R); } | |
| eq_expr[L] "!=" cmp_expr[R] { $$ = ast_binop(BINOP_NEQ, $L, $R); } | |
; | |
and_expr : eq_expr | |
| and_expr[L] "&" eq_expr[R] { $$ = ast_binop(BINOP_AND, $L, $R); } | |
; | |
xor_expr : and_expr | |
| xor_expr[L] "^" and_expr[R] { $$ = ast_binop(BINOP_XOR, $L, $R); } | |
; | |
or_expr : xor_expr | |
| or_expr[L] "|" xor_expr[R] { $$ = ast_binop(BINOP_OR, $L, $R); } | |
; | |
scand_expr : or_expr | |
| scand_expr[L] "&&" or_expr[R] { $$ = ast_binop(BINOP_SC_AND, $L, $R); } | |
; | |
scor_expr : scand_expr | |
| scor_expr[L] "||" scand_expr[R] { $$ = ast_binop(BINOP_SC_OR, $L, $R); } | |
; | |
ternary_expr : scor_expr | |
| ternary_expr[C] "?" scor_expr[L] ":" scor_expr[R] { $$ = ast_conditional($C, $L, $R); } | |
; | |
assignment : ternary_expr | |
| ternary_expr[L] "=" assignment[R] { $$ = ast_assign(BINOP_NONE, $L, $R); } | |
| ternary_expr[L] "+=" assignment[R] { $$ = ast_assign(BINOP_ADD, $L, $R); } | |
| ternary_expr[L] "-=" assignment[R] { $$ = ast_assign(BINOP_SUB, $L, $R); } | |
| ternary_expr[L] "*=" assignment[R] { $$ = ast_assign(BINOP_MUL, $L, $R); } | |
| ternary_expr[L] "/=" assignment[R] { $$ = ast_assign(BINOP_DIV, $L, $R); } | |
| ternary_expr[L] "%=" assignment[R] { $$ = ast_assign(BINOP_MOD, $L, $R); } | |
| ternary_expr[L] "&=" assignment[R] { $$ = ast_assign(BINOP_AND, $L, $R); } | |
| ternary_expr[L] "^=" assignment[R] { $$ = ast_assign(BINOP_XOR, $L, $R); } | |
| ternary_expr[L] "|=" assignment[R] { $$ = ast_assign(BINOP_OR, $L, $R); } | |
| ternary_expr[L] ">>=" assignment[R] { $$ = ast_assign(BINOP_SHR, $L, $R); } | |
| ternary_expr[L] "<<=" assignment[R] { $$ = ast_assign(BINOP_SHL, $L, $R); } | |
; | |
expr_arglist : { $$ = NULL; } | |
| exprlist | |
; | |
exprnode : expr[E] { $$ = ast_expr_node($E); } | |
; | |
exprlist : exprnode[E] | |
| exprnode[E] "," exprlist[X] { $E->next = $X; $$ = $E; } | |
; | |
%% | |
void yyerror(ASTFileElement **f, const char *msg) | |
{ | |
fprintf(stderr, "%s\n", msg); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment