mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 13:06:59 -04:00
Script cleanup for standards-compliance (not going out of bounds on vectors).
I_POP is no longer considered a binary instruction because all other binary instructions expect the stack to have at least two elements - adding a manual check is kludgy Added I_TAILCALL to accomodate indended optimizations git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@1417 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
+16
-11
@@ -44,12 +44,15 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
|
||||
try {
|
||||
// Instruction pointer
|
||||
const Instruction* instr = &script.instructions[0];
|
||||
const Instruction* end = &*script.instructions.end();
|
||||
const Instruction* end = instr + script.instructions.size();
|
||||
|
||||
// Loop until we are done
|
||||
while (instr < end) {
|
||||
// Evaluate the current instruction
|
||||
Instruction i = *instr++;
|
||||
// If a scope is created, destroy it at end of block.
|
||||
scoped_ptr<LocalScope> scope;
|
||||
|
||||
switch (i.instr) {
|
||||
case I_NOP: break;
|
||||
// Push a constant
|
||||
@@ -59,7 +62,7 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
|
||||
}
|
||||
// Jump
|
||||
case I_JUMP: {
|
||||
instr = &script.instructions[i.data];
|
||||
instr = &script.instructions[0] + i.data;
|
||||
break;
|
||||
}
|
||||
// Conditional jump
|
||||
@@ -67,7 +70,7 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
|
||||
bool condition = *stack.back();
|
||||
stack.pop_back();
|
||||
if (!condition) {
|
||||
instr = &script.instructions[i.data];
|
||||
instr = &script.instructions[0] + i.data;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -98,7 +101,7 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
|
||||
stack.push_back(val);
|
||||
} else {
|
||||
stack.erase(stack.end() - 2); // remove iterator
|
||||
instr = &script.instructions[i.data];
|
||||
instr = &script.instructions[0] + i.data;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -112,7 +115,7 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
|
||||
stack.push_back(key);
|
||||
} else {
|
||||
stack.erase(stack.end() - 2); // remove iterator
|
||||
instr = &script.instructions[i.data];
|
||||
instr = &script.instructions[0] + i.data;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -123,9 +126,8 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
|
||||
}
|
||||
|
||||
// Function call
|
||||
case I_CALL: {
|
||||
// new scope
|
||||
LocalScope local_scope(*this);
|
||||
case I_CALL: scope.reset(new LocalScope(*this)); //new scope
|
||||
case I_TAILCALL: {
|
||||
// prepare arguments
|
||||
for (unsigned int j = 0 ; j < i.data ; ++j) {
|
||||
setVariable((Variable)instr[i.data - j - 1].data, stack.back());
|
||||
@@ -203,6 +205,12 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
|
||||
instrQuaternary(i.instr4, a, b, c, d);
|
||||
break;
|
||||
}
|
||||
// Pop off stack
|
||||
case I_POP: {
|
||||
stack.pop_back();
|
||||
break;
|
||||
}
|
||||
|
||||
// Duplicate stack
|
||||
case I_DUP: {
|
||||
stack.push_back(stack.at(stack.size() - i.data - 1));
|
||||
@@ -419,9 +427,6 @@ class ScriptCompose : public ScriptValue {
|
||||
|
||||
void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP& b) {
|
||||
switch (i) {
|
||||
case I_POP:
|
||||
// a = a;
|
||||
break;
|
||||
case I_MEMBER:
|
||||
a = a->getMember(*b);
|
||||
break;
|
||||
|
||||
@@ -169,7 +169,7 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script)
|
||||
delete j;
|
||||
}
|
||||
|
||||
if (instr >= &*script.instructions.end()) break; // end of script
|
||||
if (instr >= &script.instructions[0] + script.instructions.size()) break; // end of script
|
||||
|
||||
// Analyze the current instruction
|
||||
Instruction i = *instr++;
|
||||
@@ -182,11 +182,11 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script)
|
||||
}
|
||||
// Jump
|
||||
case I_JUMP: {
|
||||
if (&script.instructions[i.data] >= instr) {
|
||||
if ( &script.instructions[0] + i.data >= instr) {
|
||||
// forward jump
|
||||
// create jump record
|
||||
Jump* jump = new Jump;
|
||||
jump->target = &script.instructions[i.data];
|
||||
jump->target = &script.instructions[0] + i.data;
|
||||
jump->stack_top.assign(stack.begin() + stack_size, stack.end());
|
||||
getBindings(scope, jump->bindings);
|
||||
jumps.push(jump);
|
||||
@@ -313,10 +313,6 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script)
|
||||
}
|
||||
// Simple instruction: binary
|
||||
case I_BINARY: {
|
||||
if (i.instr2 == I_POP) {
|
||||
stack.pop_back();
|
||||
continue;
|
||||
}
|
||||
ScriptValueP b = stack.back(); stack.pop_back();
|
||||
ScriptValueP& a = stack.back();
|
||||
switch (i.instr2) {
|
||||
@@ -356,6 +352,10 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script)
|
||||
stack.push_back(stack.at(stack.size() - i.data - 1));
|
||||
break;
|
||||
}
|
||||
// Pop value off stack
|
||||
case I_POP: {
|
||||
stack.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -534,10 +534,10 @@ void parseExpr(TokenIterator& input, Script& script, Precedence minPrec) {
|
||||
expectToken(input, _("do")); // do
|
||||
if (with_key) {
|
||||
script.addInstruction(I_SET_VAR, key); // set key_name
|
||||
script.addInstruction(I_BINARY, I_POP); // pop
|
||||
script.addInstruction(I_POP); // pop
|
||||
}
|
||||
script.addInstruction(I_SET_VAR, var); // set name
|
||||
script.addInstruction(I_BINARY, I_POP); // pop
|
||||
script.addInstruction(I_POP); // pop
|
||||
parseOper(input, script, PREC_SET, I_BINARY, I_ADD); // EEE; add
|
||||
script.addInstruction(I_JUMP, lblStart); // jump lbl_start
|
||||
script.comeFrom(lblStart); // lbl_end:
|
||||
@@ -650,7 +650,7 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
|
||||
// allow ; at end of expression without errors
|
||||
break;
|
||||
}
|
||||
script.addInstruction(I_BINARY, I_POP); // discard result of first expression
|
||||
script.addInstruction(I_POP); // discard result of first expression
|
||||
parseOper(input, script, PREC_SET);
|
||||
} else if (minPrec <= PREC_SET && token==_(":=")) {
|
||||
// We made a mistake, the part before the := should be a variable name,
|
||||
@@ -761,7 +761,7 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
|
||||
// newline functions as ;
|
||||
// only if we don't match another token!
|
||||
input.putBack();
|
||||
script.addInstruction(I_BINARY, I_POP);
|
||||
script.addInstruction(I_POP);
|
||||
parseOper(input, script, PREC_SET);
|
||||
} else {
|
||||
input.putBack();
|
||||
|
||||
@@ -99,7 +99,11 @@ ScriptValueP Script::dependencies(Context& ctx, const Dependency& dep) const {
|
||||
static const unsigned int INVALID_ADDRESS = 0x03FFFFFF;
|
||||
|
||||
unsigned int Script::addInstruction(InstructionType t) {
|
||||
assert( t == I_JUMP || t == I_JUMP_IF_NOT || t == I_LOOP || t == I_LOOP_WITH_KEY);
|
||||
assert( t == I_JUMP
|
||||
|| t == I_JUMP_IF_NOT
|
||||
|| t == I_LOOP
|
||||
|| t == I_LOOP_WITH_KEY
|
||||
|| t == I_POP);
|
||||
Instruction i = {t, {INVALID_ADDRESS}};
|
||||
instructions.push_back(i);
|
||||
return getLabel() - 1;
|
||||
@@ -179,7 +183,6 @@ String Script::dumpInstr(unsigned int pos, Instruction i) const {
|
||||
break;
|
||||
case I_BINARY: ret += _("binary\t");
|
||||
switch (i.instr2) {
|
||||
case I_POP: ret += _("pop"); break;
|
||||
case I_ITERATOR_R: ret += _("iterator_r"); break;
|
||||
case I_MEMBER: ret += _("member"); break;
|
||||
case I_ADD: ret += _("+"); break;
|
||||
@@ -210,6 +213,8 @@ String Script::dumpInstr(unsigned int pos, Instruction i) const {
|
||||
}
|
||||
break;
|
||||
case I_DUP: ret += _("dup"); break;
|
||||
case I_POP: ret += _("pop"); break;
|
||||
case I_TAILCALL: ret += _("tailcall"); break;
|
||||
}
|
||||
// arg
|
||||
switch (i.instr) {
|
||||
|
||||
@@ -43,6 +43,8 @@ enum InstructionType
|
||||
, I_TERNARY = 14 ///< arg = 3ary instr : pop 3 values, apply a function, push the result
|
||||
, I_QUATERNARY = 15 ///< arg = 4ary instr : pop 4 values, apply a function, push the result
|
||||
, I_DUP = 16 ///< arg = int : duplicate the k-from-top element of the stack
|
||||
, I_POP = 17 ///< arg = * : pop the top value off the stack.
|
||||
, I_TAILCALL = 18 ///< arg = int, n*var : perform a tail call - like I_CALL, except faster
|
||||
};
|
||||
|
||||
/// Types of unary instructions (taking one argument from the stack)
|
||||
@@ -54,8 +56,7 @@ enum UnaryInstructionType
|
||||
|
||||
/// Types of binary instructions (taking two arguments from the stack)
|
||||
enum BinaryInstructionType
|
||||
{ I_POP ///< Pop the top value of the stack
|
||||
, I_ITERATOR_R ///< Make an iterator for a range (two integers)
|
||||
{ I_ITERATOR_R ///< Make an iterator for a range (two integers)
|
||||
, I_MEMBER ///< Member of an object
|
||||
// Arithmatic
|
||||
, I_ADD ///< add
|
||||
|
||||
Reference in New Issue
Block a user