|
|
@ -1,5 +1,5 @@ |
|
|
|
/*
|
|
|
|
** $Id: lcode.c,v 1.5 2000/03/03 20:30:47 roberto Exp roberto $ |
|
|
|
** $Id: lcode.c,v 1.8 2000/03/09 13:57:37 roberto Exp roberto $ |
|
|
|
** Code generator for Lua |
|
|
|
** See Copyright Notice in lua.h |
|
|
|
*/ |
|
|
@ -100,6 +100,28 @@ static void luaK_conc (LexState *ls) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void luaK_eq (LexState *ls) { |
|
|
|
Instruction *previous = previous_instruction(ls); |
|
|
|
if (*previous == CREATE_U(PUSHNIL, 1)) { |
|
|
|
*previous = CREATE_0(NOTOP); |
|
|
|
luaK_deltastack(ls, -1); /* undo effect of PUSHNIL */ |
|
|
|
} |
|
|
|
else |
|
|
|
luaK_S(ls, IFEQJMP, 0, -2); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void luaK_neq (LexState *ls) { |
|
|
|
Instruction *previous = previous_instruction(ls); |
|
|
|
if (*previous == CREATE_U(PUSHNIL, 1)) { |
|
|
|
ls->fs->pc--; /* remove PUSHNIL */ |
|
|
|
luaK_deltastack(ls, -1); /* undo effect of PUSHNIL */ |
|
|
|
} |
|
|
|
else |
|
|
|
luaK_S(ls, IFNEQJMP, 0, -2); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void luaK_retcode (LexState *ls, int nlocals, int nexps) { |
|
|
|
Instruction *previous = previous_instruction(ls); |
|
|
|
if (nexps > 0 && GET_OPCODE(*previous) == CALL) { |
|
|
@ -116,9 +138,7 @@ static void luaK_pushnil (LexState *ls, int n) { |
|
|
|
Instruction *previous = previous_instruction(ls); |
|
|
|
luaK_deltastack(ls, n); |
|
|
|
switch(GET_OPCODE(*previous)) { |
|
|
|
case PUSHNIL: |
|
|
|
SETARG_U(*previous, GETARG_U(*previous)+n); |
|
|
|
break; |
|
|
|
case PUSHNIL: SETARG_U(*previous, GETARG_U(*previous)+n); break; |
|
|
|
default: luaK_primitivecode(ls, CREATE_U(PUSHNIL, n)); |
|
|
|
} |
|
|
|
} |
|
|
@ -281,6 +301,8 @@ static OpCode invertjump (OpCode op) { |
|
|
|
case IFLEJMP: return IFGTJMP; |
|
|
|
case IFGTJMP: return IFLEJMP; |
|
|
|
case IFGEJMP: return IFLTJMP; |
|
|
|
case IFTJMP: case ONTJMP: return IFFJMP; |
|
|
|
case IFFJMP: case ONFJMP: return IFTJMP; |
|
|
|
default: |
|
|
|
LUA_INTERNALERROR(NULL, "invalid jump instruction"); |
|
|
|
return ENDCODE; /* to avoid warnings */ |
|
|
@ -288,13 +310,23 @@ static OpCode invertjump (OpCode op) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void luaK_jump (LexState *ls, OpCode jump) { |
|
|
|
Instruction *previous = previous_instruction(ls); |
|
|
|
luaK_deltastack(ls, -1); |
|
|
|
if (*previous == CREATE_0(NOTOP)) |
|
|
|
*previous = CREATE_S(invertjump(jump), 0); |
|
|
|
else |
|
|
|
luaK_primitivecode(ls, CREATE_S(jump, 0)); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void insert_last (FuncState *fs, int *list) { |
|
|
|
int temp = *list; |
|
|
|
*list = fs->pc-1; |
|
|
|
if (temp == 0) /* chain list */ |
|
|
|
int first = *list; |
|
|
|
*list = fs->pc-1; /* insert last instruction in the list */ |
|
|
|
if (first == 0) |
|
|
|
SETARG_S(fs->f->code[*list], 0); |
|
|
|
else |
|
|
|
SETARG_S(fs->f->code[*list], temp-fs->pc); |
|
|
|
SETARG_S(fs->f->code[*list], first-fs->pc); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -305,18 +337,18 @@ static void luaK_patchlistaux (LexState *ls, int list, int target, |
|
|
|
for (;;) { |
|
|
|
Instruction *i = &code[list]; |
|
|
|
OpCode op = GET_OPCODE(*i); |
|
|
|
int temp = GETARG_S(*i); |
|
|
|
if (op == special) |
|
|
|
int next = GETARG_S(*i); |
|
|
|
if (op == special) /* this `op' already has a value */ |
|
|
|
SETARG_S(*i, special_target-(list+1)); |
|
|
|
else { |
|
|
|
SETARG_S(*i, target-(list+1)); |
|
|
|
if (op == ONTJMP) |
|
|
|
SETARG_S(*i, target-(list+1)); /* do the patch */ |
|
|
|
if (op == ONTJMP) /* remove eventual values */ |
|
|
|
SET_OPCODE(*i, IFTJMP); |
|
|
|
else if (op == ONFJMP) |
|
|
|
SET_OPCODE(*i, IFFJMP); |
|
|
|
} |
|
|
|
if (temp == 0) return; |
|
|
|
list += temp+1; |
|
|
|
if (next == 0) return; |
|
|
|
list += next+1; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -327,15 +359,15 @@ void luaK_patchlist (LexState *ls, int list, int target) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int has_jumps (FuncState *fs, int list, OpCode ignore) { |
|
|
|
static int need_value (FuncState *fs, int list, OpCode hasvalue) { |
|
|
|
if (list == 0) return 0; |
|
|
|
else { |
|
|
|
else { /* check whether list has a jump without a value */ |
|
|
|
Instruction *code = fs->f->code; |
|
|
|
for (;;) { |
|
|
|
int temp = GETARG_S(code[list]); |
|
|
|
if (GET_OPCODE(code[list]) != ignore) return 1; |
|
|
|
else if (temp == 0) return 0; |
|
|
|
list += temp+1; |
|
|
|
int next = GETARG_S(code[list]); |
|
|
|
if (GET_OPCODE(code[list]) != hasvalue) return 1; |
|
|
|
else if (next == 0) return 0; |
|
|
|
list += next+1; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -348,12 +380,12 @@ static void concatlists (LexState *ls, int *l1, int l2) { |
|
|
|
FuncState *fs = ls->fs; |
|
|
|
int list = *l1; |
|
|
|
for (;;) { /* traverse `l1' */ |
|
|
|
int temp = GETARG_S(fs->f->code[list]); |
|
|
|
if (temp == 0) { /* end of list? */ |
|
|
|
int next = GETARG_S(fs->f->code[list]); |
|
|
|
if (next == 0) { /* end of list? */ |
|
|
|
SETARG_S(fs->f->code[list], l2-(list+1)); /* end points to `l2' */ |
|
|
|
return; |
|
|
|
} |
|
|
|
list += temp+1; |
|
|
|
list += next+1; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -368,7 +400,7 @@ void luaK_goiftrue (LexState *ls, expdesc *v, int keepvalue) { |
|
|
|
SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous))); |
|
|
|
else { |
|
|
|
OpCode jump = keepvalue ? ONFJMP : IFFJMP; |
|
|
|
luaK_S(ls, jump, 0, -1); |
|
|
|
luaK_jump(ls, jump); |
|
|
|
} |
|
|
|
insert_last(fs, &v->u.l.f); |
|
|
|
luaK_patchlist(ls, v->u.l.t, luaK_getlabel(ls)); |
|
|
@ -378,12 +410,12 @@ void luaK_goiftrue (LexState *ls, expdesc *v, int keepvalue) { |
|
|
|
|
|
|
|
void luaK_goiffalse (LexState *ls, expdesc *v, int keepvalue) { |
|
|
|
FuncState *fs = ls->fs; |
|
|
|
Instruction *previous; |
|
|
|
Instruction previous; |
|
|
|
discharge1(ls, v); |
|
|
|
previous = &fs->f->code[fs->pc-1]; |
|
|
|
if (!ISJUMP(GET_OPCODE(*previous))) { |
|
|
|
previous = fs->f->code[fs->pc-1]; |
|
|
|
if (!ISJUMP(GET_OPCODE(previous))) { |
|
|
|
OpCode jump = keepvalue ? ONTJMP : IFTJMP; |
|
|
|
luaK_S(ls, jump, 0, -1); |
|
|
|
luaK_jump(ls, jump); |
|
|
|
} |
|
|
|
insert_last(fs, &v->u.l.t); |
|
|
|
luaK_patchlist(ls, v->u.l.f, luaK_getlabel(ls)); |
|
|
@ -395,8 +427,8 @@ void luaK_tostack (LexState *ls, expdesc *v, int onlyone) { |
|
|
|
if (discharge(ls, v)) return; |
|
|
|
else { /* is an expression */ |
|
|
|
FuncState *fs = ls->fs; |
|
|
|
Instruction *previous = &fs->f->code[fs->pc-1]; |
|
|
|
if (!ISJUMP(GET_OPCODE(*previous)) && v->u.l.f == 0 && v->u.l.t == 0) { |
|
|
|
OpCode previous = GET_OPCODE(fs->f->code[fs->pc-1]); |
|
|
|
if (!ISJUMP(previous) && v->u.l.f == 0 && v->u.l.t == 0) { |
|
|
|
/* it is an expression without jumps */ |
|
|
|
if (onlyone && v->k == VEXP) |
|
|
|
luaK_setcallreturns(ls, 1); /* call must return 1 value */ |
|
|
@ -406,25 +438,25 @@ void luaK_tostack (LexState *ls, expdesc *v, int onlyone) { |
|
|
|
int p_nil = 0; /* position of an eventual PUSHNIL */ |
|
|
|
int p_1 = 0; /* position of an eventual PUSHINT */ |
|
|
|
int final; /* position after whole expression */ |
|
|
|
if (ISJUMP(GET_OPCODE(*previous))) { |
|
|
|
insert_last(fs, &v->u.l.t); |
|
|
|
if (ISJUMP(previous)) { |
|
|
|
insert_last(fs, &v->u.l.t); /* put `previous' in true list */ |
|
|
|
p_nil = luaK_0(ls, PUSHNILJMP, 0); |
|
|
|
p_1 = luaK_S(ls, PUSHINT, 1, 1); |
|
|
|
} |
|
|
|
else { /* still may need a PUSHNIL or a PUSHINT */ |
|
|
|
int need_nil = has_jumps(fs, v->u.l.f, ONFJMP); /* needs a PUSHNIL? */ |
|
|
|
int need_1 = has_jumps(fs, v->u.l.t, ONTJMP); /* needs a PUSHINT? */ |
|
|
|
int need_nil = need_value(fs, v->u.l.f, ONFJMP); |
|
|
|
int need_1 = need_value(fs, v->u.l.t, ONTJMP); |
|
|
|
if (need_nil && need_1) { |
|
|
|
luaK_S(ls, JMP, 2, 0); |
|
|
|
luaK_S(ls, JMP, 2, 0); /* skip both pushes */ |
|
|
|
p_nil = luaK_0(ls, PUSHNILJMP, 0); |
|
|
|
p_1 = luaK_S(ls, PUSHINT, 1, 1); |
|
|
|
p_1 = luaK_S(ls, PUSHINT, 1, 0); |
|
|
|
} |
|
|
|
else if (need_nil || need_1) { |
|
|
|
luaK_S(ls, JMP, 1, 0); |
|
|
|
luaK_S(ls, JMP, 1, 0); /* skip one push */ |
|
|
|
if (need_nil) |
|
|
|
p_nil = luaK_0(ls, PUSHNIL, 1); |
|
|
|
p_nil = luaK_U(ls, PUSHNIL, 1, 0); |
|
|
|
else /* need_1 */ |
|
|
|
p_1 = luaK_S(ls, PUSHINT, 1, 1); |
|
|
|
p_1 = luaK_S(ls, PUSHINT, 1, 0); |
|
|
|
} |
|
|
|
} |
|
|
|
final = luaK_getlabel(ls); |
|
|
@ -462,7 +494,7 @@ void luaK_infix (LexState *ls, int op, expdesc *v) { |
|
|
|
else if (op == OR) |
|
|
|
luaK_goiffalse(ls, v, 1); |
|
|
|
else |
|
|
|
luaK_tostack(ls, v, 1); |
|
|
|
luaK_tostack(ls, v, 1); /* all other binary operators need a value */ |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -480,7 +512,7 @@ void luaK_posfix (LexState *ls, int op, expdesc *v1, expdesc *v2) { |
|
|
|
concatlists(ls, &v1->u.l.t, v2->u.l.t); |
|
|
|
} |
|
|
|
else { |
|
|
|
luaK_tostack(ls, v2, 1); /* `v2' must have a value */ |
|
|
|
luaK_tostack(ls, v2, 1); /* `v2' must be a value */ |
|
|
|
switch (op) { |
|
|
|
case '+': luaK_add(ls); break; |
|
|
|
case '-': luaK_sub(ls); break; |
|
|
@ -488,8 +520,8 @@ void luaK_posfix (LexState *ls, int op, expdesc *v1, expdesc *v2) { |
|
|
|
case '/': luaK_0(ls, DIVOP, -1); break; |
|
|
|
case '^': luaK_0(ls, POWOP, -1); break; |
|
|
|
case CONC: luaK_conc(ls); break; |
|
|
|
case EQ: luaK_S(ls, IFEQJMP, 0, -2); break; |
|
|
|
case NE: luaK_S(ls, IFNEQJMP, 0, -2); break; |
|
|
|
case EQ: luaK_eq(ls); break; |
|
|
|
case NE: luaK_neq(ls); break; |
|
|
|
case '>': luaK_S(ls, IFGTJMP, 0, -2); break; |
|
|
|
case '<': luaK_S(ls, IFLTJMP, 0, -2); break; |
|
|
|
case GE: luaK_S(ls, IFGEJMP, 0, -2); break; |
|
|
|