Ejemplo n.º 1
0
void ExpEvaluator::dump(const ExpOperation& oper, String& res) const
{
    const char* name = getOperator(oper.opcode());
    if (name) {
	res << name;
	return;
    }
    switch (oper.opcode()) {
	case OpcPush:
	case OpcCopy:
	    if (oper.isInteger())
		res << (int)oper.number();
	    else
		res << "'" << oper << "'";
	    break;
	case OpcField:
	    res << oper.name();
	    break;
	case OpcFunc:
	    res << oper.name() << "(" << (int)oper.number() << ")";
	    break;
	default:
	    res << "[" << oper.opcode() << "]";
	    if (oper.number() && oper.isInteger())
		res << "(" << (int)oper.number() << ")";
    }
}
Ejemplo n.º 2
0
ExpOperation* ExpEvaluator::popOne(ObjList& stack)
{
    ExpOperation* o = 0;
    for (;;) {
	o = static_cast<ExpOperation*>(stack.get());
	if (o || !stack.next())
	    break;
	// non-terminal NULL - remove the list entry
	stack.remove();
    }
    if (o && o->barrier()) {
	XDebug(DebugInfo,"Not popping barrier %u: '%s'='%s'",o->opcode(),o->name().c_str(),o->c_str());
	return 0;
    }
    stack.remove(o,false);
#ifdef DEBUG
#ifdef XDEBUG
    Debug(DebugAll,"popOne: %p%s%s",o,
	(YOBJECT(ExpFunction,o) ? " function" : ""),
	(YOBJECT(ExpWrapper,o) ? " wrapper" : ""));
#else
    Debug(DebugAll,"popOne: %p",o);
#endif
#endif
    return o;
}
Ejemplo n.º 3
0
ExpOperation* ExpEvaluator::popValue(ObjList& stack, GenObject* context) const
{
    ExpOperation* oper = popOne(stack);
    if (!oper || (oper->opcode() != OpcField))
	return oper;
    XDebug(DebugAll,"ExpEvaluator::popValue() field '%s' [%p]",
	oper->name().c_str(),this);
    bool ok = runField(stack,*oper,context);
    TelEngine::destruct(oper);
    return ok ? popOne(stack) : 0;
}
Ejemplo n.º 4
0
void ExpEvaluator::addOpcode(ExpEvaluator::Opcode oper)
{
    DDebug(DebugAll,"addOpcode %u",oper);
    if (oper == OpcAs) {
        // the second operand is used just for the field name
        ExpOperation* o = 0;
        for (ObjList* l = m_opcodes.skipNull(); l; l=l->skipNext())
            o = static_cast<ExpOperation*>(l->get());
        if (o && (o->opcode() == OpcField)) {
            o->m_opcode = OpcPush;
            o->String::operator=(o->name());
        }
    }
    m_opcodes.append(new ExpOperation(oper));
}
Ejemplo n.º 5
0
ExpOperation* ExpEvaluator::addOpcode(ExpEvaluator::Opcode oper, bool barrier)
{
    DDebug(this,DebugAll,"addOpcode %u (%s)",oper,getOperator(oper));
    if (oper == OpcAs) {
	// the second operand is used just for the field name
	ExpOperation* o = 0;
	for (ObjList* l = m_opcodes.skipNull(); l; l=l->skipNext())
	    o = static_cast<ExpOperation*>(l->get());
	if (o && (o->opcode() == OpcField)) {
	    o->m_opcode = OpcPush;
	    o->String::operator=(o->name());
	}
    }
    ExpOperation* op = new ExpOperation(oper,0,ExpOperation::nonInteger(),barrier);
    op->lineNumber(lineNumber());
    m_opcodes.append(op);
    return op;
}
Ejemplo n.º 6
0
bool ExpEvaluator::runOperation(ObjList& stack, const ExpOperation& oper) const
{
    DDebug(DebugAll,"runOperation(%p,%u) %s",&stack,oper.opcode(),getOperator(oper.opcode()));
    switch (oper.opcode()) {
    case OpcPush:
        stack.append(new ExpOperation(oper));
        break;
    case OpcAnd:
    case OpcOr:
    case OpcXor:
    case OpcShl:
    case OpcShr:
    case OpcAdd:
    case OpcSub:
    case OpcMul:
    case OpcDiv:
    case OpcMod:
    case OpcEq:
    case OpcNe:
    case OpcLt:
    case OpcGt:
    case OpcLe:
    case OpcGe:
    {
        ExpOperation* op2 = popOne(stack);
        ExpOperation* op1 = popOne(stack);
        if (!op1 || !op2) {
            TelEngine::destruct(op1);
            TelEngine::destruct(op2);
            return gotError("ExpEvaluator stack underflow");
        }
        switch (oper.opcode()) {
        case OpcDiv:
        case OpcMod:
            if (!op2->number())
                return gotError("Division by zero");
        default:
            break;
        }
        long int val = 0;
        switch (oper.opcode()) {
        case OpcAnd:
            val = op1->number() & op2->number();
            break;
        case OpcOr:
            val = op1->number() | op2->number();
            break;
        case OpcXor:
            val = op1->number() ^ op2->number();
            break;
        case OpcShl:
            val = op1->number() << op2->number();
            break;
        case OpcShr:
            val = op1->number() >> op2->number();
            break;
        case OpcAdd:
            val = op1->number() + op2->number();
            break;
        case OpcSub:
            val = op1->number() - op2->number();
            break;
        case OpcMul:
            val = op1->number() * op2->number();
            break;
        case OpcDiv:
            val = op1->number() / op2->number();
            break;
        case OpcMod:
            val = op1->number() % op2->number();
            break;
        case OpcLt:
            val = (op1->number() < op2->number()) ? 1 : 0;
            break;
        case OpcGt:
            val = (op1->number() > op2->number()) ? 1 : 0;
            break;
        case OpcLe:
            val = (op1->number() <= op2->number()) ? 1 : 0;
            break;
        case OpcGe:
            val = (op1->number() >= op2->number()) ? 1 : 0;
            break;
        case OpcEq:
            val = (*op1 == *op2) ? 1 : 0;
            break;
        case OpcNe:
            val = (*op1 != *op2) ? 1 : 0;
            break;
        default:
            break;
        }
        TelEngine::destruct(op1);
        TelEngine::destruct(op2);
        DDebug(DebugAll,"Numeric result: %lu",val);
        stack.append(new ExpOperation(val));
    }
    break;
    case OpcLAnd:
    case OpcLOr:
    {
        ExpOperation* op2 = popOne(stack);
        ExpOperation* op1 = popOne(stack);
        if (!op1 || !op2) {
            TelEngine::destruct(op1);
            TelEngine::destruct(op2);
            return gotError("ExpEvaluator stack underflow");
        }
        bool val = false;
        switch (oper.opcode()) {
        case OpcLAnd:
            val = op1->number() && op2->number();
            break;
        case OpcLOr:
            val = op1->number() || op2->number();
            break;
        default:
            break;
        }
        TelEngine::destruct(op1);
        TelEngine::destruct(op2);
        DDebug(DebugAll,"Bool result: '%s'",String::boolText(val));
        stack.append(new ExpOperation(val ? 1 : 0));
    }
    break;
    case OpcCat:
    {
        ExpOperation* op2 = popOne(stack);
        ExpOperation* op1 = popOne(stack);
        if (!op1 || !op2) {
            TelEngine::destruct(op1);
            TelEngine::destruct(op2);
            return gotError("ExpEvaluator stack underflow");
        }
        String val = *op1 + *op2;
        TelEngine::destruct(op1);
        TelEngine::destruct(op2);
        DDebug(DebugAll,"String result: '%s'",val.c_str());
        stack.append(new ExpOperation(val));
    }
    break;
    case OpcAs:
    {
        ExpOperation* op2 = popOne(stack);
        ExpOperation* op1 = popOne(stack);
        if (!op1 || !op2) {
            TelEngine::destruct(op1);
            TelEngine::destruct(op2);
            return gotError("ExpEvaluator stack underflow");
        }
        stack.append(new ExpOperation(*op1,*op2));
        TelEngine::destruct(op1);
        TelEngine::destruct(op2);
    }
    break;
    case OpcFunc:
        return runFunction(stack,oper);
    case OpcField:
        return runField(stack,oper);
    default:
        Debug(DebugStub,"Please implement operation %u",oper.opcode());
        return false;
    }
    return true;
}
Ejemplo n.º 7
0
bool ExpEvaluator::trySimplify()
{
    DDebug(DebugInfo,"trySimplify");
    bool done = false;
    for (unsigned int i = 0; i < m_opcodes.length(); i++) {
        ExpOperation* o = static_cast<ExpOperation*>(m_opcodes[i]);
        if (!o)
            continue;
        switch (o->opcode()) {
        case OpcLAnd:
        case OpcLOr:
        case OpcLXor:
        case OpcAnd:
        case OpcOr:
        case OpcXor:
        case OpcShl:
        case OpcShr:
        case OpcAdd:
        case OpcSub:
        case OpcMul:
        case OpcDiv:
        case OpcMod:
        case OpcCat:
        case OpcEq:
        case OpcNe:
        case OpcLt:
        case OpcGt:
        case OpcLe:
        case OpcGe:
            if (i >= 2) {
                ExpOperation* op2 = static_cast<ExpOperation*>(m_opcodes[i-1]);
                ExpOperation* op1 = static_cast<ExpOperation*>(m_opcodes[i-2]);
                if (!op1 || !op2)
                    continue;
                if (o->opcode() == OpcLAnd || o->opcode() == OpcAnd || o->opcode() == OpcMul) {
                    if ((op1->opcode() == OpcPush && !op1->number() && op2->opcode() == OpcField) ||
                            (op2->opcode() == OpcPush && !op2->number() && op1->opcode() == OpcField)) {
                        (m_opcodes+i)->set(new ExpOperation(0));
                        m_opcodes.remove(op1);
                        m_opcodes.remove(op2);
                        i -= 2;
                        done = true;
                        continue;
                    }
                }
                if (o->opcode() == OpcLOr) {
                    if ((op1->opcode() == OpcPush && op1->number() && op2->opcode() == OpcField) ||
                            (op2->opcode() == OpcPush && op2->number() && op1->opcode() == OpcField)) {
                        (m_opcodes+i)->set(new ExpOperation(1));
                        m_opcodes.remove(op1);
                        m_opcodes.remove(op2);
                        i -= 2;
                        done = true;
                        continue;
                    }
                }
                if ((op1->opcode() == OpcPush) && (op2->opcode() == OpcPush)) {
                    ObjList stack;
                    stack.append(new ExpOperation(*op1));
                    stack.append(new ExpOperation(*op2));
                    if (runOperation(stack,*o)) {
                        // replace operators and operation with computed constant
                        (m_opcodes+i)->set(popOne(stack));
                        m_opcodes.remove(op1);
                        m_opcodes.remove(op2);
                        i -= 2;
                        done = true;
                    }
                }
            }
        default:
            break;
        }
    }
    return done;
}
Ejemplo n.º 8
0
bool ExpEvaluator::runOperation(ObjList& stack, const ExpOperation& oper, GenObject* context) const
{
    DDebug(this,DebugAll,"runOperation(%p,%u,%p) %s",&stack,oper.opcode(),context,getOperator(oper.opcode()));
    XDebug(this,DebugAll,"stack: %s",dump(stack).c_str());
    bool boolRes = true;
    switch (oper.opcode()) {
	case OpcPush:
	case OpcField:
	    pushOne(stack,oper.clone());
	    break;
	case OpcCopy:
	    {
		Mutex* mtx = 0;
		ScriptRun* runner = YOBJECT(ScriptRun,&oper);
		if (runner) {
		    if (runner->context())
			mtx = runner->context()->mutex();
		    if (!mtx)
			mtx = runner;
		}
		pushOne(stack,oper.copy(mtx));
	    }
	    break;
	case OpcNone:
	case OpcLabel:
	    break;
	case OpcDrop:
	    TelEngine::destruct(popOne(stack));
	    break;
	case OpcDup:
	    {
		ExpOperation* op = popValue(stack,context);
		if (!op)
		    return gotError("ExpEvaluator stack underflow",oper.lineNumber());
		pushOne(stack,op->clone());
		pushOne(stack,op);
	    }
	    break;
	case OpcAnd:
	case OpcOr:
	case OpcXor:
	case OpcShl:
	case OpcShr:
	case OpcAdd:
	case OpcSub:
	case OpcMul:
	case OpcDiv:
	case OpcMod:
	    boolRes = false;
	    // fall through
	case OpcEq:
	case OpcNe:
	case OpcLt:
	case OpcGt:
	case OpcLe:
	case OpcGe:
	    {
		ExpOperation* op2 = popValue(stack,context);
		ExpOperation* op1 = popValue(stack,context);
		if (!op1 || !op2) {
		    TelEngine::destruct(op1);
		    TelEngine::destruct(op2);
		    return gotError("ExpEvaluator stack underflow",oper.lineNumber());
		}
		switch (oper.opcode()) {
		    case OpcDiv:
		    case OpcMod:
			if (!op2->valInteger())
			    return gotError("Division by zero",oper.lineNumber());
		    case OpcAdd:
			if (op1->isInteger() && op2->isInteger())
			    break;
			// turn addition into concatenation
			{
			    String val = *op1 + *op2;
			    TelEngine::destruct(op1);
			    TelEngine::destruct(op2);
			    DDebug(this,DebugAll,"String result: '%s'",val.c_str());
			    pushOne(stack,new ExpOperation(val));
			    return true;
			}
		    default:
			break;
		}
		long int val = 0;
		switch (oper.opcode()) {
		    case OpcAnd:
			val = op1->valInteger() & op2->valInteger();
			break;
		    case OpcOr:
			val = op1->valInteger() | op2->valInteger();
			break;
		    case OpcXor:
			val = op1->valInteger() ^ op2->valInteger();
			break;
		    case OpcShl:
			val = op1->valInteger() << op2->valInteger();
			break;
		    case OpcShr:
			val = op1->valInteger() >> op2->valInteger();
			break;
		    case OpcAdd:
			val = op1->valInteger() + op2->valInteger();
			break;
		    case OpcSub:
			val = op1->valInteger() - op2->valInteger();
			break;
		    case OpcMul:
			val = op1->valInteger() * op2->valInteger();
			break;
		    case OpcDiv:
			val = op1->valInteger() / op2->valInteger();
			break;
		    case OpcMod:
			val = op1->valInteger() % op2->valInteger();
			break;
		    case OpcLt:
			val = (op1->valInteger() < op2->valInteger()) ? 1 : 0;
			break;
		    case OpcGt:
			val = (op1->valInteger() > op2->valInteger()) ? 1 : 0;
			break;
		    case OpcLe:
			val = (op1->valInteger() <= op2->valInteger()) ? 1 : 0;
			break;
		    case OpcGe:
			val = (op1->valInteger() >= op2->valInteger()) ? 1 : 0;
			break;
		    case OpcEq:
			val = (*op1 == *op2) ? 1 : 0;
			break;
		    case OpcNe:
			val = (*op1 != *op2) ? 1 : 0;
			break;
		    default:
			break;
		}
		TelEngine::destruct(op1);
		TelEngine::destruct(op2);
		if (boolRes) {
		    DDebug(this,DebugAll,"Bool result: '%s'",String::boolText(val != 0));
		    pushOne(stack,new ExpOperation(val != 0));
		}
		else {
		    DDebug(this,DebugAll,"Numeric result: %lu",val);
		    pushOne(stack,new ExpOperation(val));
		}
	    }
	    break;
	case OpcLAnd:
	case OpcLOr:
	    {
		ExpOperation* op2 = popValue(stack,context);
		ExpOperation* op1 = popValue(stack,context);
		if (!op1 || !op2) {
		    TelEngine::destruct(op1);
		    TelEngine::destruct(op2);
		    return gotError("ExpEvaluator stack underflow",oper.lineNumber());
		}
		bool val = false;
		switch (oper.opcode()) {
		    case OpcLAnd:
			val = op1->valBoolean() && op2->valBoolean();
			break;
		    case OpcLOr:
			val = op1->valBoolean() || op2->valBoolean();
			break;
		    default:
			break;
		}
		TelEngine::destruct(op1);
		TelEngine::destruct(op2);
		DDebug(this,DebugAll,"Bool result: '%s'",String::boolText(val));
		pushOne(stack,new ExpOperation(val));
	    }
	    break;
	case OpcCat:
	    {
		ExpOperation* op2 = popValue(stack,context);
		ExpOperation* op1 = popValue(stack,context);
		if (!op1 || !op2) {
		    TelEngine::destruct(op1);
		    TelEngine::destruct(op2);
		    return gotError("ExpEvaluator stack underflow",oper.lineNumber());
		}
		String val = *op1 + *op2;
		TelEngine::destruct(op1);
		TelEngine::destruct(op2);
		DDebug(this,DebugAll,"String result: '%s'",val.c_str());
		pushOne(stack,new ExpOperation(val));
	    }
	    break;
	case OpcAs:
	    {
		ExpOperation* op2 = popOne(stack);
		ExpOperation* op1 = popOne(stack);
		if (!op1 || !op2) {
		    TelEngine::destruct(op1);
		    TelEngine::destruct(op2);
		    return gotError("ExpEvaluator stack underflow",oper.lineNumber());
		}
		pushOne(stack,op1->clone(*op2));
		TelEngine::destruct(op1);
		TelEngine::destruct(op2);
	    }
	    break;
	case OpcNeg:
	case OpcNot:
	case OpcLNot:
	    {
		ExpOperation* op = popValue(stack,context);
		if (!op)
		    return gotError("ExpEvaluator stack underflow",oper.lineNumber());
		switch (oper.opcode()) {
		    case OpcNeg:
			pushOne(stack,new ExpOperation(-op->valInteger()));
			break;
		    case OpcNot:
			pushOne(stack,new ExpOperation(~op->valInteger()));
			break;
		    case OpcLNot:
			pushOne(stack,new ExpOperation(!op->valBoolean()));
			break;
		    default:
			pushOne(stack,new ExpOperation(op->valInteger()));
			break;
		}
		TelEngine::destruct(op);
	    }
	    break;
	case OpcFunc:
	    return runFunction(stack,oper,context) ||
		gotError("Function '" + oper.name() + "' call failed",oper.lineNumber());
	case OpcIncPre:
	case OpcDecPre:
	case OpcIncPost:
	case OpcDecPost:
	    {
		ExpOperation* fld = popOne(stack);
		if (!fld)
		    return gotError("ExpEvaluator stack underflow",oper.lineNumber());
		if (fld->opcode() != OpcField) {
		    TelEngine::destruct(fld);
		    return gotError("Expecting LValue in operator",oper.lineNumber());
		}
		ExpOperation* val = 0;
		if (!(runField(stack,*fld,context) && (val = popOne(stack)))) {
		    TelEngine::destruct(fld);
		    return false;
		}
		long int num = val->valInteger();
		switch (oper.opcode()) {
		    case OpcIncPre:
			num++;
			(*val) = num;
			break;
		    case OpcDecPre:
			num--;
			(*val) = num;
			break;
		    case OpcIncPost:
			(*val) = num;
			num++;
			break;
		    case OpcDecPost:
			(*val) = num;
			num--;
			break;
		    default:
			break;
		}
		(*fld) = num;
		bool ok = runAssign(stack,*fld,context);
		TelEngine::destruct(fld);
		if (!ok) {
		    TelEngine::destruct(val);
		    return gotError("Assignment failed",oper.lineNumber());
		}
		pushOne(stack,val);
	    }
	    break;
	case OpcAssign:
	    {
		ExpOperation* val = popValue(stack,context);
		ExpOperation* fld = popOne(stack);
		if (!fld || !val) {
		    TelEngine::destruct(fld);
		    TelEngine::destruct(val);
		    return gotError("ExpEvaluator stack underflow",oper.lineNumber());
		}
		if (fld->opcode() != OpcField) {
		    TelEngine::destruct(fld);
		    TelEngine::destruct(val);
		    return gotError("Expecting LValue in assignment",oper.lineNumber());
		}
		ExpOperation* op = val->clone(fld->name());
		TelEngine::destruct(fld);
		bool ok = runAssign(stack,*op,context);
		TelEngine::destruct(op);
		if (!ok) {
		    TelEngine::destruct(val);
		    return gotError("Assignment failed",oper.lineNumber());
		}
		pushOne(stack,val);
	    }
	    break;
	default:
	    if (oper.opcode() & OpcAssign) {
		// assignment by operation
		ExpOperation* val = popValue(stack,context);
		ExpOperation* fld = popOne(stack);
		if (!fld || !val) {
		    TelEngine::destruct(fld);
		    TelEngine::destruct(val);
		    return gotError("ExpEvaluator stack underflow",oper.lineNumber());
		}
		if (fld->opcode() != OpcField) {
		    TelEngine::destruct(fld);
		    TelEngine::destruct(val);
		    return gotError("Expecting LValue in assignment",oper.lineNumber());
		}
		pushOne(stack,fld->clone());
		pushOne(stack,fld);
		pushOne(stack,val);
		ExpOperation op((Opcode)(oper.opcode() & ~OpcAssign),
		    oper.name(),oper.number(),oper.barrier());
		if (!runOperation(stack,op,context))
		    return false;
		static const ExpOperation assign(OpcAssign);
		return runOperation(stack,assign,context);
	    }
	    Debug(this,DebugStub,"Please implement operation %u '%s'",
		oper.opcode(),getOperator(oper.opcode()));
	    return false;
    }
    return true;
}
Ejemplo n.º 9
0
bool ExpEvaluator::trySimplify()
{
    DDebug(this,DebugInfo,"trySimplify");
    bool done = false;
    for (unsigned int i = 0; ; i++) {
	ExpOperation* o = static_cast<ExpOperation*>(m_opcodes[i]);
	if (!o) {
	    if (i >= m_opcodes.length())
		break;
	    else
		continue;
	}
	if (o->barrier())
	    continue;
	switch (o->opcode()) {
	    case OpcLAnd:
	    case OpcLOr:
	    case OpcLXor:
	    case OpcAnd:
	    case OpcOr:
	    case OpcXor:
	    case OpcShl:
	    case OpcShr:
	    case OpcAdd:
	    case OpcSub:
	    case OpcMul:
	    case OpcDiv:
	    case OpcMod:
	    case OpcCat:
	    case OpcEq:
	    case OpcNe:
	    case OpcLt:
	    case OpcGt:
	    case OpcLe:
	    case OpcGe:
		if (i >= 2) {
		    ExpOperation* op2 = static_cast<ExpOperation*>(m_opcodes[i-1]);
		    ExpOperation* op1 = static_cast<ExpOperation*>(m_opcodes[i-2]);
		    if (!op1 || !op2)
			continue;
		    if (o->opcode() == OpcLAnd || o->opcode() == OpcAnd || o->opcode() == OpcMul) {
			if ((op1->opcode() == OpcPush && !op1->number() && op2->opcode() == OpcField) ||
			    (op2->opcode() == OpcPush && !op2->number() && op1->opcode() == OpcField)) {
			    ExpOperation* newOp = (o->opcode() == OpcLAnd) ? new ExpOperation(false) : new ExpOperation((long int)0);
			    newOp->lineNumber(o->lineNumber());
			    (m_opcodes+i)->set(newOp);
			    m_opcodes.remove(op1);
			    m_opcodes.remove(op2);
			    i -= 2;
			    done = true;
			    continue;
			}
		    }
		    if (o->opcode() == OpcLOr) {
			if ((op1->opcode() == OpcPush && op1->number() && op2->opcode() == OpcField) ||
			    (op2->opcode() == OpcPush && op2->number() && op1->opcode() == OpcField)) {
			    ExpOperation* newOp = new ExpOperation(true);
			    newOp->lineNumber(o->lineNumber());
			    (m_opcodes+i)->set(newOp);
			    m_opcodes.remove(op1);
			    m_opcodes.remove(op2);
			    i -= 2;
			    done = true;
			    continue;
			}
		    }
		    if ((op1->opcode() == OpcPush) && (op2->opcode() == OpcPush)) {
			ObjList stack;
			pushOne(stack,op1->clone());
			pushOne(stack,op2->clone());
			if (runOperation(stack,*o)) {
			    // replace operators and operation with computed constant
			    ExpOperation* newOp = popOne(stack);
			    newOp->lineNumber(o->lineNumber());
			    (m_opcodes+i)->set(newOp);
			    m_opcodes.remove(op1);
			    m_opcodes.remove(op2);
			    i -= 2;
			    done = true;
			}
		    }
		}
		break;
	    case OpcNeg:
	    case OpcNot:
	    case OpcLNot:
		if (i >= 1) {
		    ExpOperation* op = static_cast<ExpOperation*>(m_opcodes[i-1]);
		    if (!op)
			continue;
		    if (op->opcode() == OpcPush) {
			ObjList stack;
			pushOne(stack,op->clone());
			if (runOperation(stack,*o)) {
			    // replace unary operator and operation with computed constant
			    ExpOperation* newOp = popOne(stack);
			    newOp->lineNumber(o->lineNumber());
			    (m_opcodes+i)->set(newOp);
			    m_opcodes.remove(op);
			    i--;
			    done = true;
			}
		    }
		    else if (op->opcode() == o->opcode() && op->opcode() != OpcLNot) {
			// minus or bit negation applied twice - remove both operators
			m_opcodes.remove(o);
			m_opcodes.remove(op);
			i--;
			done = true;
		    }
		}
		break;
	    default:
		break;
	}
    }
    return done;
}