#include "util.h"
#include "ast.h"
+#include "y.tab.h"
static const char *binop_str[] = {
[binor] = "||", [binand] = "&&", [eq] = "==", [neq] = "!=",
static const char *fieldspec_str[] = {
[fst] = "fst", [snd] = "snd", [hd] = "hd", [tl] = "tl"};
static const char *unop_str[] = { [inverse] = "!", [negate] = "-", };
+static const char *basictype_str[] = {
+ [btbool] = "Bool", [btchar] = "Char", [btint] = "Int",
+ [btvoid] = "Void",
+};
struct ast *ast(struct list *decls)
{
return res;
}
-struct decl *decl_fun(char *ident, struct list *args, struct list *body)
+struct vardecl *vardecl(struct type *type, char *ident, struct expr *expr)
+{
+ struct vardecl *res = safe_malloc(sizeof(struct vardecl));
+ res->type = type;
+ res->ident = ident;
+ res->expr = expr;
+ return res;
+}
+
+struct decl *decl_fun(char *ident, struct list *args, struct list *atypes,
+ struct type *rtype, struct list *vars, struct list *body)
{
struct decl *res = safe_malloc(sizeof(struct decl));
res->type = dfundecl;
res->data.dfun.ident = ident;
res->data.dfun.args = (char **)
list_to_array(args, &res->data.dfun.nargs, true);
+ res->data.dfun.atypes = (struct type **)
+ list_to_array(atypes, &res->data.dfun.natypes, true);
+ res->data.dfun.rtype = rtype;
+ res->data.dfun.vars = (struct vardecl **)
+ list_to_array(vars, &res->data.dfun.nvar, true);
res->data.dfun.body = (struct stmt **)
list_to_array(body, &res->data.dfun.nbody, true);
return res;
}
-struct decl *decl_var(struct vardecl vardecl)
+struct decl *decl_var(struct vardecl *vardecl)
{
struct decl *res = safe_malloc(sizeof(struct decl));
res->type = dvardecl;
return res;
}
-struct stmt *stmt_vardecl(struct vardecl vardecl)
-{
- struct stmt *res = safe_malloc(sizeof(struct stmt));
- res->type = svardecl;
- res->data.svardecl = vardecl;
- return res;
-}
-
struct stmt *stmt_while(struct expr *pred, struct list *body)
{
struct stmt *res = safe_malloc(sizeof(struct stmt));
return res;
}
+struct type *type_list(struct type *type)
+{
+ struct type *res = safe_malloc(sizeof(struct type));
+ res->type = tlist;
+ res->data.tlist = type;
+ return res;
+}
+
+struct type *type_tuple(struct type *l, struct type *r)
+{
+ struct type *res = safe_malloc(sizeof(struct type));
+ res->type = ttuple;
+ res->data.ttuple.l = l;
+ res->data.ttuple.r = r;
+ return res;
+}
+
+struct type *type_var(char *ident)
+{
+ struct type *res = safe_malloc(sizeof(struct type));
+ if (strcmp(ident, "Int") == 0) {
+ res->type = tbasic;
+ res->data.tbasic = btint;
+ free(ident);
+ } else if (strcmp(ident, "Char") == 0) {
+ res->type = tbasic;
+ res->data.tbasic = btchar;
+ free(ident);
+ } else if (strcmp(ident, "Bool") == 0) {
+ res->type = tbasic;
+ res->data.tbasic = btbool;
+ free(ident);
+ } else if (strcmp(ident, "Void") == 0) {
+ res->type = tbasic;
+ res->data.tbasic = btvoid;
+ free(ident);
+ } else {
+ res->type = tvar;
+ res->data.tvar = ident;
+ }
+ return res;
+}
+
+
const char *cescapes[] = {
[0] = "\\0", [1] = "\\x01", [2] = "\\x02", [3] = "\\x03",
[4] = "\\x04", [5] = "\\x05", [6] = "\\x06", [7] = "\\a", [8] = "\\b",
decl_print(ast->decls[i], 0, out);
}
+void vardecl_print(struct vardecl *decl, int indent, FILE *out)
+{
+ pindent(indent, out);
+ if (decl->type == NULL)
+ safe_fprintf(out, "var");
+ else
+ type_print(decl->type, out);
+ safe_fprintf(out, " %s = ", decl->ident);
+ expr_print(decl->expr, out);
+ safe_fprintf(out, ";\n");
+}
+
void decl_print(struct decl *decl, int indent, FILE *out)
{
if (decl == NULL)
if (i < decl->data.dfun.nargs - 1)
safe_fprintf(out, ", ");
}
- safe_fprintf(out, ") {\n");
+ safe_fprintf(out, ")");
+ if (decl->data.dfun.rtype != NULL) {
+ safe_fprintf(out, " :: ");
+ for (int i = 0; i<decl->data.dfun.natypes; i++) {
+ type_print(decl->data.dfun.atypes[i], out);
+ safe_fprintf(out, " ");
+ }
+ safe_fprintf(out, "-> ");
+ type_print(decl->data.dfun.rtype, out);
+ }
+ safe_fprintf(out, " {\n");
+ for (int i = 0; i<decl->data.dfun.nvar; i++)
+ vardecl_print(decl->data.dfun.vars[i], indent+1, out);
for (int i = 0; i<decl->data.dfun.nbody; i++)
stmt_print(decl->data.dfun.body[i], indent+1, out);
pindent(indent, out);
safe_fprintf(out, "}\n");
break;
case dvardecl:
- pindent(indent, out);
- safe_fprintf(out, "var %s = ", decl->data.dvar.ident);
- expr_print(decl->data.dvar.expr, out);
- safe_fprintf(out, ";\n");
+ vardecl_print(decl->data.dvar, indent, out);
break;
default:
die("Unsupported decl node\n");
expr_print(stmt->data.sexpr, out);
safe_fprintf(out, ";\n");
break;
- case svardecl:
- pindent(indent, out);
- safe_fprintf(out, "var %s = ", stmt->data.svardecl.ident);
- expr_print(stmt->data.svardecl.expr, out);
- safe_fprintf(out, ";\n");
- break;
case swhile:
pindent(indent, out);
safe_fprintf(out, "while (");
}
}
+void type_print(struct type *type, FILE *out)
+{
+ if (type == NULL)
+ return;
+ switch (type->type) {
+ case tbasic:
+ safe_fprintf(out, "%s", basictype_str[type->data.tbasic]);
+ break;
+ case tlist:
+ safe_fprintf(out, "[");
+ type_print(type->data.tlist, out);
+ safe_fprintf(out, "]");
+ break;
+ case ttuple:
+ safe_fprintf(out, "(");
+ type_print(type->data.ttuple.l, out);
+ safe_fprintf(out, ",");
+ type_print(type->data.ttuple.r, out);
+ safe_fprintf(out, ")");
+ break;
+ case tvar:
+ safe_fprintf(out, "%s", type->data.tvar);
+ break;
+ default:
+ die("Unsupported type node\n");
+ }
+}
+
void ast_free(struct ast *ast)
{
if (ast == NULL)
free(ast);
}
+void vardecl_free(struct vardecl *decl)
+{
+ type_free(decl->type);
+ free(decl->ident);
+ expr_free(decl->expr);
+ free(decl);
+}
+
void decl_free(struct decl *decl)
{
if (decl == NULL)
for (int i = 0; i<decl->data.dfun.nargs; i++)
free(decl->data.dfun.args[i]);
free(decl->data.dfun.args);
+ for (int i = 0; i<decl->data.dfun.natypes; i++)
+ type_free(decl->data.dfun.atypes[i]);
+ free(decl->data.dfun.atypes);
+ type_free(decl->data.dfun.rtype);
+ for (int i = 0; i<decl->data.dfun.nvar; i++)
+ vardecl_free(decl->data.dfun.vars[i]);
+ free(decl->data.dfun.vars);
for (int i = 0; i<decl->data.dfun.nbody; i++)
stmt_free(decl->data.dfun.body[i]);
free(decl->data.dfun.body);
break;
case dvardecl:
- free(decl->data.dvar.ident);
- expr_free(decl->data.dvar.expr);
+ vardecl_free(decl->data.dvar);
break;
default:
die("Unsupported decl node\n");
case sexpr:
expr_free(stmt->data.sexpr);
break;
- case svardecl:
- free(stmt->data.svardecl.ident);
- expr_free(stmt->data.svardecl.expr);
- break;
case swhile:
expr_free(stmt->data.swhile.pred);
for (int i = 0; i<stmt->data.swhile.nbody; i++)
void expr_free(struct expr *expr)
{
+ if (expr == NULL)
+ return;
switch(expr->type) {
case ebinop:
expr_free(expr->data.ebinop.l);
}
free(expr);
}
+
+void type_free(struct type *type)
+{
+ if (type == NULL)
+ return;
+ switch (type->type) {
+ case tbasic:
+ break;
+ case tlist:
+ type_free(type->data.tlist);
+ break;
+ case ttuple:
+ type_free(type->data.ttuple.l);
+ type_free(type->data.ttuple.r);
+ break;
+ case tvar:
+ free(type->data.tvar);
+ break;
+ default:
+ die("Unsupported type node\n");
+ }
+ free(type);
+}
#include <stdbool.h>
#include "util.h"
+struct ast;
+#include "y.tab.h"
struct ast {
int ndecls;
};
struct vardecl {
+ struct type *type;
char *ident;
struct expr *expr;
};
+enum basictype {btbool, btchar, btint, btvoid};
+struct type {
+ enum {tbasic,tlist,ttuple,tvar} type;
+ union {
+ enum basictype tbasic;
+ struct type *tlist;
+ struct {
+ struct type *l;
+ struct type *r;
+ } ttuple;
+ char *tvar;
+ } data;
+};
+
struct decl {
enum {dfundecl, dvardecl} type;
union {
char *ident;
int nargs;
char **args;
+ int natypes;
+ struct type **atypes;
+ struct type *rtype;
+ int nvar;
+ struct vardecl **vars;
int nbody;
struct stmt **body;
} dfun;
- struct vardecl dvar;
+ struct vardecl *dvar;
} data;
};
struct stmt {
- enum {sassign, sif, sreturn, sexpr, svardecl, swhile} type;
+ enum {sassign, sif, sreturn, sexpr, swhile} type;
union {
struct {
char *ident;
} sif;
struct expr *sreturn;
struct expr *sexpr;
- struct vardecl svardecl;
struct {
struct expr *pred;
int nbody;
struct ast *ast(struct list *decls);
-struct decl *decl_fun(char *ident, struct list *args, struct list *body);
-struct decl *decl_var(struct vardecl vardecl);
+struct vardecl *vardecl(struct type *type, char *ident, struct expr *expr);
+
+struct decl *decl_fun(char *ident, struct list *args, struct list *atypes,
+ struct type *rtype, struct list *vars, struct list *body);
+struct decl *decl_var(struct vardecl *vardecl);
struct stmt *stmt_assign(char *ident, struct expr *expr);
struct stmt *stmt_if(struct expr *pred, struct list *then, struct list *els);
struct expr *expr_tuple(struct expr *left, struct expr *right);
struct expr *expr_unop(enum unop op, struct expr *l);
+struct type *type_list(struct type *type);
+struct type *type_tuple(struct type *l, struct type *r);
+struct type *type_var(char *ident);
+
void ast_print(struct ast *, FILE *out);
+void vardecl_print(struct vardecl *decl, int indent, FILE *out);
void decl_print(struct decl *ast, int indent, FILE *out);
void stmt_print(struct stmt *ast, int indent, FILE *out);
void expr_print(struct expr *ast, FILE *out);
+void type_print(struct type *type, FILE *out);
void ast_free(struct ast *);
+void vardecl_free(struct vardecl *decl);
void decl_free(struct decl *ast);
void stmt_free(struct stmt *ast);
void expr_free(struct expr *ast);
+void type_free(struct type *type);
#endif
%{
#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
#include "ast.h"
-
#include "y.tab.h"
int yylex(void);
+extern YYLTYPE yylloc;
void yyerror(struct ast **result, const char *str)
{
- ast_free(*result);
- fprintf(stderr, "error: %s\n", str);
+ fprintf(stderr, "%d-%d: %s\n", yylloc.first_line, yylloc.last_column, str);
+ (void)result;
}
int yywrap()
%}
-%union
-{
+%union {
struct expr *expr;
struct stmt *stmt;
struct list *list;
- struct vardecl vardecl;
+ struct vardecl *vardecl;
struct decl *decl;
+ struct type *type;
char *ident;
}
-//%define parse.error verbose
+%locations
%token <ident> IDENT
%token <expr> BOOL CHAR INTEGER
-%token ASSIGN BCLOSE BINAND BINOR BOPEN CCLOSE COMMA CONS COPEN DIVIDE DOT ELSE
-%token IF INVERSE MINUS MODULO NIL PLUS POWER RETURN SEMICOLON TIMES VAR WHILE
+%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 VAR WHILE
%parse-param { struct ast **result }
+%right ARROW
%right BINOR
%right BINAND
%nonassoc EQ NEQ LEQ LE GEQ GE
%right POWER
%type <ast> start
-%type <expr> expr
-%type <list> args body decls fargs field fnargs nargs
%type <decl> fundecl
-%type <vardecl> vardecl
+%type <expr> expr
+%type <list> args body decls fargs field fnargs nargs funtype vardecls
%type <stmt> stmt
+%type <type> type
+%type <vardecl> vardecl
%%
start : decls { *result = ast($1); } ;
decls
: { $$ = NULL; }
- | decls vardecl SEMICOLON { $$ = list_cons(decl_var($2), $1); }
+ | decls vardecl { $$ = list_cons(decl_var($2), $1); }
| decls fundecl { $$ = list_cons($2, $1); }
;
vardecl
- : VAR IDENT ASSIGN expr { $$ = (struct vardecl) {.ident=$2, .expr=$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
- { $$ = decl_fun($1, $3, $6); }
+ : IDENT BOPEN args BCLOSE CONS CONS funtype ARROW type COPEN vardecls body CCLOSE
+ { $$ = decl_fun($1, $3, $7, $9, $11, $12); }
+ | IDENT BOPEN args BCLOSE COPEN vardecls body CCLOSE
+ { $$ = decl_fun($1, $3, NULL, NULL, $6, $7); }
+ ;
+vardecls
+ : { $$ = NULL; }
+ | vardecls vardecl { $$ = list_cons($2, $1); }
+ ;
+funtype
+ : { $$ = NULL; }
+ | funtype type { $$ = list_cons($2, $1); }
+ ;
+type
+ : BOPEN type COMMA type BCLOSE { $$ = type_tuple($2, $4); }
+ | BOPEN type BCLOSE { $$ = $2; }
+ | SOPEN type SCLOSE { $$ = type_list($2); }
+ | IDENT { $$ = type_var($1); }
;
args
: { $$ = NULL; }
| IDENT ASSIGN expr SEMICOLON { $$ = stmt_assign($1, $3); }
| RETURN expr SEMICOLON { $$ = stmt_return($2); }
| RETURN SEMICOLON { $$ = stmt_return(NULL); }
- | vardecl SEMICOLON { $$ = stmt_vardecl($1); }
;
field
: { $$ = NULL; }
| 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 { $$ = expr_unop(negate, $2); }
+ | MINUS expr %prec TIMES { $$ = expr_unop(negate, $2); }
| INVERSE expr %prec TIMES { $$ = expr_unop(inverse, $2); }
| BOPEN expr COMMA expr BCLOSE { $$ = expr_tuple($2, $4); }
| BOPEN expr BCLOSE { $$ = $2; }