}
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;
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;
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:
}
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)
{
}
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");
}
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);