]> mj.ucw.cz Git - umpf.git/blobdiff - code.c
fix content length after filtering mail
[umpf.git] / code.c
diff --git a/code.c b/code.c
index de0ed89338b6e86659ec6a56c0ef8ec765fe6690..932bb9ab5d8766c3a43f508a43b5add5b27825ab 100644 (file)
--- a/code.c
+++ b/code.c
@@ -5,9 +5,6 @@
 
 #include "umpf.h"
 
-#define HASHSIZE 103
-#define MAGIC 19
-
 struct list* 
 new_var_hash(void)
 {
@@ -21,7 +18,7 @@ new_var_hash(void)
        return res;
 }
 
-static int
+int
 get_bucket_number(char* name)
 {
        unsigned int n = 0;
@@ -35,22 +32,36 @@ get_bucket_number(char* name)
         return n;
 }
 
-/* if not found, variable with value "" is created  */ 
+/* return var struct or NULL if not found */
+struct variable*
+get_var_struct(char* name, enum var_type type, struct list* hash)
+{
+       int n;
+       struct variable *p;
+
+       n = get_bucket_number(name);
+       LIST_FOREACH(p, hash + n)
+               if (!strcasecmp(p->name, name) && p->type == type)
+                       return p;
+
+       return NULL;
+}
+
 int
-find_var(char* name, struct list* hash)
+find_var(char* name, enum var_type type, struct list* hash)
 {
        int n;
        struct variable *p;
 
        n = get_bucket_number(name);
-       int nocase = isupper(*name);
        LIST_FOREACH(p, hash + n)
-               if (!(nocase ? strcasecmp : strcmp)(p->name,name))
+               if (!strcasecmp(p->name, name) && p->type == type)
                        return p->varcode;
 
        p = xmalloc(sizeof(struct variable));
        p->name = xstrdup(name);
        p->varcode = current_varcode++;
+       p->type = type;
        list_add_last(hash+n, &p->car);
 
        return p->varcode;
@@ -80,38 +91,58 @@ new_instr(struct code c, struct list* where)
                list_add_last(&input_code, &p->car);
 }
 
+static int
+new_3par_instr(int opcode, int left, int right, int pref_var, 
+                struct list* where)
+{
+       struct code ins;
+
+       ins.opcode = opcode;
+       ins.u.tpop.l = left;
+       ins.u.tpop.r = right;
+       if (pref_var >= 0)
+               ins.u.tpop.res = pref_var;
+       else
+               ins.u.tpop.res = current_varcode++;;
+       new_instr(ins, where);
+       return ins.u.tpop.res;
+}
+
 /* return number of variable where lies result 
  * pref_var < 0 => no preference
  */
 static int
 evaluate(struct tree* t, int pref_var, struct list* where)
 {
-       struct code ins;
-
        if (t->st == ST_LEAF) { 
                return t->pt.leaf.n;
-       } else if (t->st == ST_OP) {
-               int left, right;
-               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;
-                               ins.u.cat.l = left;
-                               ins.u.cat.r = right;
-                               if (pref_var >= 0)
-                                       ins.u.cat.res = pref_var;
-                               else
-                                       ins.u.cat.res = current_varcode++;;
-                               new_instr(ins, where);
-                               return ins.u.cat.res;
-                               break;
-                       default:
-                               die("evaluate: got to default");
-               }
-       } else
-               die("evaluate: I can evaluate only expressions but I got %d",
-                       t->st);
+       } 
+       int left, right;
+       left = evaluate(t->pt.op.left, -1, where);
+       right = evaluate(t->pt.op.right, -1, where);
+       switch (t->pt.op.op) {
+               case '.':
+                       return new_3par_instr(OPC_CAT, left, 
+                               right, pref_var, where);
+                       break;
+               case '+':
+                       return new_3par_instr(OPC_PLUS, left, 
+                               right, pref_var, where);
+                       break;
+               case '-':
+                       return new_3par_instr(OPC_MINUS, left, 
+                               right, pref_var, where);
+                       break;
+               case '*':
+                       return new_3par_instr(OPC_MUL, left, 
+                               right, pref_var, where);
+                       break;
+               case '/':
+                       return new_3par_instr(OPC_DIV, left, 
+                               right, pref_var, where);
+                       break;
+       }
+       die("evaluate: Never can get here :)");
 }
 
 static void
@@ -122,7 +153,7 @@ do_ass(struct tree* t, struct list* where)
        var_l = t->pt.ass.left->pt.leaf.n;
        var_r = evaluate(t->pt.ass.right, -1, where);
        
