edgecases
[ccc.git] / ast.c
diff --git a/ast.c b/ast.c
index 8b087f0..0a17870 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -62,11 +62,13 @@ struct decl *decl_var(struct vardecl *vardecl)
        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;
 }
@@ -142,12 +144,14 @@ struct expr *expr_char(const char *c)
        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;
@@ -156,8 +160,10 @@ struct expr *expr_char(const char *c)
                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;
 }
 
@@ -220,6 +226,16 @@ struct expr *expr_tuple(struct expr *left, struct expr *right)
        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));
@@ -282,15 +298,16 @@ struct type *type_var(char *ident)
 
 
 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)
@@ -360,6 +377,8 @@ void stmt_print(struct stmt *stmt, int indent, 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");
@@ -421,13 +440,16 @@ void expr_print(struct expr *expr, FILE *out)
                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);
@@ -457,6 +479,9 @@ void expr_print(struct expr *expr, FILE *out)
                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);
@@ -550,6 +575,8 @@ void stmt_free(struct stmt *stmt)
        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:
@@ -610,6 +637,9 @@ void expr_free(struct expr *expr)
                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;