]> 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 fbddbe101f74e40e1818ee9fffd4ba63aec65e29..932bb9ab5d8766c3a43f508a43b5add5b27825ab 100644 (file)
--- a/code.c
+++ b/code.c
@@ -5,11 +5,7 @@
 
 #include "umpf.h"
 
-#define HASHSIZE 103
-#define MAGIC 19
-#define BUFSIZE 1024
-
-static struct list* 
+struct list* 
 new_var_hash(void)
 {
        struct list* res;
@@ -22,7 +18,7 @@ new_var_hash(void)
        return res;
 }
 
-static int
+int
 get_bucket_number(char* name)
 {
        unsigned int n = 0;
@@ -36,36 +32,42 @@ get_bucket_number(char* name)
         return n;
 }
 
-/* if not found, variable with value "" is created  */ 
-static int
-find_var(char* name, struct list* hash)
+/* 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);
-       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;
+
+       return NULL;
+}
+
+int
+find_var(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->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;
-}
 
-void
-init(void)
-{
-       list_init(&input_code);
-       var_hash = new_var_hash();
-       const_tab = xmalloc(BUFSIZE);
-       cur_const_s = BUFSIZE;
+       return p->varcode;
 }
 
-static int
+int
 store_const(char* c)
 {
        if (cur_const_n >= cur_const_s) {
@@ -79,54 +81,386 @@ 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);
+}
+
+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)
+{
+       if (t->st == ST_LEAF) { 
+               return t->pt.leaf.n;
+       } 
+       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
-do_ass(struct tree* t)
+do_ass(struct tree* t, struct list* where)
 {
        int var_l, var_r;
        struct code ins;
-       var_l = find_var(t->pt.ass.left->pt.leaf.value, var_hash);
+       var_l = t->pt.ass.left->pt.leaf.n;
+       var_r = evaluate(t->pt.ass.right, -1, where);
+       
+       ins.opcode = OPC_SET;
+       ins.u.set.l = var_l;
+       ins.u.set.r = var_r;
+       new_instr(ins, where);
 
-       if (t->st == ST_LEAF) { 
-               if (t->pt.leaf.type == L_VAR)
-                       var_r = find_var(t->pt.leaf.value, var_hash);
+}
+
+static int
+eval_cond(struct tree *t, int pref_var, struct list* where)
+{
+       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
-                       var_r = store_const(t->pt.leaf.value);
-               ins.opc = SET;
-               ins.op1.i = var_l;
-               ins.op2.i = var_r;
-               new_instr(ins);
+                       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 '>':
+                               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", 
+                               t->pt.cond.op);
+
+               }
+       }
+       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
+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  = OPC_NOP;
+       jmp.opcode = OPC_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 = OPC_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
+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;
 }
 
 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:
-                       compile(t->pt.block.head);
-                       compile(t->pt.block.tail);
+                       reset_temp_var_count();
+                       compile(t->pt.block.head, where);
+                       compile(t->pt.block.tail, where);
                        break;
                case ST_EMPTY:
                        break;
+               case ST_LEAF: //warn?
+                       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?
+               case ST_ARROW:
+                       do_arrow(t, where);
                        break;
                default:
-                       die("compile: got to default");
+                       die("compile: got to default, type: %d", t->st);
        }
 }
 
 void
-print_code(struct tree* t)
+print_code(void)
 {
+       struct code* p;
 
+       LIST_FOREACH(p, &input_code) {
+               switch (p->opcode) {
+                       case OPC_SET:
+                               printf("SET %d %d\n", p->u.set.l, p->u.set.r);
+                               break; 
+                       case OPC_CAT:
+                               printf("CAT %d %d %d\n", p->u.tpop.l,
+                               p->u.tpop.r, p->u.tpop.res);
+                               break;
+                       case OPC_JUMP:
+                               printf("JUMP %d\n", (int) p->u.jump.target);
+                               break;
+                       case OPC_JUMP_UNLESS:
+                               printf("JUMP_UNLESS %d %d\n", p->u.jump_unless.cond,(int) p->u.jump_unless.target);
+                               break;
+                       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 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);
+               }
+       }
 }