Skip to content

Instantly share code, notes, and snippets.

@antonijn
Created February 1, 2019 22:20
Show Gist options
  • Save antonijn/6626c2b17659cbb69c6c64e32bfdd64f to your computer and use it in GitHub Desktop.
Save antonijn/6626c2b17659cbb69c6c64e32bfdd64f to your computer and use it in GitHub Desktop.
%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