return res;
}
-struct stmt *stmt_assign(char *ident, struct expr *expr)
+struct stmt *stmt_assign(char *ident, struct list *fields, struct expr *expr)
{
struct stmt *res = safe_malloc(sizeof(struct stmt));
res->type = sassign;
res->data.sassign.ident = ident;
+ res->data.sassign.fields = (char **)
+ list_to_array(fields, &res->data.sassign.nfield, true);
res->data.sassign.expr = expr;
return res;
}
struct expr *res = safe_malloc(sizeof(struct expr));
res->type = echar;
//regular char
- if (strlen(c) == 3)
+ if (c[0] == '\'' && c[2] == '\'')
res->data.echar = c[1];
//escape
- if (strlen(c) == 4)
+ else if (c[0] == '\'' && c[1] == '\\' && c[3] == '\'')
switch(c[2]) {
case '0': res->data.echar = '\0'; break;
+ case '\'': res->data.echar = '\''; break;
+ case '\\': res->data.echar = '\\'; break;
case 'a': res->data.echar = '\a'; break;
case 'b': res->data.echar = '\b'; break;
case 't': res->data.echar = '\t'; break;
case 'r': res->data.echar = '\r'; break;
}
//hex escape
- if (strlen(c) == 6)
+ else if (c[0] == '\'' && c[1] == '\\' && c[2] == 'x' && c[5] == '\'')
res->data.echar = (fromHex(c[3])<<4)+fromHex(c[4]);
+ else
+ die("malformed character: %s\n", c);
return res;
}
return res;
}
+struct expr *expr_string(char *str)
+{
+ struct expr *res = safe_malloc(sizeof(struct expr));
+ res->type = estring;
+ res->data.estring = safe_strdup(str+1);
+ res->data.estring[strlen(res->data.estring)-1] = '\0';
+ //TODO escapes
+ return res;
+}
+
struct expr *expr_unop(enum unop op, struct expr *l)
{
struct expr *res = safe_malloc(sizeof(struct expr));
const char *cescapes[] = {
- [0] = "\\0", [1] = "\\x01", [2] = "\\x02", [3] = "\\x03",
- [4] = "\\x04", [5] = "\\x05", [6] = "\\x06", [7] = "\\a", [8] = "\\b",
- [9] = "\\t", [10] = "\\n", [11] = "\\v", [12] = "\\f", [13] = "\\r",
- [14] = "\\x0E", [15] = "\\x0F", [16] = "\\x10", [17] = "\\x11",
- [18] = "\\x12", [19] = "\\x13", [20] = "\\x14", [21] = "\\x15",
- [22] = "\\x16", [23] = "\\x17", [24] = "\\x18", [25] = "\\x19",
- [26] = "\\x1A", [27] = "\\x1B", [28] = "\\x1C", [29] = "\\x1D",
- [30] = "\\x1E", [31] = "\\x1F",
- [127] = "\\x7F"
+ [0] = "0", [1] = "x01", [2] = "x02", [3] = "x03",
+ [4] = "x04", [5] = "x05", [6] = "x06", [7] = "a", [8] = "b",
+ [9] = "t", [10] = "n", [11] = "v", [12] = "f", [13] = "r",
+ [14] = "x0E", [15] = "x0F", [16] = "x10", [17] = "x11",
+ [18] = "x12", [19] = "x13", [20] = "x14", [21] = "x15",
+ [22] = "x16", [23] = "x17", [24] = "x18", [25] = "x19",
+ [26] = "x1A", [27] = "x1B", [28] = "x1C", [29] = "x1D",
+ [30] = "x1E", [31] = "x1F",
+ ['\\'] = "\\", ['\''] = "'",
+ [127] = "x7F"
};
void ast_print(struct ast *ast, FILE *out)
case sassign:
pindent(indent, out);
fprintf(out, "%s", stmt->data.sassign.ident);
+ for (int i = 0; i<stmt->data.sassign.nfield; i++)
+ fprintf(out, ".%s", stmt->data.sassign.fields[i]);
safe_fprintf(out, " = ");
expr_print(stmt->data.sassign.expr, out);
safe_fprintf(out, ";\n");
safe_fprintf(out, "%s", expr->data.ebool ? "true" : "false");
break;
case echar:
- if (expr->data.echar < 0)
+ if (expr->data.echar < 0) {
safe_fprintf(out, "'?'");
- if (expr->data.echar < ' ' || expr->data.echar == 127)
- safe_fprintf(out, "'%s'",
+ } else if (expr->data.echar < ' ' || expr->data.echar == 127
+ || expr->data.echar == '\\'
+ || expr->data.echar == '\'') {
+ safe_fprintf(out, "'\\%s'",
cescapes[(int)expr->data.echar]);
- else
+ } else {
safe_fprintf(out, "'%c'", expr->data.echar);
+ }
break;
case efuncall:
safe_fprintf(out, "%s(", expr->data.efuncall.ident);
expr_print(expr->data.etuple.right, out);
safe_fprintf(out, ")");
break;
+ case estring:
+ safe_fprintf(out, "\"%s\"", expr->data.estring);
+ break;
case eunop:
safe_fprintf(out, "(%s", unop_str[expr->data.eunop.op]);
expr_print(expr->data.eunop.l, out);
switch(stmt->type) {
case sassign:
free(stmt->data.sassign.ident);
+ for (int i = 0; i<stmt->data.sassign.nfield; i++)
+ free(stmt->data.sassign.fields[i]);
expr_free(stmt->data.sassign.expr);
break;
case sif:
expr_free(expr->data.etuple.left);
expr_free(expr->data.etuple.right);
break;
+ case estring:
+ free(expr->data.estring);
+ break;
case eunop:
expr_free(expr->data.eunop.l);
break;
union {
struct {
char *ident;
+ int nfield;
+ char **fields;
struct expr *expr;
} sassign;
struct {
enum unop {negate,inverse};
struct expr {
enum {ebinop, ebool, echar, efuncall, eident, eint, enil, etuple,
- eunop} type;
+ estring, eunop} type;
union {
bool ebool;
struct {
struct expr *left;
struct expr *right;
} etuple;
+ char *estring;
struct {
enum unop op;
struct expr *l;
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_assign(char *ident, struct list *fields, struct expr *expr);
struct stmt *stmt_if(struct expr *pred, struct list *then, struct list *els);
struct stmt *stmt_return(struct expr *rtrn);
struct stmt *stmt_expr(struct expr *expr);
struct expr *expr_ident(char *ident, struct list *fields);
struct expr *expr_nil();
struct expr *expr_tuple(struct expr *left, struct expr *right);
+struct expr *expr_string(char *str);
struct expr *expr_unop(enum unop op, struct expr *l);
struct type *type_basic(enum basictype type);
%locations
%token <ident> IDENT
-%token <expr> BOOL CHAR INTEGER
+%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
%type <ast> start
%type <decl> fundecl
%type <expr> expr
-%type <list> args body decls fargs field fnargs nargs funtype vardecls
+%type <list> args body decls fargs field fnargs nargs funtype vardecls bbody
%type <stmt> stmt
-%type <type> type
+%type <type> type ftype
%type <vardecl> vardecl
%%
;
vardecl
: VAR IDENT ASSIGN expr SEMICOLON { $$ = vardecl(NULL, $2, $4); }
+ | type IDENT ASSIGN expr SEMICOLON { $$ = vardecl($1, $2, $4); }
;
fundecl
- : IDENT BOPEN args BCLOSE CONS CONS funtype ARROW type COPEN vardecls body CCLOSE
+ : IDENT BOPEN args BCLOSE CONS CONS funtype ARROW ftype 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); }
;
funtype
: /* empty */ { $$ = NULL; }
- | funtype type { $$ = list_cons($2, $1); }
- | funtype IDENT { $$ = list_cons(type_var($2), $1); }
+ | funtype ftype { $$ = list_cons($2, $1); }
;
+ftype
+ : 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); }
+ | IDENT { $$ = type_var($1); }
type
: BOPEN type COMMA type BCLOSE { $$ = type_tuple($2, $4); }
| SOPEN type SCLOSE { $$ = type_list($2); }
: /* 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
- { $$ = stmt_if($3, $6, $10); }
- | WHILE BOPEN expr BCLOSE COPEN body CCLOSE
- { $$ = stmt_while($3, $6); }
- | IDENT ASSIGN expr SEMICOLON { $$ = stmt_assign($1, $3); }
+ : 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); }
| expr SEMICOLON { $$ = stmt_expr($1); }
;
-field
- : /* empty */ { $$ = NULL; }
- | field DOT IDENT { $$ = list_cons($3, $1); }
expr
: expr BINOR expr { $$ = expr_binop($1, binor, $3); }
| expr BINAND expr { $$ = expr_binop($1, binand, $3); }
| INTEGER
| BOOL
| CHAR
+ | STRING
| IDENT field { $$ = expr_ident($1, $2); }
| NIL { $$ = expr_nil(); }
;