Exemple #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() << ")";
    }
}
Exemple #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;
}
Exemple #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;
}
Exemple #4
0
ExpOperation* ExpEvaluator::popAny(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();
    }
    stack.remove(o,false);
#ifdef DEBUG
#ifdef XDEBUG
    Debug(DebugAll,"popAny: %p%s%s '%s'",o,
	(YOBJECT(ExpFunction,o) ? " function" : ""),
	(YOBJECT(ExpWrapper,o) ? " wrapper" : ""),
	(o ? o->name().safe() : (const char*)0));
#else
    Debug(DebugAll,"popAny: %p '%s'",o,(o ? o->name().safe() : (const char*)0));
#endif
#endif
    return o;
}
Exemple #5
0
bool ExpEvaluator::runFunction(ObjList& stack, const ExpOperation& oper) const
{
    DDebug(DebugAll,"runFunction(%p,'%s' %ld) ext=%p",
           &stack,oper.name().c_str(),oper.number(),(void*)m_extender);
    if (oper.name() == YSTRING("chr")) {
        String res;
        for (long int i = oper.number(); i; i--) {
            ExpOperation* o = popOne(stack);
            if (!o)
                return gotError("ExpEvaluator stack underflow");
            res = String((char)o->number()) + res;
            TelEngine::destruct(o);
        }
        stack.append(new ExpOperation(res));
        return true;
    }
    if (oper.name() == YSTRING("now")) {
        if (oper.number())
            return gotError("Function expects no arguments");
        stack.append(new ExpOperation(Time::secNow()));
        return true;
    }
    return m_extender && m_extender->runFunction(this,stack,oper);
}
Exemple #6
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));
}
Exemple #7
0
bool ExpEvaluator::runFunction(ObjList& stack, const ExpOperation& oper, GenObject* context) const
{
    DDebug(this,DebugAll,"runFunction(%p,'%s' %ld, %p) ext=%p",
	&stack,oper.name().c_str(),oper.number(),context,(void*)m_extender);
    if (oper.name() == YSTRING("chr")) {
	String res;
	for (long int i = oper.number(); i; i--) {
	    ExpOperation* o = popValue(stack,context);
	    if (!o)
		return gotError("ExpEvaluator stack underflow",oper.lineNumber());
	    res = String((char)o->number()) + res;
	    TelEngine::destruct(o);
	}
	pushOne(stack,new ExpOperation(res));
	return true;
    }
    if (oper.name() == YSTRING("now")) {
	if (oper.number())
	    return gotError("Function expects no arguments",oper.lineNumber());
	pushOne(stack,new ExpOperation((long int)Time::secNow()));
	return true;
    }
    return m_extender && m_extender->runFunction(stack,oper,context);
}
Exemple #8
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;
}
Exemple #9
0
bool ExpEvaluator::runField(ObjList& stack, const ExpOperation& oper) const
{
    DDebug(DebugAll,"runField(%p,'%s') ext=%p",
           &stack,oper.name().c_str(),(void*)m_extender);
    return m_extender && m_extender->runField(this,stack,oper);
}
Exemple #10
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;
}
Exemple #11
0
bool ExpEvaluator::runAssign(ObjList& stack, const ExpOperation& oper, GenObject* context) const
{
    DDebug(this,DebugAll,"runAssign('%s'='%s',%p) ext=%p",
	oper.name().c_str(),oper.c_str(),context,(void*)m_extender);
    return m_extender && m_extender->runAssign(stack,oper,context);
}