%{
#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
#include "ast.h"
-#define YYSTYPE struct ast *
+#include "list.h"
+#include "parse.h"
-#include "y.tab.h"
-
-int yylex_debug = 1;
int yylex(void);
+extern YYLTYPE yylloc;
void yyerror(struct ast **result, const char *str)
{
- ast_free(*result);
- fprintf(stderr, "error: %s\n", str);
+ (void)result;
+ fprintf(stderr, "%d-%d: %s\n", yylloc.first_line, yylloc.last_column, str);
}
int yywrap()
%}
+%define parse.lac full
%define parse.error verbose
-%token INTEGER PLUS MINUS TIMES DIVIDE BOPEN BCLOSE SEMICOLON POWER CONS MODULO
-%token BINOR BINAND INVERSE VAR ASSIGN IDENT COMMA COPEN CCLOSE IF ELSE WHILE
-%token BOOL CHAR
+
+%union {
+ struct expr *expr;
+ struct stmt *stmt;
+ struct list *list;
+ struct vardecl *vardecl;
+ struct fundecl *fundecl;
+ struct type *type;
+ char *ident;
+}
+
+%locations
+%token <ident> IDENT
+%token <expr> 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 }
%left TIMES DIVIDE MODULO
%right POWER
-%%
+%type <ast> start
+%type <expr> expr
+%type <list> args body decls fargs field fnargs nargs funtype bbody
+%type <stmt> stmt
+%type <type> type ftype
+%type <vardecl> vardecl
+%type <fundecl> fundecl
-start : decls { *result = ast_list($1); } ;
+%%
+start : decls { *result = ast($1); } ;
decls
- : { $$ = NULL; }
- | decls vardecl SEMICOLON { $$ = ast_cons($2, $1); }
- | decls fundecl { $$ = ast_cons($2, $1); }
+ : /* empty */ { $$ = NULL; }
+ | decls vardecl { $$ = list_cons(decl_var($2), $1); }
+ | decls fundecl { $$ = list_cons(decl_fun($2), $1); }
;
-
vardecl
- : VAR IDENT ASSIGN expr { $$ = ast_vardecl($2, $4); }
+ : 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
- { $$ = ast_fundecl($1, ast_list($3), ast_list($6)); }
+ { $$ = 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
- : { $$ = NULL; }
+ : /* empty */ { $$ = NULL; }
| nargs
;
nargs
- : nargs COMMA IDENT { $$ = ast_cons($3, $1); }
- | IDENT { $$ = ast_cons($1, NULL); }
+ : 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
- : { $$ = NULL; }
- | body vardecl SEMICOLON { $$ = ast_cons($2, $1); }
- | body stmt { $$ = ast_cons($2, $1); }
+ : /* 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 COPEN body CCLOSE ELSE COPEN body CCLOSE
- { $$ = ast_if($3, ast_list($6), ast_list($10)); }
- | WHILE BOPEN expr BCLOSE COPEN body CCLOSE
- { $$ = ast_while($3, ast_list($6)); }
- | expr SEMICOLON { $$ = ast_stmt_expr($1); }
+ : 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 { $$ = ast_binop($1, binor, $3); }
- | expr BINAND expr { $$ = ast_binop($1, binand, $3); }
- | expr EQ expr { $$ = ast_binop($1, eq, $3); }
- | expr NEQ expr { $$ = ast_binop($1, neq, $3); }
- | expr LEQ expr { $$ = ast_binop($1, leq, $3); }
- | expr LE expr { $$ = ast_binop($1, le, $3); }
- | expr GEQ expr { $$ = ast_binop($1, geq, $3); }
- | expr GE expr { $$ = ast_binop($1, ge, $3); }
- | expr CONS expr { $$ = ast_binop($1, cons, $3); }
- | expr PLUS expr { $$ = ast_binop($1, plus, $3); }
- | expr MINUS expr { $$ = ast_binop($1, minus, $3); }
- | expr TIMES expr { $$ = ast_binop($1, times, $3); }
- | expr DIVIDE expr { $$ = ast_binop($1, divide, $3); }
- | expr MODULO expr { $$ = ast_binop($1, modulo, $3); }
- | expr POWER expr { $$ = ast_binop($1, power, $3); }
- | MINUS expr { $$ = ast_unop(negate, $2); }
- | INVERSE expr { $$ = ast_unop(inverse, $2); }
+ : 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
- | IDENT
+ | STRING
+ | IDENT field { $$ = expr_ident($1, $2); }
+ | NIL { $$ = expr_nil(); }
;