]> mj.ucw.cz Git - umpf.git/commitdiff
start with conditions
authorAnicka Bernathova <anicka@anicka.net>
Tue, 14 Jul 2009 21:36:34 +0000 (23:36 +0200)
committerAnicka Bernathova <anicka@anicka.net>
Tue, 14 Jul 2009 21:36:34 +0000 (23:36 +0200)
code.c
lists.c
lists.h
umpf.h

diff --git a/code.c b/code.c
index af2348973efb31f07f733130576f46366003e908..de0ed89338b6e86659ec6a56c0ef8ec765fe6690 100644 (file)
--- a/code.c
+++ b/code.c
@@ -70,18 +70,21 @@ store_const(char* c)
 }
 
 static void
-new_instr(struct code c)
+new_instr(struct code c, struct list* where)
 {
        struct code* p = xmalloc(sizeof(struct code));
        *p = c;
-       list_add_last(&input_code, &p->car);
+       if (where)
+               list_add_last(where, &p->car);
+       else
+               list_add_last(&input_code, &p->car);
 }
 
 /* return number of variable where lies result 
  * pref_var < 0 => no preference
  */
 static int
-evaluate(struct tree* t, int pref_var)
+evaluate(struct tree* t, int pref_var, struct list* where)
 {
        struct code ins;
 
@@ -89,8 +92,8 @@ evaluate(struct tree* t, int pref_var)
                return t->pt.leaf.n;
        } else if (t->st == ST_OP) {
                int left, right;
-               left = evaluate(t->pt.op.left, -1);
-               right = evaluate(t->pt.op.right, -1);
+               left = evaluate(t->pt.op.left, -1, where);
+               right = evaluate(t->pt.op.right, -1, where);
                switch (t->pt.op.op) {
                        case '.':
                                ins.opcode = CAT;
@@ -100,7 +103,7 @@ evaluate(struct tree* t, int pref_var)
                                        ins.u.cat.res = pref_var;
                                else
                                        ins.u.cat.res = current_varcode++;;
-                               new_instr(ins);
+                               new_instr(ins, where);
                                return ins.u.cat.res;
                                break;
                        default:
@@ -112,20 +115,92 @@ evaluate(struct tree* t, int pref_var)
 }
 
 static void
-do_ass(struct tree* t)
+do_ass(struct tree* t, struct list* where)
 {
        int var_l, var_r;
        struct code ins;
        var_l = t->pt.ass.left->pt.leaf.n;
-       var_r = evaluate(t->pt.ass.right, -1);
+       var_r = evaluate(t->pt.ass.right, -1, where);
        
        ins.opcode = SET;
        ins.u.set.l = var_l;
        ins.u.set.r = var_r;
-       new_instr(ins);
+       new_instr(ins, where);
 
 }
 
+static int
+eval_cond(struct tree *t, int pref_var, struct list* where)
+{
+       struct code ins;
+       int left, right;
+       if (t->pt.cond.type == JUST_BOOL) {
+               if (t->pt.cond.left->st == ST_LEAF)
+                       return t->pt.cond.left->pt.leaf.n;
+               if (t->pt.cond.left->st == ST_OP)
+                       return evaluate(t->pt.cond.left, -1, where);
+               else
+                       die("eval_cond: %d cannot be JUST_BOOL\n", 
+                       t->pt.cond.left->st);
+       }
+       if (t->pt.cond.type == OP_REL) {
+               left = evaluate(t->pt.cond.left, -1, where);
+               right = evaluate(t->pt.cond.right, -1, where);
+
+               switch (t->pt.cond.op) {                
+                       case '>':
+                               ins.opcode = GT;
+                               ins.u.gt.l = left;
+                               ins.u.gt.r = right;
+                               if (pref_var >= 0)
+                                       ins.u.gt.res = pref_var;
+                               else
+                                       ins.u.gt.res = current_varcode++;;
+                               new_instr(ins, where);
+                               return ins.u.gt.res;
+                       break;
+                       /* fixme: do more of them */
+                       default:
+                               die("eval_cond: unknown relation op %c\n", 
+                               t->pt.cond.op);
+
+               }
+       }
+}
+
+static void
+do_if(struct tree *t, struct list* where)
+{
+       int c;
+       struct code ins, nop, jmp;
+       struct list* if_branch = xmalloc(sizeof(struct list));
+       struct list* else_branch = xmalloc(sizeof(struct list));
+
+       list_init(if_branch);
+       list_init(else_branch);
+       nop.opcode  = NOP;
+       jmp.opcode = JUMP;
+
+       c = eval_cond(t->pt.tif.c, -1, where);
+
+       compile(t->pt.tif.i, if_branch);        
+       compile(t->pt.tif.i, else_branch);      
+       new_instr(nop, if_branch);
+       new_instr(nop, else_branch);
+       jmp.u.jump.target = list_last(else_branch);
+       new_instr(jmp, if_branch);
+       
+       ins.opcode = JUMP_UNLESS;
+       ins.u.jump_unless.cond = c;
+       ins.u.jump_unless.target = list_last(if_branch);
+       new_instr(ins, where);
+       list_cat(where, if_branch);
+       list_cat(where, else_branch);
+
+       free(if_branch);
+       free(else_branch);
+}
+
 static void
 reset_temp_var_count(void)
 {
@@ -133,23 +208,32 @@ reset_temp_var_count(void)
 }
 
 void
-compile(struct tree* t)
+compile(struct tree* t, struct list* where)
 {
        if (!t)
                return;
+       if (! where)
+               where = &input_code;
+
        switch(t->st) {
                case ST_BLOCK:
                        reset_temp_var_count();
-                       compile(t->pt.block.head);
-                       compile(t->pt.block.tail);
+                       compile(t->pt.block.head, where);
+                       compile(t->pt.block.tail, where);
                        break;
                case ST_EMPTY:
                        break;
                case ST_ASS:
-                       do_ass(t);
+                       do_ass(t, where);
                        break;
                case ST_OP:
+                       evaluate(t, -1, where); //emit warning?
                        break;
+               case ST_IF:
+                       do_if(t, where);
+                       break;
+               case ST_COND:
+                       eval_cond(t, -1, where); // warn?
                default:
                        die("compile: got to default");
        }
@@ -169,6 +253,18 @@ print_code(void)
                                printf("CAT %d %d %d\n", p->u.cat.l,
                                p->u.cat.r, p->u.cat.res);
                                break;
+                       case JUMP:
+                               printf("JUMP %d\n", (int) p->u.jump.target);
+                               break;
+                       case JUMP_UNLESS:
+                               printf("JUMP_UNLESS %d %d\n", p->u.jump_unless.cond,(int) p->u.jump_unless.target);
+                               break;
+                       case GT:
+                               printf("GT %d %d %d\n", p->u.gt.l, p->u.gt.r, p->u.gt.res);
+                               break;
+                       case NOP:
+                               puts("NOP");    
+                               break;
                        default:
                                printf("not implemented, opcode: %d\n",
                                p->opcode);
diff --git a/lists.c b/lists.c
index ae9c3d7d6ed7b7e393d834007d007a3b7bd5e8e4..9d64e285640eddeab1d4188abd34d016cb357d15 100644 (file)
--- a/lists.c
+++ b/lists.c
@@ -111,3 +111,16 @@ list_del_last(struct list* l)
        
        return del;
 }
+
+void
+list_cat(struct list* dst, struct list* src) 
+{
+       struct node* dst_last = dst->head.prev;
+       struct node* src_first = src->head.next;
+       struct node* src_last = src->head.prev;
+
+       dst_last->next = src_first;
+       src_first->prev = dst_last;
+       src_last->next = &dst->head;
+       dst->head.prev = src_last;
+}
diff --git a/lists.h b/lists.h
index e430f02728c37533e86a10b1a71e952555a0651b..e4e30bd25bfba42a2de628e954a83b7464bd140c 100644 (file)
--- a/lists.h
+++ b/lists.h
@@ -21,3 +21,4 @@ void list_add_before(struct node* orig, struct node* new);
 void list_del_node(struct node* n);
 void* list_del_first(struct list* l);
 void* list_del_last(struct list* l);
+void list_cat(struct list* dst, struct list* src);
diff --git a/umpf.h b/umpf.h
index 179229f0da7a105b86445320812e2d6a181fe2d6..b5b7df82d6d43b2f08765736077af9c6fd27ac5c 100644 (file)
--- a/umpf.h
+++ b/umpf.h
@@ -26,7 +26,7 @@ struct tree {
                        enum {
                                OP_REL,
                                OP_BOOL,
-                               JUST_BOOL /* value only in left */      
+                               JUST_BOOL /* value only in left, no op */       
                        } type;
                        int op;
                        struct tree* left;
@@ -127,7 +127,8 @@ struct code {
                DELIVER,
                CALL_EXT,
                NOP,
-               CAT
+               CAT,
+               GT
        } opcode;
 
        union {
@@ -153,6 +154,11 @@ struct code {
                } cat;
                struct {
                } nop;
+               struct {
+                       int l;
+                       int r;
+                       int res; /* result */
+               } gt;
        } u;
 };
 
@@ -172,7 +178,7 @@ int cur_const_n;
 int cur_const_s;
 
 void init(void);
-void compile(struct tree* t);
+void compile(struct tree* t, struct list* where);
 int find_var(char* name, struct list* hash);
 int store_const(char* c);
 struct list* new_var_hash(void);