long vm_execute(VMContext ctx, ScriptCInstruction inst) { static const void *table[] = { #define DEFINE_TABLE(NAME) &&OP_##NAME, IR_EACH(DEFINE_TABLE) #undef DEFINE_TABLE }; if(inst == NULL) { return (long)table; } register ScriptCInstruction pc = inst+1; goto *GET_ADDR(pc); OP(exit) { return 0; } OP(call) { ctx = createVMContext(ctx, pc-inst+1); JUMP(inst + pc->call_point); } OP(ret) { long retPoint = ctx->retPoint; Type top = pop_sp(ctx); VMContext next = call_back(ctx); if(top->type == TYPE_INT) { push_i(next, top->int_val); } else if(top->type == TYPE_FLOAT) { push_d(next, top->double_val); } else if(top->type == TYPE_STRING) { push_s(next, top->string); } else if(top->type == TYPE_BOOL) { push_b(next, top->bool_val); } else { fprintf(stderr, "type error of return statement\n"); return 1; } disposeVMContext(ctx); ctx = next; JUMP(inst + retPoint); } OP(ret_void) { long retPoint = ctx->retPoint; VMContext next = call_back(ctx); disposeVMContext(ctx); ctx = next; JUMP(inst + retPoint); } OP(iconst) { push_i(ctx, pc->int_val); DISPATCH_NEXT; } OP(dconst) { push_d(ctx, pc->double_val); DISPATCH_NEXT; } OP(sconst) { push_s(ctx, pc->string); DISPATCH_NEXT; } OP(bconst) { push_b(ctx, pc->bool_val); DISPATCH_NEXT; } OP(jump) { JUMP(inst + pc->jump); } OP(ifcmp) { Type top = pop_sp(ctx); if(top->type != TYPE_BOOL) { fprintf(stderr, "type error of ifcmp\n"); } if(!top->bool_val) { JUMP(inst + pc->jump); } DISPATCH_NEXT; } OP(gt) { Type right = pop_sp(ctx); Type left = pop_sp(ctx); if(right->type == TYPE_INT && left->type == TYPE_INT) { push_b(ctx, left->int_val > right->int_val); } else if(right->type == TYPE_FLOAT && left->type == TYPE_FLOAT) { push_b(ctx, left->double_val > right->double_val); } else { fprintf(stderr, "type error of gt expression\n"); return 1; } DISPATCH_NEXT; } OP(ge) { Type right = pop_sp(ctx); Type left = pop_sp(ctx); if(right->type == TYPE_INT && left->type == TYPE_INT) { push_b(ctx, left->int_val >= right->int_val); } else if(right->type == TYPE_FLOAT && left->type == TYPE_FLOAT) { push_b(ctx, left->double_val >= right->double_val); } else { fprintf(stderr, "type error of ge expression\n"); return 1; } DISPATCH_NEXT; } OP(lt) { Type right = pop_sp(ctx); Type left = pop_sp(ctx); if(right->type == TYPE_INT && left->type == TYPE_INT) { push_b(ctx, left->int_val < right->int_val); } else if(right->type == TYPE_FLOAT && left->type == TYPE_FLOAT) { push_b(ctx, left->double_val < right->double_val); } else { fprintf(stderr, "type error of lt expression\n"); return 1; } DISPATCH_NEXT; } OP(le) { Type right = pop_sp(ctx); Type left = pop_sp(ctx); if(right->type == TYPE_INT && left->type == TYPE_INT) { push_b(ctx, left->int_val <= right->int_val); } else if(right->type == TYPE_FLOAT && left->type == TYPE_FLOAT) { push_b(ctx, left->double_val <= right->double_val); } else { fprintf(stderr, "type error of le expression\n"); return 1; } DISPATCH_NEXT; } OP(eq) { Type right = pop_sp(ctx); Type left = pop_sp(ctx); if(right->type == TYPE_INT && left->type == TYPE_INT) { push_b(ctx, left->int_val == right->int_val); } else if(right->type == TYPE_FLOAT && left->type == TYPE_FLOAT) { push_b(ctx, left->double_val == right->double_val); } else if(right->type == TYPE_STRING && left->type == TYPE_STRING) { push_b(ctx, !strcmp(left->string, right->string)); } else if(right->type == TYPE_BOOL && left->type == TYPE_BOOL) { push_b(ctx, left->bool_val == right->bool_val); } else { fprintf(stderr, "type error of le expression\n"); return 1; } DISPATCH_NEXT; } OP(ne) { Type right = pop_sp(ctx); Type left = pop_sp(ctx); if(right->type == TYPE_INT && left->type == TYPE_INT) { push_b(ctx, left->int_val != right->int_val); } else if(right->type == TYPE_FLOAT && left->type == TYPE_FLOAT) { push_b(ctx, left->double_val != right->double_val); } else if(right->type == TYPE_STRING && left->type == TYPE_STRING) { push_b(ctx, strcmp(left->string, right->string)); } else if(right->type == TYPE_BOOL && left->type == TYPE_BOOL) { push_b(ctx, left->bool_val != right->bool_val); } else { fprintf(stderr, "type error of le expression\n"); return 1; } DISPATCH_NEXT; } OP(add) { Type right = pop_sp(ctx); Type left = pop_sp(ctx); if(right->type == TYPE_INT && left->type == TYPE_INT) { push_i(ctx, left->int_val + right->int_val); } else if(right->type == TYPE_FLOAT && left->type == TYPE_FLOAT) { push_d(ctx, left->double_val + right->double_val); } else if(right->type == TYPE_STRING && left->type == TYPE_STRING) { strcat(left->string, right->string); push_s(ctx, left->string); } else { fprintf(stderr, "type error of add expression\n"); return 1; } DISPATCH_NEXT; } OP(sub) { Type right = pop_sp(ctx); Type left = pop_sp(ctx); if(right->type == TYPE_INT && left->type == TYPE_INT) { push_i(ctx, left->int_val - right->int_val); } else if(right->type == TYPE_FLOAT && left->type == TYPE_FLOAT) { push_d(ctx, left->double_val - right->double_val); } else { fprintf(stderr, "type error of sub expression\n"); return 1; } DISPATCH_NEXT; } OP(mul) { Type right = pop_sp(ctx); Type left = pop_sp(ctx); if(right->type == TYPE_INT && left->type == TYPE_INT) { push_i(ctx, left->int_val * right->int_val); } else if(right->type == TYPE_FLOAT && left->type == TYPE_FLOAT) { push_d(ctx, left->double_val * right->double_val); } else { fprintf(stderr, "type error of mul expression\n"); return 1; } DISPATCH_NEXT; } OP(div) { Type right = pop_sp(ctx); Type left = pop_sp(ctx); if(right->type == TYPE_INT && left->type == TYPE_INT) { push_i(ctx, left->int_val / right->int_val); } else if(right->type == TYPE_FLOAT && left->type == TYPE_FLOAT) { push_d(ctx, left->double_val / right->double_val); } else { fprintf(stderr, "type error of div expression\n"); return 1; } DISPATCH_NEXT; } OP(minus) { Type left = pop_sp(ctx); if(left->type == TYPE_INT) { push_i(ctx, -left->int_val); } else if(left->type == TYPE_FLOAT) { push_d(ctx, -left->double_val); } else { fprintf(stderr, "type error of add expression\n"); return 1; } DISPATCH_NEXT; } OP(loadl) { Type val = ctx->var_list+pc->var_id; if(val->type == TYPE_INT) { push_i(ctx, val->int_val); } else if(val->type == TYPE_FLOAT) { push_d(ctx, val->double_val); } else if(val->type == TYPE_STRING) { push_s(ctx, val->string); } else if(val->type == TYPE_BOOL) { push_b(ctx, val->bool_val); } else { fprintf(stderr, "type error of loadl\n"); return 1; } DISPATCH_NEXT; } OP(storea) { Type val = ctx->var_list+pc->var_id; Type top = pop_sp(ctx->prev); if(top->type == TYPE_INT) { val->int_val = top->int_val; } else if(top->type == TYPE_FLOAT) { val->double_val = top->double_val; } else if(top->type == TYPE_STRING) { val->string = top->string; } else if(top->type == TYPE_BOOL) { val->bool_val = top->bool_val; } else { fprintf(stderr, "type error of storel\n"); return 1; } DISPATCH_NEXT; } OP(storel) { Type val = ctx->var_list+pc->var_id; Type top = pop_sp(ctx); if(top->type == TYPE_INT) { val->int_val = top->int_val; val->type = TYPE_INT; } else if(top->type == TYPE_FLOAT) { val->double_val = top->double_val; val->type = TYPE_FLOAT; } else if(top->type == TYPE_STRING) { val->string = top->string; val->type = TYPE_STRING; } else if(top->type == TYPE_BOOL) { val->bool_val = top->bool_val; val->type = TYPE_BOOL; } else { fprintf(stderr, "type error of storel\n"); return 1; } DISPATCH_NEXT; } OP(write) { Type val = pop_sp(ctx); if(val->type == TYPE_INT) { printf("%d\n", val->int_val); } else if(val->type == TYPE_FLOAT) { printf("%f\n", val->double_val); } else if(val->type == TYPE_STRING) { printf("%s\n", val->string); } else if(val->type == TYPE_BOOL) { if(val->bool_val) { printf("true\n"); } else { printf("false\n"); } } DISPATCH_NEXT; } return 0; }
CompileOutput *Compiler::Compile(AMXRef amx) { Prepare(amx); Disassembler disasm(amx); Instruction instr; bool error = false; while (!error && disasm.Decode(instr, error)) { if (!Process(instr)) { error = true; break; } switch (instr.opcode().GetId()) { case OP_LOAD_PRI: load_pri(instr.operand()); break; case OP_LOAD_ALT: load_alt(instr.operand()); break; case OP_LOAD_S_PRI: load_s_pri(instr.operand()); break; case OP_LOAD_S_ALT: load_s_alt(instr.operand()); break; case OP_LREF_PRI: lref_pri(instr.operand()); break; case OP_LREF_ALT: lref_alt(instr.operand()); break; case OP_LREF_S_PRI: lref_s_pri(instr.operand()); break; case OP_LREF_S_ALT: lref_s_alt(instr.operand()); break; case OP_LOAD_I: load_i(); break; case OP_LODB_I: lodb_i(instr.operand()); break; case OP_CONST_PRI: const_pri(instr.operand()); break; case OP_CONST_ALT: const_alt(instr.operand()); break; case OP_ADDR_PRI: addr_pri(instr.operand()); break; case OP_ADDR_ALT: addr_alt(instr.operand()); break; case OP_STOR_PRI: stor_pri(instr.operand()); break; case OP_STOR_ALT: stor_alt(instr.operand()); break; case OP_STOR_S_PRI: stor_s_pri(instr.operand()); break; case OP_STOR_S_ALT: stor_s_alt(instr.operand()); break; case OP_SREF_PRI: sref_pri(instr.operand()); break; case OP_SREF_ALT: sref_alt(instr.operand()); break; case OP_SREF_S_PRI: sref_s_pri(instr.operand()); break; case OP_SREF_S_ALT: sref_s_alt(instr.operand()); break; case OP_STOR_I: stor_i(); break; case OP_STRB_I: strb_i(instr.operand()); break; case OP_LIDX: lidx(); break; case OP_LIDX_B: lidx_b(instr.operand()); break; case OP_IDXADDR: idxaddr(); break; case OP_IDXADDR_B: idxaddr_b(instr.operand()); break; case OP_ALIGN_PRI: align_pri(instr.operand()); break; case OP_ALIGN_ALT: align_alt(instr.operand()); break; case OP_LCTRL: lctrl(instr.operand(), instr.address() + instr.size()); break; case OP_SCTRL: sctrl(instr.operand()); break; case OP_MOVE_PRI: move_pri(); break; case OP_MOVE_ALT: move_alt(); break; case OP_XCHG: xchg(); break; case OP_PUSH_PRI: push_pri(); break; case OP_PUSH_ALT: push_alt(); break; case OP_PUSH_C: push_c(instr.operand()); break; case OP_PUSH: push(instr.operand()); break; case OP_PUSH_S: push_s(instr.operand()); break; case OP_POP_PRI: pop_pri(); break; case OP_POP_ALT: pop_alt(); break; case OP_STACK: // value stack(instr.operand()); break; case OP_HEAP: heap(instr.operand()); break; case OP_PROC: proc(); break; case OP_RET: ret(); break; case OP_RETN: retn(); break; case OP_JUMP_PRI: jump_pri(); break; case OP_CALL: case OP_JUMP: case OP_JZER: case OP_JNZ: case OP_JEQ: case OP_JNEQ: case OP_JLESS: case OP_JLEQ: case OP_JGRTR: case OP_JGEQ: case OP_JSLESS: case OP_JSLEQ: case OP_JSGRTR: case OP_JSGEQ: { cell dest = instr.operand() - reinterpret_cast<cell>(amx.code()); switch (instr.opcode().GetId()) { case OP_CALL: call(dest); break; case OP_JUMP: jump(dest); break; case OP_JZER: jzer(dest); break; case OP_JNZ: jnz(dest); break; case OP_JEQ: jeq(dest); break; case OP_JNEQ: jneq(dest); break; case OP_JLESS: jless(dest); break; case OP_JLEQ: jleq(dest); break; case OP_JGRTR: jgrtr(dest); break; case OP_JGEQ: jgeq(dest); break; case OP_JSLESS: jsless(dest); break; case OP_JSLEQ: jsleq(dest); break; case OP_JSGRTR: jsgrtr(dest); break; case OP_JSGEQ: jsgeq(dest); break; } break; } case OP_SHL: shl(); break; case OP_SHR: shr(); break; case OP_SSHR: sshr(); break; case OP_SHL_C_PRI: shl_c_pri(instr.operand()); break; case OP_SHL_C_ALT: shl_c_alt(instr.operand()); break; case OP_SHR_C_PRI: shr_c_pri(instr.operand()); break; case OP_SHR_C_ALT: shr_c_alt(instr.operand()); break; case OP_SMUL: smul(); break; case OP_SDIV: sdiv(); break; case OP_SDIV_ALT: sdiv_alt(); break; case OP_UMUL: umul(); break; case OP_UDIV: udiv(); break; case OP_UDIV_ALT: udiv_alt(); break; case OP_ADD: add(); break; case OP_SUB: sub(); break; case OP_SUB_ALT: sub_alt(); break; case OP_AND: and_(); break; case OP_OR: or_(); break; case OP_XOR: xor_(); break; case OP_NOT: not_(); break; case OP_NEG: neg(); break; case OP_INVERT: invert(); break; case OP_ADD_C: add_c(instr.operand()); break; case OP_SMUL_C: smul_c(instr.operand()); break; case OP_ZERO_PRI: zero_pri(); break; case OP_ZERO_ALT: zero_alt(); break; case OP_ZERO: zero(instr.operand()); break; case OP_ZERO_S: zero_s(instr.operand()); break; case OP_SIGN_PRI: sign_pri(); break; case OP_SIGN_ALT: sign_alt(); break; case OP_EQ: eq(); break; case OP_NEQ: neq(); break; case OP_LESS: less(); break; case OP_LEQ: leq(); break; case OP_GRTR: grtr(); break; case OP_GEQ: geq(); break; case OP_SLESS: sless(); break; case OP_SLEQ: sleq(); break; case OP_SGRTR: sgrtr(); break; case OP_SGEQ: sgeq(); break; case OP_EQ_C_PRI: eq_c_pri(instr.operand()); break; case OP_EQ_C_ALT: eq_c_alt(instr.operand()); break; case OP_INC_PRI: inc_pri(); break; case OP_INC_ALT: inc_alt(); break; case OP_INC: inc(instr.operand()); break; case OP_INC_S: inc_s(instr.operand()); break; case OP_INC_I: inc_i(); break; case OP_DEC_PRI: dec_pri(); break; case OP_DEC_ALT: dec_alt(); break; case OP_DEC: dec(instr.operand()); break; case OP_DEC_S: dec_s(instr.operand()); break; case OP_DEC_I: dec_i(); break; case OP_MOVS: movs(instr.operand()); break; case OP_CMPS: cmps(instr.operand()); break; case OP_FILL: fill(instr.operand()); break; case OP_HALT: halt(instr.operand()); break; case OP_BOUNDS: bounds(instr.operand()); break; case OP_SYSREQ_PRI: sysreq_pri(); break; case OP_SYSREQ_C: { const char *name = amx.GetNativeName(instr.operand()); if (name == 0) { error = true; } else { sysreq_c(instr.operand(), name); } break; } case OP_SYSREQ_D: { const char *name = amx.GetNativeName(amx.FindNative(instr.operand())); if (name == 0) { error = true; } else { sysreq_d(instr.operand(), name); } break; } case OP_SWITCH: switch_(CaseTable(amx, instr.operand())); break; case OP_CASETBL: casetbl(); break; case OP_SWAP_PRI: swap_pri(); break; case OP_SWAP_ALT: swap_alt(); break; case OP_PUSH_ADR: push_adr(instr.operand()); break; case OP_NOP: nop(); break; case OP_BREAK: break_(); break; default: error = true; } } if (error && error_handler_ != 0) { error_handler_->Execute(instr); } return Finish(error); }