-       ins.opcode = SET;
+       ins.opcode = OPC_SET;
        ins.u.set.l = var_l;
        ins.u.set.r = var_r;
        new_instr(ins, where);
@@ -132,7 +163,6 @@ do_ass(struct tree* t, struct list* 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)
@@ -149,16 +179,37 @@ eval_cond(struct tree *t, int pref_var, struct list* 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;
+                               return new_3par_instr (OPC_GT, left, 
+                                       right, pref_var, where);
+                               break;
+                       case '<':
+                               return new_3par_instr (OPC_LT, left, 
+                                       right, pref_var, where);
+                               break;
+                       case CC('<','='):
+                               return new_3par_instr (OPC_LE, left, 
+                                       right, pref_var, where);
+                               break;
+                       case CC('>','='):
+                               return new_3par_instr (OPC_GE, left, 
+                                       right, pref_var, where);
+                               break;
+                       case CC('!','~'):
+                               return new_3par_instr (OPC_NRE, left, 
+                                       right, pref_var, where);
+                               break;
+                       case CC('~','~'):
+                               return new_3par_instr (OPC_RE, left, 
+                                       right, pref_var, where);
+                               break;
+                       case CC('=','='):
+                               return new_3par_instr (OPC_EQ, left, 
+                                       right, pref_var, where);
+                               break;
+                       case CC('!','='):
+                               return new_3par_instr (OPC_NEQ, left, 
+                                       right, pref_var, where);
+                               break;
                        /* fixme: do more of them */
                        default:
                                die("eval_cond: unknown relation op %c\n", 
@@ -166,6 +217,42 @@ eval_cond(struct tree *t, int pref_var, struct list* where)
 
                }
        }
+       if (t->pt.cond.type == OP_BOOL) {
+               struct code ins;
+
+               left = eval_cond(t->pt.cond.left, -1, where);
+               if (t->pt.cond.op != '!') /* ! is unary */
+                       right = eval_cond(t->pt.cond.right, -1, where);
+               switch (t->pt.cond.op) {
+                       case '&':
+                               return new_3par_instr (OPC_AND, left, 
+                                       right, pref_var, where);
+                               break;
+                       case '|':
+                               return new_3par_instr (OPC_OR, left, 
+                                       right, pref_var, where);
+                               break;
+                       case '^':
+                               return new_3par_instr (OPC_XOR, left, 
+                                       right, pref_var, where);
+                               break;
+                       case '!':
+                               ins.opcode = OPC_NOT;
+                               ins.u.dpop.par = left;
+                               if (pref_var >= 0)
+                                       ins.u.dpop.res = pref_var;
+                               else
+                                       ins.u.dpop.res = current_varcode++;;
+                               new_instr(ins, where);
+                               return ins.u.dpop.res;
+                               break;
+                       default:
+                               die("eval_cond: unknown boolean op %c\n", 
+                               t->pt.cond.op);
+               }
+       }
+       
+       die("eval_cond: unknown condition type");
 }
 
 static void
@@ -178,8 +265,8 @@ do_if(struct tree *t, struct list* where)
 
        list_init(if_branch);
        list_init(else_branch);
-       nop.opcode  = NOP;
-       jmp.opcode = JUMP;
+       nop.opcode  = OPC_NOP;
+       jmp.opcode = OPC_JUMP;
 
        c = eval_cond(t->pt.tif.c, -1, where);
 
@@ -190,7 +277,7 @@ do_if(struct tree *t, struct list* where)
        jmp.u.jump.target = list_last(else_branch);
        new_instr(jmp, if_branch);
        
-       ins.opcode = JUMP_UNLESS;
+       ins.opcode = OPC_JUMP_UNLESS;
        ins.u.jump_unless.cond = c;
        ins.u.jump_unless.target = list_last(if_branch);
        new_instr(ins, where);
@@ -201,9 +288,50 @@ do_if(struct tree *t, struct list* where)
        free(else_branch);
 }
 
