%{ #include #include "ast.h" #include "list.h" #include "parse.h" int yylex(void); extern YYLTYPE yylloc; void yyerror(struct ast **result, const char *str) { (void)result; fprintf(stderr, "%d-%d: %s\n", yylloc.first_line, yylloc.last_column, str); } int yywrap() { return 1; } %} %define parse.lac full %define parse.error verbose %union { struct expr *expr; struct stmt *stmt; struct list *list; struct vardecl *vardecl; struct fundecl *fundecl; struct type *type; char *ident; } %locations %token IDENT %token BOOL CHAR INTEGER STRING %token ARROW ASSIGN BCLOSE BINAND BINOR BOPEN CCLOSE COMMA CONS COPEN DIVIDE %token DOT ELSE ERROR IF INVERSE MINUS MODULO NIL PLUS POWER RETURN SEMICOLON %token SCLOSE SOPEN TIMES TBOOL TCHAR TINT TVOID VAR WHILE %parse-param { struct ast **result } %right BINOR %right BINAND %nonassoc EQ NEQ LEQ LE GEQ GE %right CONS %left PLUS MINUS %left TIMES DIVIDE MODULO %right POWER %type start %type expr %type args body decls fargs field fnargs nargs funtype bbody %type stmt %type type ftype %type vardecl %type fundecl %% start : decls { *result = ast($1); } ; decls : /* empty */ { $$ = NULL; } | decls vardecl { $$ = list_cons(decl_var($2), $1); } | decls fundecl { $$ = list_cons(decl_fun($2), $1); } ; vardecl : VAR IDENT ASSIGN expr SEMICOLON { $$ = vardecl(NULL, $2, $4); } | type IDENT ASSIGN expr SEMICOLON { $$ = vardecl($1, $2, $4); } ; fundecl : IDENT BOPEN args BCLOSE COPEN body CCLOSE { $$ = fundecl($1, $3, NULL, NULL, $6); } | IDENT BOPEN args BCLOSE CONS CONS funtype ARROW ftype COPEN body CCLOSE { $$ = fundecl($1, $3, $7, $9, $11); } ; funtype : /* empty */ { $$ = NULL; } | funtype ftype { $$ = list_cons($2, $1); } ; /* don't allow vardecls to be fully polymorph, this complicates parsing a lot */ type : BOPEN ftype COMMA ftype BCLOSE { $$ = type_tuple($2, $4); } | SOPEN ftype SCLOSE { $$ = type_list($2); } | TBOOL { $$ = type_basic(btbool); } | TCHAR { $$ = type_basic(btchar); } | TINT { $$ = type_basic(btint); } | TVOID { $$ = type_basic(btvoid); } ; ftype : type | IDENT { $$ = type_var($1); } ; args : /* empty */ { $$ = NULL; } | nargs ; nargs : nargs COMMA IDENT { $$ = list_cons($3, $1); } | IDENT { $$ = list_cons($1, NULL); } ; fargs : /* empty */ { $$ = NULL; } | fnargs ; fnargs : fnargs COMMA expr { $$ = list_cons($3, $1); } | expr { $$ = list_cons($1, NULL); } ; body : /* empty */ { $$ = NULL; } | body stmt { $$ = list_cons($2, $1); } ; field : /* empty */ { $$ = NULL; } | field DOT IDENT { $$ = list_cons($3, $1); } ; bbody : COPEN body CCLOSE { $$ = $2; } | stmt { $$ = list_cons($1, NULL); } ; stmt : IF BOPEN expr BCLOSE bbody { $$ = stmt_if($3, $5, NULL); } | IF BOPEN expr BCLOSE bbody ELSE bbody { $$ = stmt_if($3, $5, $7); } | WHILE BOPEN expr BCLOSE bbody { $$ = stmt_while($3, $5); } | IDENT field ASSIGN expr SEMICOLON { $$ = stmt_assign($1, $2, $4); } | RETURN expr SEMICOLON { $$ = stmt_return($2); } | RETURN SEMICOLON { $$ = stmt_return(NULL); } | vardecl { $$ = stmt_vardecl($1); } | expr SEMICOLON { $$ = stmt_expr($1); } ; expr : expr BINOR expr { $$ = expr_binop($1, binor, $3); } | expr BINAND expr { $$ = expr_binop($1, binand, $3); } | expr EQ expr { $$ = expr_binop($1, eq, $3); } | expr NEQ expr { $$ = expr_binop($1, neq, $3); } | expr LEQ expr { $$ = expr_binop($1, leq, $3); } | expr LE expr { $$ = expr_binop($1, le, $3); } | expr GEQ expr { $$ = expr_binop($1, geq, $3); } | expr GE expr { $$ = expr_binop($1, ge, $3); } | expr CONS expr { $$ = expr_binop($1, cons, $3); } | expr PLUS expr { $$ = expr_binop($1, plus, $3); } | expr MINUS expr { $$ = expr_binop($1, minus, $3); } | expr TIMES expr { $$ = expr_binop($1, times, $3); } | expr DIVIDE expr { $$ = expr_binop($1, divide, $3); } | expr MODULO expr { $$ = expr_binop($1, modulo, $3); } | expr POWER expr { $$ = expr_binop($1, power, $3); } | MINUS expr %prec TIMES { $$ = expr_unop(negate, $2); } | INVERSE expr %prec TIMES { $$ = expr_unop(inverse, $2); } | IDENT BOPEN fargs BCLOSE field { $$ = expr_funcall($1, $3, $5); } | BOPEN expr COMMA expr BCLOSE { $$ = expr_tuple($2, $4); } | BOPEN expr BCLOSE { $$ = $2; } | INTEGER | BOOL | CHAR | STRING | IDENT field { $$ = expr_ident($1, $2); } | NIL { $$ = expr_nil(); } ;