/* Copyright (C) 2003 by Walter Schreppers Copyright (C) 2004 by Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // This file is originally written by Walter Scheppers, but almost // every aspect of it is slightly changed by Cies Breijs. #include // for usleep(); #include #include #include #include #include #include "executer.h" // this function is used in executer and canvas: #define ROUND2INT(x) ( (x) >= 0 ? (int)( (x) + .5 ) : (int)( (x) - .5 ) ) Executer::Executer(TreeNode* tree) { this->tree = tree; functionTable.clear(); bBreak = false; bReturn = false; } Executer::~Executer() { emit Finished(); } bool Executer::run() { bBreak = false; bReturn = false; bPause = false; bAbort = false; symtable main; symbolTables.push(main); // new symbol table for main block TreeNode::const_iterator i; for (i = tree->begin(); i != tree->end(); ++i) { if (bAbort) return false; kapp->processEvents(); execute(*i); symbolTables.pop(); //free up stack } return true; } void Executer::slowDown(TreeNode* node) { switch (runSpeed) { case 1: // slow startWaiting(0); break; case 2: // slower startWaiting(250); break; case 3: // slowest startWaiting(900); break; default: kdDebug(0)<<"Executer: Wrong execution speed given"<getToken(); emit setSelection(tok.start.row, tok.start.col, tok.end.row, tok.end.col); } void Executer::slotChangeSpeed(int speed) { runSpeed = speed; } void Executer::pause() { // The next line is within all loops of the Executer // if (bAbort) return; // mostly before // kapp->processEvents(); // this to keep the GUI of KTurtle accessible while executing the logo code // so the Abort button can be clicked, and will function bPause = true; } void Executer::abort() { // The next line is within all loops of the Executer // if(bAbort) return; // mostly before // kapp->processEvents(); // this to keep the GUI of KTurtle accessible while executing the logo code // so the Abort button can be clicked, and will function bAbort = true; } void Executer::execute(TreeNode* node) { switch ( node->getType() ) { case blockNode : execBlock(node); break; case forNode : execFor(node); break; case forEachNode : execForEach(node); break; case whileNode : execWhile(node); break; case ifNode : execIf(node); break; case assignNode : execAssign(node); break; case expressionNode : execExpression(/*node*/); break; case idNode : execId(node); break; case constantNode : execConstant(/*node*/); break; // does nothing value allready set case addNode : execAdd(node); break; case mulNode : execMul(node); break; case divNode : execDiv(node); break; case subNode : execSub(node); break; case minusNode : execMinus(node); break; case nodeGE : execGE(node); break; case nodeGT : execGT(node); break; case nodeLE : execLE(node); break; case nodeLT : execLT(node); break; case nodeNE : execNE(node); break; case nodeEQ : execEQ(node); break; case andNode : execAnd(node); break; case orNode : execOr(node); break; case notNode : execNot(node); break; case functionNode : createFunction(node); break; case functionCallNode : execFunction(node); break; case funcReturnNode : execRetFunction(node); break; case returnNode : execReturn(node); break; case breakNode : execBreak(/*node*/); break; case runNode : execRun(node); break; case ClearNode : execClear(node); break; case GoNode : execGo(node); break; case GoXNode : execGoX(node); break; case GoYNode : execGoY(node); break; case ForwardNode : execForward(node); break; case BackwardNode : execBackward(node); break; case DirectionNode : execDirection(node); break; case TurnLeftNode : execTurnLeft(node); break; case TurnRightNode : execTurnRight(node); break; case CenterNode : execCenter(node); break; case SetPenWidthNode : execSetPenWidth(node); break; case PenUpNode : execPenUp(node); break; case PenDownNode : execPenDown(node); break; case SetFgColorNode : execSetFgColor(node); break; case SetBgColorNode : execSetBgColor(node); break; case ResizeCanvasNode : execResizeCanvas(node); break; case SpriteShowNode : execSpriteShow(node); break; case SpriteHideNode : execSpriteHide(node); break; case SpritePressNode : execSpritePress(node); break; case SpriteChangeNode : execSpriteChange(node); break; case MessageNode : execMessage(node); break; case InputWindowNode : execInputWindow(node); break; case printNode : execPrint(node); break; case FontTypeNode : execFontType(node); break; case FontSizeNode : execFontSize(node); break; case RepeatNode : execRepeat(node); break; case RandomNode : execRandom(node); break; case WaitNode : execWait(node); break; case WrapOnNode : execWrapOn(node); break; case WrapOffNode : execWrapOff(node); break; case ResetNode : execReset(node); break; case EndOfFileNode : break; // just do nothing is enough case Unknown : // dont break but fallthrough to default default: kdDebug(0)<<"Found unsupported node named '"<getLook()<<"' in the tree @ ("<getRow()<<", "<getCol()<<")"<getLook(); functionTable[funcname] = node; //store for later use } //execute a function void Executer::execFunction(TreeNode* node) { TQString funcname = node->getLook(); // locate function node functable::iterator p = functionTable.find(funcname); if ( p == functionTable.end() ) { emit ErrorMsg(node->getToken(), i18n("Call to undefined function: %1.").tqarg(funcname), 5010); return; } TreeNode* funcnode = p->second; TreeNode* funcIds = funcnode->firstChild(); TreeNode* callparams = node->firstChild(); // check if number of parameters match if ( callparams->size() != funcIds->size() ) { emit ErrorMsg(node->getToken(), i18n("Call to function '%1' with wrong number of parameters.").tqarg(funcname), 5020); return; } // pass parameters to function // by adding them to it's symboltable and setting the values TreeNode::iterator pfrom, pto = funcIds->begin(); symtable funcSymTable; for (pfrom = callparams->begin(); pfrom != callparams->end(); ++pfrom ) { if (bAbort) return; if (bPause) startPausing(); kapp->processEvents(); // execute the parameters which can be expressions execute(*pfrom); TQString idname = (*pto)->getLook(); funcSymTable[idname] = (*pfrom)->getValue(); ++pto; } symbolTables.push(funcSymTable); // use new symboltable for current function // execute function statement block bReturn = false; // set to true when return is called execute( funcnode->secondChild() ); bReturn = false; // function execution done symbolTables.pop(); // release function symboltable } // execute a function and expect and get return // value from stack // first child = function name // second child = parameters void Executer::execRetFunction(TreeNode* node) { execFunction(node); if (runStack.size() == 0) { emit ErrorMsg(node->getToken(), i18n("Function %1 did not return a value.").tqarg( node->getLook() ), 5030); return; } node->setValue( runStack.top() ); // set return val runStack.pop(); // remove from stack } void Executer::execReturn(TreeNode* node) { execute( node->firstChild() ); // execute return expression runStack.push( node->firstChild()->getValue() ); bReturn = true; // notify blocks of return } void Executer::execBreak(/*TreeNode* node*/) { bBreak = true; // stops loop block execution } void Executer::execBlock(TreeNode* node) { // execute all statements in block TreeNode::iterator i; for (i = node->begin(); i != node->end(); ++i) { if (runSpeed != 0) slowDown(*i); if (bAbort) return; if (bPause) startPausing(); kapp->processEvents(); execute(*i); if (bReturn || bBreak) break; //jump out of block } } void Executer::execForEach(TreeNode* node) { // sorry, not fully implemented/tested yet TreeNode* expr1 = node->firstChild(); TreeNode* expr2 = node->secondChild(); TreeNode* statements = node->thirdChild(); execute(expr1); execute(expr2); TQString expStr1 = expr1->getValue().String(); TQString expStr2 = expr2->getValue().String(); bBreak = false; int i = expStr2.tqcontains(expStr1, false); for ( ; i > 0; i-- ) { if (bAbort) return; if (bPause) startPausing(); kapp->processEvents(); execute(statements); if (bBreak || bReturn) break; //jump out loop } bBreak = false; } void Executer::execFor(TreeNode* node) { TreeNode* id = node->firstChild(); TreeNode* startNode = node->secondChild(); TreeNode* stopNode = node->thirdChild(); TreeNode* statements = node->fourthChild(); TQString name = id->getLook(); execute(startNode); //assign startval to id Value startVal = startNode->getValue(); ( symbolTables.top() )[ name ] = startVal; execute(stopNode); Value stopVal = stopNode->getValue(); if(node->size() == 4 ) //for loop without step part { bBreak = false; for (double d = startVal.Number(); d <= stopVal.Number(); d = d + 1) { if (bAbort) return; if (bPause) startPausing(); kapp->processEvents(); ( symbolTables.top() )[name] = d; execute( statements ); if (bBreak || bReturn) break; //jump out loop } bBreak = false; } else //for loop with step part { TreeNode* step = node->fourthChild(); statements = node->fifthChild(); execute(step); Value stepVal = step->getValue(); bBreak = false; if ( (stepVal.Number() >= 0.0) && (startVal.Number() <= stopVal.Number() ) ) { for ( double d = startVal.Number(); d <= stopVal.Number(); d = d + stepVal.Number() ) { if (bAbort) return; if (bPause) startPausing(); kapp->processEvents(); (symbolTables.top() )[name] = d; execute( statements ); if (bBreak || bReturn) break; //jump out loop } } else if ( (stepVal.Number() < 0.0) && (startVal.Number() >= stopVal.Number() ) ) { for (double d = startVal.Number(); d >= stopVal.Number(); d = d + stepVal.Number() ) { if (bAbort) return; if (bPause) startPausing(); kapp->processEvents(); ( symbolTables.top() )[name] = d; execute(statements); if (bBreak || bReturn) break; //jump out loop } } bBreak = false; } } void Executer::execRepeat(TreeNode* node) { TreeNode* value = node->firstChild(); TreeNode* statements = node->secondChild(); bBreak = false; execute(value); for ( int i = ROUND2INT( value->getValue().Number() ); i > 0; i-- ) { if (bAbort) return; if (bPause) startPausing(); kapp->processEvents(); execute(statements); if (bBreak || bReturn) break; //jump out loop } bBreak = false; } void Executer::execWhile(TreeNode* node) { TreeNode* condition = node->firstChild(); TreeNode* statements = node->secondChild(); bBreak = false; execute(condition); while (condition->getValue().Number() != 0) { if (bAbort) return; if (bPause) startPausing(); kapp->processEvents(); execute(statements); if (bBreak || bReturn) break; //jump out loop execute(condition); } bBreak = false; } void Executer::execIf(TreeNode* node) { TreeNode* condition = node->firstChild(); TreeNode* ifblok = node->secondChild(); //determine if there is an else part if (node->size() == 2) // no else { execute( condition ); if( condition->getValue().Number() != 0 ) execute(ifblok); } else // else part given { TreeNode* elseblok = node->thirdChild(); execute( condition ); if( condition->getValue().Number() != 0 ) execute(ifblok); else execute( elseblok ); } } void Executer::execAssign(TreeNode* node) { TreeNode* expr = node->firstChild(); execute(expr); ( symbolTables.top() )[ node->getLook() ] = expr->getValue(); } void Executer::execExpression(/*TreeNode* node*/) { // execExpression is not implemented, because it should not be needed! } void Executer::execId(TreeNode* node) { node->setValue( ( symbolTables.top() )[ node->getLook() ] ); } void Executer::execConstant(/*TreeNode* node*/) { // do nothing, value is already set } Value Executer::exec2getValue(TreeNode* node) { execute(node); return node->getValue(); } void Executer::execAdd(TreeNode* node) { Value left( exec2getValue( node->firstChild() ) ); Value right( exec2getValue( node->secondChild() ) ); if (left.Type() == numberValue && right.Type() == numberValue) node->setValue( left + right ); else node->setValue( left.String().append( right.String() ) ); } void Executer::execMul(TreeNode* node) { Value left( exec2getValue( node->firstChild() ) ); Value right( exec2getValue( node->secondChild() ) ); if (left.Type() == numberValue && right.Type() == numberValue) node->setValue( left * right ); else emit ErrorMsg(node->getToken(), i18n("Can only multiply numbers."), 9000); } void Executer::execDiv(TreeNode* node) { Value left( exec2getValue( node->firstChild() ) ); Value right( exec2getValue( node->secondChild() ) ); if (left.Type() == numberValue && right.Type() == numberValue) { if (right.Number() == 0) emit ErrorMsg(node->getToken(), i18n("Cannot divide by zero."), 9000); else node->setValue( left / right ); } else emit ErrorMsg(node->getToken(), i18n("Can only divide numbers."), 9000); } void Executer::execSub(TreeNode* node) { Value left( exec2getValue( node->firstChild() ) ); Value right( exec2getValue( node->secondChild() ) ); if (left.Type() == numberValue && right.Type() == numberValue) node->setValue( left - right ); else emit ErrorMsg(node->getToken(), i18n("Can only subtract numbers."), 9000); } void Executer::execLT(TreeNode* node) { Value left( exec2getValue( node->firstChild() ) ); Value right( exec2getValue( node->secondChild() ) ); node->setValue( left < right ); } void Executer::execLE(TreeNode* node) { Value left( exec2getValue( node->firstChild() ) ); Value right( exec2getValue( node->secondChild() ) ); node->setValue( left <= right ); } void Executer::execGT(TreeNode* node) { Value left( exec2getValue( node->firstChild() ) ); Value right( exec2getValue( node->secondChild() ) ); node->setValue( left > right ); } void Executer::execGE(TreeNode* node) { Value left( exec2getValue( node->firstChild() ) ); Value right( exec2getValue( node->secondChild() ) ); node->setValue( left >= right ); } void Executer::execEQ(TreeNode* node) { Value left( exec2getValue( node->firstChild() ) ); Value right( exec2getValue( node->secondChild() ) ); node->setValue( left == right ); } void Executer::execNE(TreeNode* node) { Value left( exec2getValue( node->firstChild() ) ); Value right( exec2getValue( node->secondChild() ) ); node->setValue( left != right ); } void Executer::execAnd(TreeNode* node) { bool nl = exec2getValue( node->firstChild() ).Number() != 0; bool nr = exec2getValue( node->secondChild() ).Number() != 0; node->setValue( (double) (nl && nr) ); } void Executer::execOr(TreeNode* node) { bool nl = exec2getValue( node->firstChild() ).Number() != 0; bool nr = exec2getValue( node->secondChild() ).Number() != 0; node->setValue(nl || nr); } void Executer::execNot(TreeNode* node) { node->setValue( exec2getValue( node->firstChild() ).Number() == 0 ); } void Executer::execMinus(TreeNode* node) { node->setValue( -exec2getValue( node->firstChild() ).Number() ); } TQString Executer::runCommand(const TQString& command) { FILE *pstream; if ( ( pstream = popen( command.ascii(), "r" ) ) == NULL ) return (""); TQString Line; char buf[100]; while( fgets(buf, sizeof(buf), pstream) !=NULL) { if (bAbort) return (""); kapp->processEvents(); Line += buf; } pclose(pstream); return Line; } void Executer::execRun(TreeNode* node) { TQString cmd = exec2getValue( node->firstChild() ).String(); node->setValue( runCommand(cmd) ); } void Executer::execClear(TreeNode* node) { if ( checkParameterQuantity(node, 0, 5060) ) emit Clear(); } void Executer::execCenter(TreeNode* node) { if ( checkParameterQuantity(node, 0, 5060) ) emit Center(); } void Executer::execPenUp(TreeNode* node) { if ( checkParameterQuantity(node, 0, 5060) ) emit PenUp(); } void Executer::execPenDown(TreeNode* node) { if ( checkParameterQuantity(node, 0, 5060) ) emit PenDown(); } void Executer::execSpriteShow(TreeNode* node) { if ( checkParameterQuantity(node, 0, 5060) ) emit SpriteShow(); } void Executer::execSpriteHide(TreeNode* node) { if ( checkParameterQuantity(node, 0, 5060) ) emit SpriteHide(); } void Executer::execSpritePress(TreeNode* node) { if ( checkParameterQuantity(node, 0, 5060) ) emit SpritePress(); } void Executer::execWrapOn(TreeNode* node) { if ( checkParameterQuantity(node, 0, 5060) ) emit WrapOn(); } void Executer::execWrapOff(TreeNode* node) { if ( checkParameterQuantity(node, 0, 5060) ) emit WrapOff(); } void Executer::execReset(TreeNode* node) { if ( checkParameterQuantity(node, 0, 5060) ) emit Reset(); } void Executer::execMessage(TreeNode* node) { if ( checkParameterQuantity(node, 1, 5060) && checkParameterType(node, stringValue, 5060) ) emit MessageDialog( node->firstChild()->getValue().String() ); } void Executer::execGoX(TreeNode* node) { if ( !checkParameterQuantity(node, 1, 5060) ) return; TreeNode* param1 = node->firstChild(); execute(param1); if ( checkParameterType(node, numberValue, 5060) ) { emit GoX( param1->getValue().Number() ); } } void Executer::execGoY(TreeNode* node) { if ( !checkParameterQuantity(node, 1, 5060) ) return; TreeNode* param1 = node->firstChild(); execute(param1); if ( checkParameterType(node, numberValue, 5060) ) { emit GoY( param1->getValue().Number() ); } } void Executer::execForward(TreeNode* node) { if ( !checkParameterQuantity(node, 1, 5060) ) return; TreeNode* param1 = node->firstChild(); execute(param1); if ( checkParameterType(node, numberValue, 5060) ) { emit Forward( param1->getValue().Number() ); } } void Executer::execBackward(TreeNode* node) { if ( !checkParameterQuantity(node, 1, 5060) ) return; TreeNode* param1 = node->firstChild(); execute(param1); if ( checkParameterType(node, numberValue, 5060) ) { emit Backward( param1->getValue().Number() ); } } void Executer::execDirection(TreeNode* node) { if ( !checkParameterQuantity(node, 1, 5060) ) return; TreeNode* param1 = node->firstChild(); execute(param1); if ( checkParameterType(node, numberValue, 5060) ) { emit Direction( param1->getValue().Number() ); } } void Executer::execTurnLeft(TreeNode* node) { if ( !checkParameterQuantity(node, 1, 5060) ) return; TreeNode* param1 = node->firstChild(); execute(param1); if ( checkParameterType(node, numberValue, 5060) ) { emit TurnLeft( param1->getValue().Number() ); } } void Executer::execTurnRight(TreeNode* node) { if ( !checkParameterQuantity(node, 1, 5060) ) return; TreeNode* param1 = node->firstChild(); execute(param1); if ( checkParameterType(node, numberValue, 5060) ) { emit TurnRight( param1->getValue().Number() ); } } void Executer::execSetPenWidth(TreeNode* node) { if ( !checkParameterQuantity(node, 1, 5060) ) return; TreeNode* param1 = node->firstChild(); execute(param1); if ( checkParameterType(node, numberValue, 5060) ) { int x = ROUND2INT( param1->getValue().Number() ); // pull the number value & round it to int if (x < 1 || x > 10000) emit ErrorMsg(node->getToken(), i18n("The penwidth cannot be set to something smaller than 1, or bigger than 10000."), 6050); else emit SetPenWidth(x); } } void Executer::execSpriteChange(TreeNode* node) { if ( !checkParameterQuantity(node, 1, 5060) ) return; TreeNode* param1 = node->firstChild(); execute(param1); if ( checkParameterType(node, numberValue, 5060) ) { int x = ROUND2INT( param1->getValue().Number() ); // pull the number value & round it to int emit SpriteChange(x); } } void Executer::execFontSize(TreeNode* node) { if ( !checkParameterQuantity(node, 1, 5060) ) return; TreeNode* param1 = node->firstChild(); execute(param1); if ( checkParameterType(node, numberValue, 5060) ) { int x = ROUND2INT( param1->getValue().Number() ); // pull the number value & round it to int if ( x < 0 || x > 350 ) emit ErrorMsg(node->getToken(), i18n("The parameters of function %1 must be within range: 0 to 350.").tqarg( node->getLook() ), 5065); else emit FontSize(x); } } void Executer::execGo(TreeNode* node) { if ( !checkParameterQuantity(node, 2, 5060) ) return; TreeNode* nodeX = node->firstChild(); // getting TreeNode* nodeY = node->secondChild(); execute(nodeX); // executing execute(nodeY); if ( checkParameterType(node, numberValue, 5060) ) { emit Go( nodeX->getValue().Number(), nodeY->getValue().Number() ); } } void Executer::execResizeCanvas(TreeNode* node) { if ( !checkParameterQuantity(node, 2, 5060) ) return; TreeNode* nodeX = node->firstChild(); // getting TreeNode* nodeY = node->secondChild(); execute(nodeX); // executing execute(nodeY); if ( checkParameterType(node, numberValue, 5060) ) { int x = ROUND2INT( nodeX->getValue().Number() ); // converting & rounding to int int y = ROUND2INT( nodeY->getValue().Number() ); if ( ( x < 1 || y < 1 ) || ( x > 10000 || y > 10000 ) ) emit ErrorMsg(node->getToken(), i18n("The parameters of the %1 command must be numbers in the range: 1 to 10000.").tqarg( node->getLook() ), 7030); else emit ResizeCanvas(x, y); } } void Executer::execRandom(TreeNode* node) { if ( !checkParameterQuantity(node, 2, 5060) ) return; TreeNode* nodeX = node->firstChild(); // getting TreeNode* nodeY = node->secondChild(); execute(nodeX); // executing execute(nodeY); if ( !checkParameterType(node, numberValue, 5060) ) return; double x = nodeX->getValue().Number(); double y = nodeY->getValue().Number(); double r = (double)( KApplication::random() ) / RAND_MAX; node->setValue( r * ( y - x ) + x ); } void Executer::execSetFgColor(TreeNode* node) { if ( !checkParameterQuantity(node, 3, 5060) ) return; TreeNode* nodeR = node->firstChild(); // getting TreeNode* nodeG = node->secondChild(); TreeNode* nodeB = node->thirdChild(); execute(nodeR); // executing execute(nodeG); execute(nodeB); if ( checkParameterType(node, numberValue, 5060) ) { int r = ROUND2INT( nodeR->getValue().Number() ); // converting & rounding to int int g = ROUND2INT( nodeG->getValue().Number() ); int b = ROUND2INT( nodeB->getValue().Number() ); if ( ( r < 0 || g < 0 || b < 0 ) || ( r > 255 || g > 255 || b > 255 ) ) emit ErrorMsg(node->getToken(), i18n("The parameters of the %1 command must be numbers in the range: 0 to 255.").tqarg( node->getLook() ), 6090); else emit SetFgColor(r, g, b); } } void Executer::execSetBgColor(TreeNode* node) { if ( !checkParameterQuantity(node, 3, 5060) ) return; TreeNode* nodeR = node->firstChild(); // getting TreeNode* nodeG = node->secondChild(); TreeNode* nodeB = node->thirdChild(); execute(nodeR); // executing execute(nodeG); execute(nodeB); if ( checkParameterType(node, numberValue, 5060) ) { int r = ROUND2INT( nodeR->getValue().Number() ); // converting & rounding to int int g = ROUND2INT( nodeG->getValue().Number() ); int b = ROUND2INT( nodeB->getValue().Number() ); if ( ( r < 0 || g < 0 || b < 0 ) || ( r > 255 || g > 255 || b > 255 ) ) emit ErrorMsg(node->getToken(), i18n("The parameters of the %1 command must be numbers in the range: 0 to 255.").tqarg( node->getLook() ), 6090); else emit SetBgColor(r, g, b); } } void Executer::execInputWindow(TreeNode* node) { if ( !checkParameterQuantity(node, 1, 5060) ) return; TQString value = node->firstChild()->getValue().String(); emit InputDialog(value); node->setType(constantNode); if ( value.isEmpty() ) node->getValue().resetValue(); // set value back to empty else { bool ok = true; double num = value.toDouble(&ok); // to see if the value from the InpDialog is a float if (ok) node->setValue(num); else node->setValue(value); } } void Executer::execPrint(TreeNode* node) { if (node->size() == 0) { emit ErrorMsg(node->getToken(), i18n("The print command needs input"), 5050); return; } TreeNode::iterator i; TQString str = ""; for (i = node->begin(); i != node->end(); ++i) { execute(*i); // execute expression str = str + (*i)->getValue().String(); } emit Print(str); } void Executer::execFontType(TreeNode* node) { // if not 2 params go staight to the checkParam, diplay the error, and return to prevent a crash if ( !checkParameterQuantity(node, 2, 5060) && !checkParameterType(node, stringValue, 5060) ) return; TQString extra; if (node->size() == 2) TQString extra = node->secondChild()->getValue().String(); TQString family = node->firstChild()->getValue().String(); emit FontType(family, extra); } void Executer::execWait(TreeNode* node) { if ( !checkParameterQuantity(node, 1, 5060) ) return; TreeNode* param1 = node->firstChild(); execute(param1); if ( !checkParameterType(node, numberValue, 5060) ) return; int msec = (int)( 1000 * param1->getValue().Number() ); startWaiting(msec); } void Executer::startWaiting(int msec) { bStopWaiting = false; // call a timer that sets stopWaiting to true when it runs TQTimer::singleShot( msec, this, TQT_SLOT( slotStopWaiting() ) ); while (bStopWaiting == false) { if (bAbort) return; // waits need to be interrupted by the stop action if (bPause) startPausing(); kapp->processEvents(); // only 10 times per second is enough... else the CPU gets 100% loaded ( not nice :) usleep(100000); } } void Executer::slotStopWaiting() { bStopWaiting = true; } void Executer::startPausing() { while (bPause == true) { if (bAbort) return; // waits need to be interrupted by the stop action kapp->processEvents(); // only 10 times per second is enough... else the CPU gets 100% loaded ( not nice :) usleep(100000); } } void Executer::slotStopPausing() { bPause = false; } bool Executer::checkParameterQuantity(TreeNode* node, uint quantity, int errorCode) { if (quantity == 0) { if (node->size() == 0) return true; // thats easy! emit ErrorMsg(node->getToken(), i18n("The %1 command accepts no parameters.").tqarg( node->getLook() ), errorCode); return false; } uint nodeSize = node->size(); if (nodeSize != 0) // when all parameters are forgotten the parser puts a Unknown/tokEOL param, catch this: if (node->firstChild()->getToken().type == tokEOL) nodeSize = 0; if (nodeSize != quantity) { if (nodeSize < quantity) { emit ErrorMsg(node->getToken(), i18n("The %1 command was called with %2 but needs 1 parameter.", "The %1 command was called with %2 but needs %n parameters.", quantity).tqarg( node->getLook() ).tqarg(nodeSize), errorCode); } else { emit ErrorMsg(node->getToken(), i18n("The %1 command was called with %2 but only accepts 1 parameter.", "The %1 command was called with %2 but only accepts %n parameters.", quantity).tqarg( node->getLook() ).tqarg(nodeSize), errorCode); } return false; } return true; // if all tests passed } bool Executer::checkParameterType(TreeNode* node, int valueType, int errorCode) { uint quantity = node->size(); uint ii = 1; TreeNode::iterator i = node->begin(); while ( i != node->end() && ii <= quantity ) { if ( (*i)->getValue().Type() != valueType ) { switch (valueType) { case stringValue: if (quantity == 1) emit ErrorMsg(node->getToken(), i18n("The %1 command only accepts a string as its parameter.").tqarg( node->getLook() ), errorCode); else emit ErrorMsg(node->getToken(), i18n("The %1 command only accepts strings as its parameters.").tqarg( node->getLook() ), errorCode); break; case numberValue: if (quantity == 1) emit ErrorMsg(node->getToken(), i18n("The %1 command only accepts a number as its parameter.").tqarg( node->getLook() ), errorCode); else emit ErrorMsg(node->getToken(), i18n("The %1 command only accepts numbers as its parameters.").tqarg( node->getLook() ), errorCode); break; } return false; } ++i; ii++; } return true; // if all tests passed } #include "executer.moc"