#include "umpf.h"
-#define HASHSIZE 103
-#define MAGIC 19
-#define BUFSIZE 1024
-
-static struct list*
+struct list*
new_var_hash(void)
{
struct list* res;
return res;
}
-static int
+int
get_bucket_number(char* name)
{
unsigned int n = 0;
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) {
}
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);
+ }
+ }
}