+static void
+do_arrow(struct tree* t, struct list* where)
+{
+       int v;
+       struct code ins;
+
+
+       if (t->pt.arrow.left == K_COPY)
+               ins.u.arrow.copy = 1;
+       else
+               ins.u.arrow.copy = 0;
+       switch (t->pt.arrow.right) {
+               case K_EMPTY:
+                       ins.opcode = OPC_DELIVER;
+                       break;
+               case K_PIPE:
+                       ins.opcode = OPC_PIPE;
+                       break;
+               case K_MAIL:
+                       ins.opcode = OPC_MAIL;
+                       break;
+               case K_DISCARD:
+                       ins.opcode = OPC_DISCARD;
+                       break;
+               case K_FILTER:
+                       ins.opcode = OPC_FILTER;
+                       break;
+               default:
+                       die("do_arrow: This cannot happen ;-)");
+       }
+
+       if (t->pt.arrow.right != K_DISCARD) {
+               v = evaluate(t->pt.arrow.s, -1, where);
+               ins.u.arrow.what = v;
+       }
+
+       new_instr(ins, where);
+}
+
 static void
 reset_temp_var_count(void)
 {
+       if (current_varcode > max_varcode)
+               max_varcode = current_varcode;
        current_varcode = temp_varcode_start;
 }
 
@@ -223,6 +351,8 @@ compile(struct tree* t, struct list* where)
                        break;
                case ST_EMPTY:
                        break;
+               case ST_LEAF: //warn?
+                       break;
                case ST_ASS:
                        do_ass(t, where);
                        break;
@@ -234,8 +364,11 @@ compile(struct tree* t, struct list* where)
                        break;
                case ST_COND:
                        eval_cond(t, -1, where); // warn?
+               case ST_ARROW:
+                       do_arrow(t, where);
+                       break;
                default:
-                       die("compile: got to default");
+                       die("compile: got to default, type: %d", t->st);
        }
 }
 
@@ -246,25 +379,85 @@ print_code(void)
 
        LIST_FOREACH(p, &input_code) {
                switch (p->opcode) {
-                       case SET:
+                       case OPC_SET:
                                printf("SET %d %d\n", p->u.set.l, p->u.set.r);
                                break; 
-                       case CAT:
-                               printf("CAT %d %d %d\n", p->u.cat.l,
-                               p->u.cat.r, p->u.cat.res);
+                       case OPC_CAT:
+                               printf("CAT %d %d %d\n", p->u.tpop.l,
+                               p->u.tpop.r, p->u.tpop.res);
                                break;
-                       case JUMP:
+                       case OPC_JUMP:
                                printf("JUMP %d\n", (int) p->u.jump.target);
                                break;
-                       case JUMP_UNLESS:
+                       case OPC_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);
+                       case OPC_GT:
+                               printf("GT %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
+                               break;
+                       case OPC_LT:
+                               printf("LT %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
+                               break;
+                       case OPC_LE:
+                               printf("LE %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
+                               break;
+                       case OPC_GE:
+                               printf("GE %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
+                               break;
+                       case OPC_RE:
+                               printf("RE %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
+                               break;
+                       case OPC_NRE:
+                               printf("NRE %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
+                               break;
+                       case OPC_NEQ:
+                               printf("NEQ %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
+                               break;
+                       case OPC_EQ:
+                               printf("EQ %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
+                               break;
+                       case OPC_AND:
+                               printf("AND %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
                                break;
-                       case NOP:
+                       case OPC_OR:
+                               printf("OR %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
+                               break;
+                       case OPC_XOR:
+                               printf("XOR %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
+                               break;
+                       case OPC_PLUS:
+                               printf("PLUS %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
+                               break;
+                       case OPC_MINUS:
+                               printf("MINUS %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
+                               break;
+                       case OPC_MUL:
+                               printf("MUL %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
+                               break;
+                       case OPC_DIV:
+                               printf("DIV %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
+                               break;
+                       case OPC_NOT:
+                               printf("NOT %d %d\n", p->u.dpop.par, p->u.dpop.res);
+                               break;
+                       case OPC_NOP:
                                puts("NOP");    
                                break;
+                       case OPC_PIPE:
+                               printf("PIPE %d %d\n", p->u.arrow.what, p->u.arrow.copy);
+                               break;
+                       case OPC_FILTER:
+                               printf("FILTER %d %d\n", p->u.arrow.what, p->u.arrow.copy);
+                               break;
+                       case OPC_DELIVER:
+                               printf("DELIVER %d %d\n", p->u.arrow.what, p->u.arrow.copy);
+                               break;
+                       case OPC_MAIL:
+                               printf("MAIL %d %d\n", p->u.arrow.what, p->u.arrow.copy);
+                               break;
+                       case OPC_DISCARD:
+                               puts("DISCARD");
+                               break;
                        default:
                                printf("not implemented, opcode: %d\n",
                                p->opcode);