diff --git a/src/interpreter/executer.cpp b/src/interpreter/executer.cpp index ee2d45d..c071cf2 100644 --- a/src/interpreter/executer.cpp +++ b/src/interpreter/executer.cpp @@ -1,1102 +1,1102 @@ /* Copyright (C) 2003-2006 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 "executer.h" #include #include #include // for wait #include #include #include #include void Executer::initialize(TreeNode* tree, ErrorList* _errorList) { rootNode = tree; newScope = rootNode; currentNode = rootNode; finished = !currentNode->hasChildren(); // set finished to false unless the tree is empty errorList = _errorList; breaking = false; returning = false; waiting = false; - returnValue = 0; + returnValue = nullptr; executeCurrent = false; functionTable.clear(); globalVariableTable.clear(); while (!functionStack.isEmpty()) { // In the ForTo loop, we can assign the globalVariableTable to an entry in the functionStack // we shouldn't delete this variableTable, so check for it. VariableTable* variableTable = functionStack.pop().variableTable; if(variableTable!=&globalVariableTable) delete variableTable; } } void Executer::execute() { //Do we have to do anything? if (finished || waiting) return; if(executeCurrent) { // executeCurrent is used to make sure the currentNode will be executed // this way the tree will not be walked before the execution... executeCurrent = false; execute(currentNode); return; } if(returning) { //We are returning from a function call // Handle returning in the top-level (not inside a function) as // gracefully as possible. // See: https://bugs.kde.org/show_bug.cgi?id=300949 if (functionStack.isEmpty()) { addError(i18n("Cannot return outside a function. "), *(currentNode->token()), 0); finished = true; return; } // Take the last called function from the function stack CalledFunction calledFunction = functionStack.pop(); // Delete the local variables of the called function delete calledFunction.variableTable; currentNode = calledFunction.function; - if (returnValue == 0) + if (returnValue == nullptr) currentNode->setNullValue(); // Handle an empty return value else currentNode->setValue(returnValue); execute(currentNode); return; } - if (newScope == 0) { + if (newScope == nullptr) { TreeNode* currentParent = currentNode->parent(); currentNode = currentNode->nextSibling(); - if(currentNode == 0) { //running off sibling list + if(currentNode == nullptr) { //running off sibling list currentNode = currentParent; if(currentNode == rootNode) { finished = true; return; } // printExe(); // debugging thing execute(currentNode); return; } }else{ // We're entering a new scope // skip ahead to frist child (if any) else we will not get into the scope if(newScope->hasChildren()) currentNode = newScope->firstChild(); else currentNode = newScope; - newScope = 0; + newScope = nullptr; } while (currentNode->hasChildren() && currentNode->token()->type() != Token::Scope) currentNode = currentNode->firstChild(); // printExe(); // debugging thing execute(currentNode); } void Executer::execute(TreeNode* node) { if (finished) return; // emit a signal for GUI Token* t = node->token(); // //qDebug() << "emitting token: '" << t->look() << "' - (" << t->startRow() << "," << t->startCol() << " - " << t->endRow() << "," << t->endCol() << ")"; // don't report scopes (their are not really executed) if (t->type() != Token::Scope) emit currentlyExecuting(node); // this method executes one node at the time // if (currentNode->token()->type() != Token::Scope) //qDebug() << "1234567890!!!!!"; switch (node->token()->type()) { //BEGIN GENERATED executer_switch_cpp CODE /* The code between the line that start with "//BEGIN GENERATED" and "//END GENERATED" * is generated by "generate.rb" according to the definitions specified in * "definitions.rb". Please make all changes in the "definitions.rb" file, since all * all change you make here will be overwritten the next time "generate.rb" is run. * Thanks for looking at the code! */ case Token::Root : executeRoot(node); break; case Token::Scope : executeScope(node); break; case Token::Variable : executeVariable(node); break; case Token::FunctionCall : executeFunctionCall(node); break; case Token::String : /* a constant; do nothing */ break; case Token::Number : /* a constant; do nothing */ break; case Token::True : /* a constant; do nothing */ break; case Token::False : /* a constant; do nothing */ break; case Token::Exit : executeExit(node); break; case Token::If : executeIf(node); break; case Token::Else : executeElse(node); break; case Token::Repeat : executeRepeat(node); break; case Token::While : executeWhile(node); break; case Token::For : executeFor(node); break; case Token::ForTo : executeForTo(node); break; case Token::Break : executeBreak(node); break; case Token::Return : executeReturn(node); break; case Token::Wait : executeWait(node); break; case Token::Assert : executeAssert(node); break; case Token::And : executeAnd(node); break; case Token::Or : executeOr(node); break; case Token::Not : executeNot(node); break; case Token::Equals : executeEquals(node); break; case Token::NotEquals : executeNotEquals(node); break; case Token::GreaterThan : executeGreaterThan(node); break; case Token::LessThan : executeLessThan(node); break; case Token::GreaterOrEquals : executeGreaterOrEquals(node); break; case Token::LessOrEquals : executeLessOrEquals(node); break; case Token::Addition : executeAddition(node); break; case Token::Substracton : executeSubstracton(node); break; case Token::Multiplication : executeMultiplication(node); break; case Token::Division : executeDivision(node); break; case Token::Power : executePower(node); break; case Token::Assign : executeAssign(node); break; case Token::Learn : executeLearn(node); break; case Token::ArgumentList : executeArgumentList(node); break; case Token::Reset : executeReset(node); break; case Token::Clear : executeClear(node); break; case Token::Center : executeCenter(node); break; case Token::Go : executeGo(node); break; case Token::GoX : executeGoX(node); break; case Token::GoY : executeGoY(node); break; case Token::Forward : executeForward(node); break; case Token::Backward : executeBackward(node); break; case Token::Direction : executeDirection(node); break; case Token::TurnLeft : executeTurnLeft(node); break; case Token::TurnRight : executeTurnRight(node); break; case Token::PenWidth : executePenWidth(node); break; case Token::PenUp : executePenUp(node); break; case Token::PenDown : executePenDown(node); break; case Token::PenColor : executePenColor(node); break; case Token::CanvasColor : executeCanvasColor(node); break; case Token::CanvasSize : executeCanvasSize(node); break; case Token::SpriteShow : executeSpriteShow(node); break; case Token::SpriteHide : executeSpriteHide(node); break; case Token::Print : executePrint(node); break; case Token::FontSize : executeFontSize(node); break; case Token::Random : executeRandom(node); break; case Token::GetX : executeGetX(node); break; case Token::GetY : executeGetY(node); break; case Token::Message : executeMessage(node); break; case Token::Ask : executeAsk(node); break; case Token::Pi : executePi(node); break; case Token::Tan : executeTan(node); break; case Token::Sin : executeSin(node); break; case Token::Cos : executeCos(node); break; case Token::ArcTan : executeArcTan(node); break; case Token::ArcSin : executeArcSin(node); break; case Token::ArcCos : executeArcCos(node); break; case Token::Sqrt : executeSqrt(node); break; case Token::Round : executeRound(node); break; case Token::GetDirection : executeGetDirection(node); break; case Token::Mod : executeMod(node); break; //END GENERATED executer_switch_cpp CODE default: //qDebug() << "Unrecognizd Token type (" << node->token()->type() << ", " << node->token()->look() << ") -- THIS SHOULDN'T HAPPEN!"; break; } } VariableTable* Executer::currentVariableTable() { if (functionStack.isEmpty()) return &globalVariableTable; else return functionStack.top().variableTable; } bool Executer::checkParameterQuantity(TreeNode* node, uint quantity, int errorCode) { // //qDebug() << "called"; uint nodeSize = node->childCount(); if (quantity == 0) { if (nodeSize == 0) return true; // thats easy! addError(i18n("The %1 command accepts no parameters.", node->token()->look()), *node->token(), errorCode); return false; } // // CHECK THIS OUT LATER // 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) { addError(i18np("The %2 command was called with %3 but needs 1 parameter.", "The %2 command was called with %3 but needs %1 parameters.", quantity, node->token()->look(), nodeSize), *node->token(), errorCode); } else { addError(i18np("The %2 command was called with %3 but only accepts 1 parameter.", "The %2 command was called with %3 but only accepts %1 parameters.", quantity, node->token()->look(), nodeSize), *node->token(), errorCode); } return false; } return true; // if all tests passed } bool Executer::checkParameterType(TreeNode* node, int valueType, int errorCode) { // //qDebug() << "called"; uint quantity = node->childCount(); TreeNode* currentChild = node->firstChild(); - while (currentChild != 0) { + while (currentChild != nullptr) { if (currentChild->value()->type() != valueType) { switch (valueType) { case Value::String: if (quantity == 1) addError(i18n("The %1 command only accepts a string as its parameter.", node->token()->look()), *node->token(), errorCode); else addError(i18n("The %1 command only accepts strings as its parameters.", node->token()->look()), *node->token(), errorCode); break; case Value::Number: if (quantity == 1) addError(i18n("The %1 command only accepts a number as its parameter.", node->token()->look()), *node->token(), errorCode); else addError(i18n("The %1 command only accepts numbers as its parameters.", node->token()->look()), *node->token(), errorCode); break; case Value::Bool: if (quantity == 1) addError(i18n("The %1 command only accepts an answer as its parameter.", node->token()->look()), *node->token(), errorCode); else addError(i18n("The %1 command only accepts answers as its parameters.", node->token()->look()), *node->token(), errorCode); break; } return false; } currentChild = node->nextChild(); } return true; // if all tests passed } void Executer::addError(const QString& s, const Token& t, int code) { // //qDebug() << qPrintable(s) << " (runtime error)"; errorList->addError(s, t, code); } //BEGIN GENERATED executer_cpp CODE /* The code between the line that start with "//BEGIN GENERATED" and "//END GENERATED" * is generated by "generate.rb" according to the definitions specified in * "definitions.rb". Please make all changes in the "definitions.rb" file, since all * all change you make here will be overwritten the next time "generate.rb" is run. * Thanks for looking at the code! */ void Executer::executeRoot(TreeNode* node) { // //qDebug() << "called"; node = node; // stop the warnings // this is a stud } void Executer::executeScope(TreeNode* node) { // //qDebug() << "called"; // catch loops, they need to be managed... int parentTokenType = node->parent()->token()->type(); if (parentTokenType == Token::If || parentTokenType == Token::Repeat || parentTokenType == Token::While || // parentTokenType == Token::ForIn || parentTokenType == Token::ForTo) { currentNode = node->parent(); executeCurrent = true; return; } if(parentTokenType == Token::Learn) { //We have the end of a Learn, so we should return returning = true; - returnValue = 0; + returnValue = nullptr; return; } newScope = node; } void Executer::executeVariable(TreeNode* node) { // //qDebug() << "called"; bool aValueIsNeeded = true; // no need to look up when assigning (in a for loop statement) if ((node->parent()->token()->type() == Token::ForTo) && (node->parent()->child(0)==node)) return; // we need to executeVariables in assignments for things like $x=$y to work if (node->parent()->token()->type() == Token::Assign) { // Test if we are in the LHS of the assignment if (node == node->parent()->child(0)) { // In this case we do not need to be initialized, we will get a value in executeAssign aValueIsNeeded = false; } } if (!functionStack.isEmpty() && functionStack.top().variableTable->contains(node->token()->look())) { // //qDebug() << "exists locally"; node->setValue( (*functionStack.top().variableTable)[node->token()->look()] ); } else if (globalVariableTable.contains(node->token()->look())) { // //qDebug() << "exists globally"; node->setValue(globalVariableTable[node->token()->look()]); } else if (aValueIsNeeded) { addError(i18n("The variable '%1' was used without first being assigned to a value", node->token()->look()), *node->token(), 0); } } void Executer::executeFunctionCall(TreeNode* node) { // //qDebug() << "called"; if (node->parent()->token()->type() == Token::Learn) { // in case we're defining a function currentNode = node->parent(); executeCurrent = true; return; } if (returning) { // if the function is already executed and returns now - returnValue = 0; + returnValue = nullptr; returning = false; // //qDebug() << "==> functionReturned!"; return; } if (!functionTable.contains(node->token()->look())) { addError(i18n("An unknown function named '%1' was called", node->token()->look()), *node->token(), 0); return; } CalledFunction c; c.function = node; c.variableTable = new VariableTable(); functionStack.push(c); // //qDebug() << "==> functionCalled!"; TreeNode* learnNode = functionTable[node->token()->look()]; // if the parameter numbers are not equal... if (node->childCount() != learnNode->child(1)->childCount()) { addError( i18n("The function '%1' was called with %2, while it should be called with %3", node->token()->look(), i18ncp("The function '%1' was called with %2, while it should be called with %3", "1 parameter", "%1 parameters", node->childCount()), i18ncp("The function '%1' was called with %2, while it should be called with %3", "1 parameter", "%1 parameters", learnNode->child(1)->childCount()) ), *node->token(), 0); return; } for (uint i = 0; i < node->childCount(); i++) { functionStack.top().variableTable->insert(learnNode->child(1)->child(i)->token()->look(), node->child(i)->value()); // //qDebug() << "inserted variable " << learnNode->child(1)->child(i)->token()->look() << " on function stack"; } newScope = learnNode->child(2); } void Executer::executeExit(TreeNode* node) { // //qDebug() << "called"; node = node; // stop the warnings finished = true; } void Executer::executeIf(TreeNode* node) { // //qDebug() << "called"; QString id = QString("__%1_%2").arg(node->token()->look()).arg(reinterpret_cast(node)); if (currentVariableTable()->contains(id)) { currentVariableTable()->remove(id); return; } if (node->child(0)->value()->boolean()) { // store a empty Value just to know we executed once currentVariableTable()->insert(id, Value()); newScope = node->child(1); } else { if (node->childCount() >= 3) { currentVariableTable()->insert(id, Value()); newScope = node->child(2); // execute the else part } } } void Executer::executeElse(TreeNode* node) { // //qDebug() << "called"; execute(node->child(0)); // execute the scope, that's all... } void Executer::executeRepeat(TreeNode* node) { // //qDebug() << "called"; QString id = QString("__%1_%2").arg(node->token()->look()).arg(reinterpret_cast(node)); if(breaking) { breaking = false; currentVariableTable()->remove(id); return; } // the iteration state is stored on the variable table if (currentVariableTable()->contains(id)) { int currentCount = static_cast(round((*currentVariableTable())[id].number())); if (currentCount > 0) { (*currentVariableTable())[id].setNumber(currentCount - 1); } else { currentVariableTable()->remove(id); return; } } else { if(static_cast(round(node->child(0)->value()->number()))<=0) // handle 'repeat 0' return; currentVariableTable()->insert(id, Value(round(node->child(0)->value()->number()) - 1.0)); } newScope = node->child(1); } void Executer::executeWhile(TreeNode* node) { // //qDebug() << "called"; // first time this gets called the expression is already executed // after one iteration the expression is not automatically re-executed. // so we do the following on every call to executeWhile: // exec scope, exec expression, exec scope, exec expression, ... QString id = QString("__%1_%2").arg(node->token()->look()).arg(reinterpret_cast(node)); if (breaking) { // We hit a break command while executing the scope breaking = false; // Not breaking anymore currentVariableTable()->remove(id); // remove the value (cleanup) return; // Move to the next sibbling } if (currentVariableTable()->contains(id)) { newScope = node; // re-execute the expression currentVariableTable()->remove(id); return; } currentVariableTable()->insert(id, Value()); // store a empty Value just to know we executed once if (node->child(0)->value()->boolean()) newScope = node->child(1); // (re-)execute the scope else currentVariableTable()->remove(id); // clean-up, keep currenNode on currentNode so the next sibling we be run next } void Executer::executeFor(TreeNode* node) { // //qDebug() << "called"; qCritical("Executer::executeFor(): should have been translated to Token::ForTo by the parser"); node = node; // stop the warnings } void Executer::executeForTo(TreeNode* node) { // //qDebug() << "called"; // first time this gets called the expressions are already executed // after one iteration the expression is not re-executed. // so we do: exec scope, exec expressions, exec scope, exec expressions, ... //TODO: We have the cleanup part twice (after breaking and after the last iteration // perhaps clean it up by putting in in one place? bool firstIteration = false; if (functionStack.isEmpty() || functionStack.top().function != node) { // if this for loop is called for the first time... CalledFunction c; c.function = node; // TODO: Find a better solution then this for nested for loops //c.variableTable = new VariableTable(); c.variableTable = currentVariableTable(); functionStack.push(c); currentVariableTable()->insert(node->child(0)->token()->look(), Value(node->child(1)->value()->number())); firstIteration = true; } QString id = QString("__%1_%2").arg(node->token()->look()).arg(reinterpret_cast(node)); if(breaking) { breaking = false; //delete functionStack.top().variableTable; functionStack.pop(); // if we don't delete the functionStack's varibleTable any more // do remove the for loops id.. currentVariableTable()->remove(id); return; } if (currentVariableTable()->contains(id)) { newScope = node; // re-execute the expressions currentVariableTable()->remove(id); return; } currentVariableTable()->insert(id, Value()); // store a empty Value just to know we executed once double currentCount = (*currentVariableTable())[node->child(0)->token()->look()].number(); double startCondition = node->child(1)->value()->number(); double endCondition = node->child(2)->value()->number(); double step = node->child(3)->value()->number(); if ((startCondition < endCondition && currentCount + step <= endCondition) || (startCondition > endCondition && currentCount + step >= endCondition && step<0) || //negative loop sanity check, is it implemented? (startCondition ==endCondition && firstIteration) ) { // for expressions like for $n=1 to 1 if (!firstIteration) (*currentVariableTable())[node->child(0)->token()->look()].setNumber(currentCount + step); newScope = node->child(4); // (re-)execute the scope } else { // cleaning up after last iteration... //delete functionStack.top().variableTable; functionStack.pop(); // if we don't delete the functionStack's varibleTable any more // do remove the for loops id.. currentVariableTable()->remove(id); } } void Executer::executeBreak(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::Break*100+90)) return; breaking = true; // Check for the first parent which is a repeat, while of for loop. // If found, switch the newScope to them so they can break. QList tokenTypes; tokenTypes.append(Token::Repeat); tokenTypes.append(Token::While); tokenTypes.append(Token::ForTo); TreeNode* ns = getParentOfTokenTypes(node, &tokenTypes); - if(ns!=0) + if(ns!=nullptr) newScope = ns; //else // We could add an error right HERE // At the moment we just ignore a break when we couldn't // find a matching parent } void Executer::executeReturn(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()>0) returnValue = node->child(0)->value(); else - returnValue = 0; + returnValue = nullptr; returning = true; } void Executer::executeWait(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Wait*100+90)) return; if (!checkParameterType(node, Value::Number, 20000+Token::Wait*100+91) ) return; waiting = true; QTimer::singleShot(static_cast(1000*node->child(0)->value()->number()), this, SLOT(stopWaiting())); } void Executer::executeAssert(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Wait*100+90)) return; if (!checkParameterType(node, Value::Bool, 20000+Token::Wait*100+91) ) return; if (!node->child(0)->value()->boolean()) addError(i18n("ASSERT failed"), *node->token(), 0); } void Executer::executeAnd(TreeNode* node) { // //qDebug() << "called"; //Niels: See 'Not' if(node->childCount()!=2) { addError(i18n("'And' needs two variables"), *node->token(), 0); return; } node->value()->setBool(node->child(0)->value()->boolean() && node->child(1)->value()->boolean()); } void Executer::executeOr(TreeNode* node) { // //qDebug() << "called"; //Niels: See 'Not' if(node->childCount()!=2) { addError(i18n("'Or' needs two variables"), *node->token(), 0); return; } node->value()->setBool(node->child(0)->value()->boolean() || node->child(1)->value()->boolean()); } void Executer::executeNot(TreeNode* node) { // //qDebug() << "called"; // OLD-TODO: maybe add some error handling here... //Niels: Ok, now we check if the node has children. Should we also check whether the child value is a boolean? if(node->childCount()!=1) { addError(i18n("I need something to do a not on"), *node->token(), 0); return; } node->value()->setBool(!node->child(0)->value()->boolean()); } void Executer::executeEquals(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("I cannot do a '==' without 2 variables"), *node->token(), 0); return; } node->value()->setBool(*node->child(0)->value() == node->child(1)->value()); } void Executer::executeNotEquals(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("I cannot do a '!=' without 2 variables"), *node->token(), 0); return; } node->value()->setBool(*node->child(0)->value() != node->child(1)->value()); } void Executer::executeGreaterThan(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("I cannot do a '>' without 2 variables"), *node->token(), 0); return; } node->value()->setBool(*node->child(0)->value() > node->child(1)->value()); } void Executer::executeLessThan(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("I cannot do a '<' without 2 variables"), *node->token(), 0); return; } node->value()->setBool(*node->child(0)->value() < node->child(1)->value()); } void Executer::executeGreaterOrEquals(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("I cannot do a '>=' without 2 variables"), *node->token(), 0); return; } node->value()->setBool(*node->child(0)->value() >= node->child(1)->value()); } void Executer::executeLessOrEquals(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("I cannot do a '<=' without 2 variables"), *node->token(), 0); return; } node->value()->setBool(*node->child(0)->value() <= node->child(1)->value()); } void Executer::executeAddition(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("You need two numbers or string to do an addition"), *node->token(), 0); return; } if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { node->value()->setNumber(node->child(0)->value()->number() + node->child(1)->value()->number()); } else { node->value()->setString(node->child(0)->value()->string().append(node->child(1)->value()->string())); } } void Executer::executeSubstracton(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("You need two numbers to subtract"), *node->token(), 0); return; } if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { node->value()->setNumber(node->child(0)->value()->number() - node->child(1)->value()->number()); } else { if (node->child(0)->value()->type() != Value::Number) addError(i18n("You tried to subtract from a non-number, '%1'", node->child(0)->token()->look()), *node->token(), 0); if (node->child(1)->value()->type() != Value::Number) addError(i18n("You tried to subtract a non-number, '%1'", node->child(1)->token()->look()), *node->token(), 0); } } void Executer::executeMultiplication(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("You need two numbers to multiplicate"), *node->token(), 0); return; } if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { node->value()->setNumber(node->child(0)->value()->number() * node->child(1)->value()->number()); } else { if (node->child(0)->value()->type() != Value::Number) addError(i18n("You tried to multiplicate a non-number, '%1'", node->child(0)->token()->look()), *node->token(), 0); if (node->child(1)->value()->type() != Value::Number) addError(i18n("You tried to multiplicate by a non-number, '%1'", node->child(1)->token()->look()), *node->token(), 0); } } void Executer::executeDivision(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("You need two numbers to divide"), *node->token(), 0); return; } if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { if(node->child(1)->value()->number()==0) { addError(i18n("You tried to divide by zero"), *node->token(), 0); return; } node->value()->setNumber(node->child(0)->value()->number() / node->child(1)->value()->number()); } else { if (node->child(0)->value()->type() != Value::Number) addError(i18n("You tried to divide a non-number, '%1'", node->child(0)->token()->look()), *node->token(), 0); if (node->child(1)->value()->type() != Value::Number) addError(i18n("You tried to divide by a non-number, '%1'", node->child(1)->token()->look()), *node->token(), 0); } } void Executer::executePower(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("You need two numbers to raise a power"), *node->token(), 0); return; } if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { node->value()->setNumber(pow(node->child(0)->value()->number(), node->child(1)->value()->number())); double result = pow(node->child(0)->value()->number(), node->child(1)->value()->number()); int error = errno; if(error==ERANGE) { node->value()->setNumber(0); addError(i18n("The result of an exponentiation was too large"), *node->token(), 0); }else{ node->value()->setNumber(result); } } else { if (node->child(0)->value()->type() != Value::Number) addError(i18n("You tried to raise a non-number to a power, '%1'", node->child(0)->token()->look()), *node->token(), 0); if (node->child(1)->value()->type() != Value::Number) addError(i18n("You tried to raise the power of a non-number, '%1'", node->child(1)->token()->look()), *node->token(), 0); } } void Executer::executeAssign(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("You need one variable and a value or variable to do a '='"), *node->token(), 0); return; } if (!functionStack.isEmpty() && !globalVariableTable.contains(node->child(0)->token()->look())) // &&functionStack.top().variableTable->contains(node->token()->look())) { // //qDebug() << "function scope"; functionStack.top().variableTable->insert(node->child(0)->token()->look(), node->child(1)->value()); } else { // inserts unless already exists then replaces globalVariableTable.insert(node->child(0)->token()->look(), node->child(1)->value()); } // //qDebug() << "variableTable updated!"; emit variableTableUpdated(node->child(0)->token()->look(), node->child(1)->value()); } void Executer::executeLearn(TreeNode* node) { // //qDebug() << "called"; if(functionTable.contains(node->child(0)->token()->look())) { addError(i18n("The function '%1' is already defined.", node->child(0)->token()->look()), *node->token(), 0); return; } functionTable.insert(node->child(0)->token()->look(), node); // //qDebug() << "functionTable updated!"; QStringList parameters; for (uint i = 0; i < node->child(1)->childCount(); i++) parameters << node->child(1)->child(i)->token()->look(); emit functionTableUpdated(node->child(0)->token()->look(), parameters); } void Executer::executeArgumentList(TreeNode* node) { // //qDebug() << "called"; node = node; // stop the warnings // this is a stud } void Executer::executeReset(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::Reset*100+90)) return; emit reset(); } void Executer::executeClear(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::Clear*100+90)) return; emit clear(); } void Executer::executeCenter(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::Center*100+90)) return; emit center(); } void Executer::executeGo(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 2, 20000+Token::Go*100+90) || !checkParameterType(node, Value::Number, 20000+Token::Go*100+91)) return; emit go(node->child(0)->value()->number(), node->child(1)->value()->number()); } void Executer::executeGoX(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::GoX*100+90) || !checkParameterType(node, Value::Number, 20000+Token::GoX*100+91)) return; emit goX(node->child(0)->value()->number()); } void Executer::executeGoY(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::GoY*100+90) || !checkParameterType(node, Value::Number, 20000+Token::GoY*100+91)) return; emit goY(node->child(0)->value()->number()); } void Executer::executeForward(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Forward*100+90) || !checkParameterType(node, Value::Number, 20000+Token::Forward*100+91)) return; emit forward(node->child(0)->value()->number()); } void Executer::executeBackward(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Backward*100+90) || !checkParameterType(node, Value::Number, 20000+Token::Backward*100+91)) return; emit backward(node->child(0)->value()->number()); } void Executer::executeDirection(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Direction*100+90) || !checkParameterType(node, Value::Number, 20000+Token::Direction*100+91)) return; emit direction(node->child(0)->value()->number()); } void Executer::executeTurnLeft(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::TurnLeft*100+90) || !checkParameterType(node, Value::Number, 20000+Token::TurnLeft*100+91)) return; emit turnLeft(node->child(0)->value()->number()); } void Executer::executeTurnRight(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::TurnRight*100+90) || !checkParameterType(node, Value::Number, 20000+Token::TurnRight*100+91)) return; emit turnRight(node->child(0)->value()->number()); } void Executer::executePenWidth(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::PenWidth*100+90) || !checkParameterType(node, Value::Number, 20000+Token::PenWidth*100+91)) return; emit penWidth(node->child(0)->value()->number()); } void Executer::executePenUp(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::PenUp*100+90)) return; emit penUp(); } void Executer::executePenDown(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::PenDown*100+90)) return; emit penDown(); } void Executer::executePenColor(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 3, 20000+Token::PenColor*100+90) || !checkParameterType(node, Value::Number, 20000+Token::PenColor*100+91)) return; emit penColor(node->child(0)->value()->number(), node->child(1)->value()->number(), node->child(2)->value()->number()); } void Executer::executeCanvasColor(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 3, 20000+Token::CanvasColor*100+90) || !checkParameterType(node, Value::Number, 20000+Token::CanvasColor*100+91)) return; emit canvasColor(node->child(0)->value()->number(), node->child(1)->value()->number(), node->child(2)->value()->number()); } void Executer::executeCanvasSize(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 2, 20000+Token::CanvasSize*100+90) || !checkParameterType(node, Value::Number, 20000+Token::CanvasSize*100+91)) return; emit canvasSize(node->child(0)->value()->number(), node->child(1)->value()->number()); } void Executer::executeSpriteShow(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::SpriteShow*100+90)) return; emit spriteShow(); } void Executer::executeSpriteHide(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::SpriteHide*100+90)) return; emit spriteHide(); } void Executer::executePrint(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Print*100+90)) return; // //qDebug() << "Printing: '" << node->child(0)->value()->string() << "'"; emit print(node->child(0)->value()->string()); } void Executer::executeFontSize(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::FontSize*100+90) || !checkParameterType(node, Value::Number, 20000+Token::FontSize*100+91)) return; emit fontSize(node->child(0)->value()->number()); } void Executer::executeRandom(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 2, 20000+Token::Random*100+90)) return; TreeNode* nodeX = node->child(0); // getting TreeNode* nodeY = node->child(1); if (!checkParameterType(node, Value::Number, 20000+Token::Random*100+91)) return; double x = nodeX->value()->number(); double y = nodeY->value()->number(); double r = static_cast(KRandom::random()) / RAND_MAX; node->value()->setNumber(r * (y - x) + x); } void Executer::executeGetX(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::GetX*100+90)) return; double value = 0; emit getX(value); node->value()->setNumber(value); } void Executer::executeGetY(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::GetY*100+90)) return; double value = 0; emit getY(value); node->value()->setNumber(value); } void Executer::executeMessage(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Message*100+90)) return; emit message(node->child(0)->value()->string()); } void Executer::executeAsk(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Ask*100+90)) return; QString value = node->child(0)->value()->string(); emit ask(value); bool convertOk; double d = value.toDouble(&convertOk); if(convertOk) node->value()->setNumber(d); else node->value()->setString(value); } void Executer::executePi(TreeNode* node) { // //qDebug() << "called"; node->value()->setNumber(M_PI); } void Executer::executeTan(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Tan*100+90)) return; double deg = node->child(0)->value()->number(); node->value()->setNumber(tan(qDegreesToRadians(deg))); } void Executer::executeSin(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Sin*100+90)) return; double deg = node->child(0)->value()->number(); node->value()->setNumber(sin(qDegreesToRadians(deg))); } void Executer::executeCos(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Cos*100+90)) return; double deg = node->child(0)->value()->number(); node->value()->setNumber(cos(qDegreesToRadians(deg))); } void Executer::executeArcTan(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::ArcTan*100+90)) return; double deg = node->child(0)->value()->number(); node->value()->setNumber(qRadiansToDegrees(atan(deg))); } void Executer::executeArcSin(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::ArcSin*100+90)) return; double deg = node->child(0)->value()->number(); node->value()->setNumber(qRadiansToDegrees(asin(deg))); } void Executer::executeArcCos(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::ArcCos*100+90)) return; double deg = node->child(0)->value()->number(); node->value()->setNumber(qRadiansToDegrees(acos(deg))); } void Executer::executeSqrt(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Sqrt*100+90)) return; double val = node->child(0)->value()->number(); if(val<0) { addError(i18n("Can't do a sqrt of a negative number"), *node->child(0)->token(), 0); node->value()->setNumber(0); return; } node->value()->setNumber(sqrt(val)); } void Executer::executeRound(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Round*100+90)) return; double val = node->child(0)->value()->number(); node->value()->setNumber(round(val)); } void Executer::executeGetDirection(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::GetDirection*100+90)) return; double value = 0; emit getDirection(value); node->value()->setNumber(value); } void Executer::executeMod(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 2, 20000+Token::Mod*100+90)) return; TreeNode* nodeX = node->child(0); // getting TreeNode* nodeY = node->child(1); if (!checkParameterType(node, Value::Number, 20000+Token::Mod*100+91)) return; double x = nodeX->value()->number(); double y = nodeY->value()->number(); double m = (static_cast(round(x)) % static_cast(round(y))); node->value()->setNumber(m); } //END GENERATED executer_cpp CODE TreeNode* Executer::getParentOfTokenTypes(TreeNode* child, QList* types) { foreach(int type, *types) { if(child->parent()->token()->type()==type) return child->parent(); else if(child->parent()->token()->type()==Token::Root) - return 0; + return nullptr; } return getParentOfTokenTypes(child->parent(), types); } void Executer::printExe() { // if (currentNode->token()->type() != Token::Scope) // //qDebug() << "EXE> " << qPrintable(currentNode->token()->look()); } diff --git a/src/interpreter/parser.cpp b/src/interpreter/parser.cpp index fd4f5f5..f92a94b 100644 --- a/src/interpreter/parser.cpp +++ b/src/interpreter/parser.cpp @@ -1,991 +1,991 @@ /* Copyright (C) 2003-2006 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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. */ #include "parser.h" #include #include Parser::~Parser() { } void Parser::initialize(Tokenizer* _tokenizer, ErrorList* _errorList) { tokenizer = _tokenizer; errorList = _errorList; rootNode = new TreeNode(new Token(Token::Root, "root", 0, 0, 0, 0)); currentScope = rootNode; newScope = nullptr; finished = false; nextToken(); } void Parser::parse() { if (finished) return; // //qDebug() << "Parser::parse() -- main parse loop called"; TreeNode* resultNode = parseStatement(); // parse the next statement - if (resultNode == 0) { // no statement was found + if (resultNode == nullptr) { // no statement was found addError(i18n("Expected a command, instead got '%1'", currentToken->look()), *currentToken, 0); return; } if (resultNode->token()->type() == Token::ScopeClose || resultNode->token()->type() == Token::EndOfInput) { delete resultNode; } else { currentScope->appendChild(resultNode); } - if (newScope != 0) { + if (newScope != nullptr) { currentScope = newScope; - newScope = 0; + newScope = nullptr; } } void Parser::nextToken() { // get the next relevant token, and store it in currentToken // skip spaces and comments: currentToken = tokenizer->getToken(); // //qDebug() << "########### got token: " << currentToken->look(); while (currentToken->type() == Token::WhiteSpace || currentToken->type() == Token::Comment) { delete currentToken; currentToken = tokenizer->getToken(); // //qDebug() << "########### got token: " << currentToken->look(); } if (currentToken->type() == Token::Error) addError(i18n("Could not understand '%1'", currentToken->look()), *currentToken, 100); // QString out = QString("Parser::nextToken(): \"%5\" [%6] @ (%1,%2)-(%3,%4)") // .arg(currentToken->startRow()) // .arg(currentToken->startCol()) // .arg(currentToken->endRow()) // .arg(currentToken->endCol()) // .arg(currentToken->look()) // .arg(currentToken->type()); // //qDebug() << "Parser::nextToken():" << currentToken->look() << " [" << currentToken->type() << "] on line" << currentToken->startRow(); if (currentToken->type() == Token::EndOfInput) finished = true; } bool Parser::skipToken(int expectedTokenType) { // if the expectedTokenType matches the currentToken's type, dispose the currentToken and get a new one if (currentToken->type() == expectedTokenType) { delete currentToken; nextToken(); return true; } return false; } bool Parser::skipToken(int expectedTokenType, Token& byToken) { // TODO have byToken, and "errorHappenedHereToken" //TODO: Translate the following QStrings? if (skipToken(expectedTokenType)) return true; switch (expectedTokenType) { case Token::ArgumentSeparator: addError(i18n("A comma was expected here..."), byToken, 0); break; case Token::EndOfInput: addError(i18n("Did not expect '%1', instead expected the line to end after %2", currentToken->look(), byToken.look()), byToken, 0); break; case Token::Assign: addError(i18n("Expected an assignment, '=', after the variable '%1'", byToken.look()), byToken, 0); break; case Token::ParenthesisClose: addError(i18n("Did not expect '%1', instead expected a closing parenthesis, ')'", currentToken->look()), byToken, 0); break; case Token::To: addError(i18n("Expected 'to' after 'for'"), byToken, 0); break; case Token::FunctionCall: addError(i18n("Expected a name for a command after 'learn' command"), byToken, 0); break; } return false; } void Parser::addError(const QString& s, const Token& t, int code) { // if (m_testing) // //qDebug() << "ERR> " << qPrintable(s) << " (parse error)"; errorList->addError(s, t, code); } void Parser::printTree() const { const char* prefix = m_testing ? "NTR> " : ""; foreach (const QString &line, rootNode->toString().split('\n', QString::SkipEmptyParts)) { qDebug() << prefix << qPrintable(line.trimmed()); } } TreeNode* Parser::parseStatement() { // in addition to whitespace and comments (skipped by nextToken()), also skip newlines before statements while (currentToken->type() == Token::EndOfLine) { delete currentToken; nextToken(); } if (finished) return new TreeNode(currentToken); // TODO check if all scopes are closed before returning + throw error switch (currentToken->type()) { //BEGIN GENERATED parser_statements_cpp CODE /* The code between the line that start with "//BEGIN GENERATED" and "//END GENERATED" * is generated by "generate.rb" according to the definitions specified in * "definitions.rb". Please make all changes in the "definitions.rb" file, since all * all change you make here will be overwritten the next time "generate.rb" is run. * Thanks for looking at the code! */ case Token::Variable : return parseVariable(); case Token::FunctionCall : return parseFunctionCall(); case Token::ScopeOpen : return parseScopeOpen(); case Token::ScopeClose : return parseScopeClose(); case Token::Exit : return parseExit(); case Token::If : return parseIf(); case Token::Repeat : return parseRepeat(); case Token::While : return parseWhile(); case Token::For : return parseFor(); case Token::Break : return parseBreak(); case Token::Return : return parseReturn(); case Token::Wait : return parseWait(); case Token::Assert : return parseAssert(); case Token::Learn : return parseLearn(); case Token::Reset : return parseReset(); case Token::Clear : return parseClear(); case Token::Center : return parseCenter(); case Token::Go : return parseGo(); case Token::GoX : return parseGoX(); case Token::GoY : return parseGoY(); case Token::Forward : return parseForward(); case Token::Backward : return parseBackward(); case Token::Direction : return parseDirection(); case Token::TurnLeft : return parseTurnLeft(); case Token::TurnRight : return parseTurnRight(); case Token::PenWidth : return parsePenWidth(); case Token::PenUp : return parsePenUp(); case Token::PenDown : return parsePenDown(); case Token::PenColor : return parsePenColor(); case Token::CanvasColor : return parseCanvasColor(); case Token::CanvasSize : return parseCanvasSize(); case Token::SpriteShow : return parseSpriteShow(); case Token::SpriteHide : return parseSpriteHide(); case Token::Print : return parsePrint(); case Token::FontSize : return parseFontSize(); case Token::Random : return parseRandom(); case Token::GetX : return parseGetX(); case Token::GetY : return parseGetY(); case Token::Message : return parseMessage(); case Token::Ask : return parseAsk(); case Token::Pi : return parsePi(); case Token::Tan : return parseTan(); case Token::Sin : return parseSin(); case Token::Cos : return parseCos(); case Token::ArcTan : return parseArcTan(); case Token::ArcSin : return parseArcSin(); case Token::ArcCos : return parseArcCos(); case Token::Sqrt : return parseSqrt(); case Token::Round : return parseRound(); case Token::GetDirection : return parseGetDirection(); case Token::Mod : return parseMod(); //END GENERATED parser_statements_cpp CODE case Token::Error : return new TreeNode(currentToken); default : { //Token type is something else... ////qDebug() << "Parser::parseStatement(): I don't know this Token type."; ////qDebug() << "Look: " << currentToken->look() << " type: " << currentToken->type(); addError(i18n("You cannot put '%1' here.", currentToken->look()), *currentToken, 0); finished = true; return new TreeNode(currentToken); } } } TreeNode* Parser::parseFactor() { // //qDebug() << "Parser::parseFactor()"; Token* rememberedToken; TreeNode* node; switch (currentToken->type()) { case Token::ParenthesisOpen: rememberedToken = currentToken; nextToken(); node = parseExpression(); skipToken(Token::ParenthesisClose, *rememberedToken); break; case Token::FunctionCall: node = parseFunctionCall(); break; case Token::Variable: node = new TreeNode(currentToken); nextToken(); break; case Token::String: node = new TreeNode(currentToken); { // extra scope to localize the QString 'str' QString str = currentToken->look(); if (!currentToken->look().endsWith('\"')) { str += "\""; addError(i18n("Text string was not properly closed, expected a double quote, ' \" ', to close the string."), *currentToken, 0); } node->value()->setString(str.mid(1, str.length() - 2)); } nextToken(); break; case Token::Number: node = new TreeNode(currentToken); { bool ok = true; double num = currentToken->look().toDouble(&ok); if (ok) { node->value()->setNumber(num); nextToken(); } else { qCritical("Parser::parseFactor(): could not parse a number"); } } break; case Token::True: node = new TreeNode(currentToken); node->value()->setBool(true); nextToken(); break; case Token::False: node = new TreeNode(currentToken); node->value()->setBool(false); nextToken(); break; // case Token::Run: // node = ExternalRun(); // break; // // case tokInputWindow: // node = InputWindow(); // break; // // case tokRandom: // node = Random(); // break; // // case Token::EndOfLine: // node = new TreeNode(currentToken); // break; default: // TODO maybe precheck if this is a statement that returns something node = parseStatement(); break; // default: // QString s = currentToken->look(); // if ( s.isEmpty() || currentToken->type() == Token::EndOfInput ) // { // // Error(currentToken, i18n("INTERNAL ERROR NR %1: please sent this Logo script to KTurtle developers").arg(1), 1020); // // if this error occurs the see the Parser::Repeat for the good solution using 'preservedToken' // } // else // { // // Error(currentToken, i18n("Cannot understand '%1', expected an expression after the '%2' command").arg(s).arg(preservedToken->look()), 1020); // } // node = new TreeNode(currentToken); // nextToken(); // break; } return node; } TreeNode* Parser::parseSignedFactor() { // //qDebug() << "Parser::parseSignedFactor()"; // see if there is a plus, minus or 'not' in front of a factor Token* rememberedToken; TreeNode* node; switch (currentToken->type()) { case Token::Addition: nextToken(); return parseFactor(); break; case Token::Substracton: rememberedToken = currentToken; nextToken(); node = parseFactor(); if (node->token()->type() == Token::Number) { // in case of just a constant (-3) situation node->value()->setNumber(-1 * node->value()->number()); return node; } else { // in case of a variable or other situation (-$a) TreeNode* minusNode = new TreeNode(rememberedToken); minusNode->appendChild(node); return minusNode; } break; case Token::Not: rememberedToken = currentToken; nextToken(); node = parseFactor(); { // extra scope needed to localize not_Node TreeNode* notNode = new TreeNode(rememberedToken); notNode->appendChild(node); return notNode; } break; default: // no 'sign', no problem; just had to check if there was any... continue with the real work: return parseFactor(); break; } } TreeNode* Parser::parseTerm() { // //qDebug() << "Parser::parseTerm()"; TreeNode* termNode = parseSignedFactor(); TreeNode* pos = termNode; - TreeNode* left = 0; - TreeNode* right = 0; + TreeNode* left = nullptr; + TreeNode* right = nullptr; while ( (currentToken->type() == Token::Multiplication) || (currentToken->type() == Token::Division) || (currentToken->type() == Token::Power) ) { // while we find a multiplicative operator do... left = pos; pos = new TreeNode(currentToken); pos->appendChild(left); nextToken(); right = parseSignedFactor(); - if (right != 0) + if (right != nullptr) pos->appendChild(right); termNode = pos; } return termNode; } TreeNode* Parser::parseExpression() { // //qDebug() << "Parser::parseExpression()"; TreeNode* expressionNode = parseTerm(); TreeNode* pos = expressionNode; - TreeNode* left = 0; - TreeNode* right = 0; + TreeNode* left = nullptr; + TreeNode* right = nullptr; - Token* prevToken = 0; + Token* prevToken = nullptr; while ((currentToken->type() == Token::Addition) || (currentToken->type() == Token::Substracton) || (currentToken->type() == Token::GreaterThan) || (currentToken->type() == Token::GreaterOrEquals) || (currentToken->type() == Token::LessThan) || (currentToken->type() == Token::LessOrEquals) || (currentToken->type() == Token::Equals) || (currentToken->type() == Token::NotEquals) || (currentToken->type() == Token::Or) || (currentToken->type() == Token::And)) { left = pos; pos = new TreeNode(currentToken); pos->appendChild(left); prevToken = currentToken; nextToken(); if(prevToken->type() == Token::And || prevToken->type() == Token::Or) right = parseExpression(); else right = parseTerm(); - if (right != 0) pos->appendChild(right); + if (right != nullptr) pos->appendChild(right); expressionNode = pos; } return expressionNode; } void Parser::appendArguments(TreeNode* node) { // appends the nodes of arguments to the node, does not do any type/quantity checking. // this because it's also used for the user defined 'functionCall' where we don't know type nor quantity // we also don't know if this node is (part of) an argument itself if (currentToken->type() == Token::EndOfLine || currentToken->type() == Token::EndOfInput || currentToken->type() == Token::ArgumentSeparator || currentToken->type() == Token::ParenthesisClose || currentToken->type() == Token::ScopeOpen || currentToken->type() == Token::ScopeClose) return; node->appendChild(parseExpression()); // append the first parameter while (skipToken(Token::ArgumentSeparator)) { // pushes through the comma if (currentToken->type() == Token::EndOfLine || currentToken->type() == Token::EndOfInput) return; // catch forgotten expressions (go 10,) node->appendChild(parseExpression()); } } //BEGIN GENERATED parser_cpp CODE /* The code between the line that start with "//BEGIN GENERATED" and "//END GENERATED" * is generated by "generate.rb" according to the definitions specified in * "definitions.rb". Please make all changes in the "definitions.rb" file, since all * all change you make here will be overwritten the next time "generate.rb" is run. * Thanks for looking at the code! */ TreeNode* Parser::parseVariable() { // This is called to the variable is the first token on a line. // There has to be an assignment token right after it... TreeNode* variableNode = new TreeNode(currentToken); nextToken(); Token* remeberedToken = new Token(*currentToken); skipToken(Token::Assign, *variableNode->token()); TreeNode* assignNode = new TreeNode(remeberedToken); assignNode->appendChild(variableNode); // the LHV; the symbol assignNode->appendChild(parseExpression()); // the RHV; the expression return assignNode; } TreeNode* Parser::parseFunctionCall() { TreeNode* node = new TreeNode(currentToken); node->token()->setType(Token::FunctionCall); nextToken(); appendArguments(node); return node; } TreeNode* Parser::parseScopeOpen() { TreeNode* scopeNode = new TreeNode(new Token(Token::Scope, "{...}", currentToken->startRow(), currentToken->startCol(), 0, 0)); delete currentToken; nextToken(); // cannot change the currentScope to this scope cauz we still have to work in the currentScope // so we set the newScope, which the currentScope will become after parsing the current statement newScope = scopeNode; return scopeNode; } TreeNode* Parser::parseScopeClose() { TreeNode* node = new TreeNode(currentToken); int endRow = currentToken->endRow(); int endCol = currentToken->endCol(); nextToken(); while (currentToken->type() == Token::EndOfLine) { // allow newlines before else delete currentToken; nextToken(); } if (currentScope->parent() && currentScope->parent()->token()->type() == Token::If && currentToken->type() == Token::Else) { currentScope->parent()->appendChild(parseElse()); } if (currentScope != rootNode) { // find the parent scope of this scope, and make it current TreeNode* parentScope = currentScope; do { parentScope = parentScope->parent(); } while (parentScope != rootNode && parentScope->token()->type() != Token::Scope); currentScope->token()->setEndRow(endRow); currentScope->token()->setEndCol(endCol); currentScope = parentScope; } return node; } TreeNode* Parser::parseExit() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseIf() { TreeNode* node = new TreeNode(currentToken); nextToken(); node->appendChild(parseExpression()); if (currentToken->type() == Token::ScopeOpen) { node->appendChild(parseScopeOpen()); // if followed by a scope } return node; } TreeNode* Parser::parseElse() { nextToken(); if (currentToken->type() == Token::ScopeOpen) { return parseScopeOpen(); // if followed by a scope } return parseStatement(); // if followed by single statement } TreeNode* Parser::parseRepeat() { TreeNode* node = new TreeNode(currentToken); nextToken(); node->appendChild(parseExpression()); if (currentToken->type() == Token::ScopeOpen) { node->appendChild(parseScopeOpen()); // if followed by a scope } else { node->appendChild(parseStatement()); // if followed by single statement } return node; } TreeNode* Parser::parseWhile() { TreeNode* node = new TreeNode(currentToken); nextToken(); node->appendChild(parseExpression()); if (currentToken->type() == Token::ScopeOpen) { node->appendChild(parseScopeOpen()); // if followed by a scope } else { node->appendChild(parseStatement()); // if followed by single statement } return node; } TreeNode* Parser::parseFor() { TreeNode* node = new TreeNode(currentToken); nextToken(); Token* firstToken = currentToken; nextToken(); if (firstToken->type() == Token::Variable && currentToken->type() == Token::Assign) { node->token()->setType(Token::ForTo); node->appendChild(new TreeNode(firstToken)); nextToken(); node->appendChild(parseExpression()); skipToken(Token::To, *node->token()); node->appendChild(parseExpression()); if (currentToken->type() == Token::Step) { nextToken(); node->appendChild(parseExpression()); } else { TreeNode* step = new TreeNode(new Token(Token::Number, "1", 0,0,0,0)); step->setValue(Value(1.0)); node->appendChild(step); } // } else if (currentToken->type() == Token::In) { // // @TODO something for a for-in loop } else { addError(i18n("'for' was called wrongly"), *node->token(), 0); finished = true; // abort after this error return node; } if (currentToken->type() == Token::ScopeOpen) { node->appendChild(parseScopeOpen()); // if followed by a scope } else { node->appendChild(parseStatement()); // if followed by single statement } return node; } TreeNode* Parser::parseBreak() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseReturn() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseWait() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseAssert() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseLearn() { TreeNode* node = new TreeNode(currentToken); nextToken(); node->appendChild(new TreeNode(new Token(*currentToken))); skipToken(Token::FunctionCall, *node->token()); TreeNode* argumentList = new TreeNode(new Token(Token::ArgumentList, "arguments", 0, 0, 0, 0)); while (currentToken->type() == Token::Variable) { // cannot just call appendArguments here because we're only appending Token::Variable tokens argumentList->appendChild(new TreeNode(currentToken)); nextToken(); if (currentToken->type() != Token::ArgumentSeparator) break; nextToken(); } node->appendChild(argumentList); //Skip all the following EndOfLine's while (currentToken->type() == Token::EndOfLine) { delete currentToken; nextToken(); } if (currentToken->type() == Token::ScopeOpen) { node->appendChild(parseScopeOpen()); // if followed by a scope } else { addError(i18n("Expected a scope after the 'learn' command"), *node->token(), 0); } return node; } TreeNode* Parser::parseReset() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseClear() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseCenter() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseGo() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseGoX() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseGoY() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseForward() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseBackward() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseDirection() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseTurnLeft() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseTurnRight() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parsePenWidth() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parsePenUp() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parsePenDown() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parsePenColor() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseCanvasColor() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseCanvasSize() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseSpriteShow() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseSpriteHide() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parsePrint() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseFontSize() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseRandom() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseGetX() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseGetY() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseMessage() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseAsk() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parsePi() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseTan() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseSin() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseCos() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseArcTan() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseArcSin() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseArcCos() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseSqrt() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseRound() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseGetDirection() { TreeNode* node = new TreeNode(currentToken); nextToken(); skipToken(Token::EndOfLine, *node->token()); return node; } TreeNode* Parser::parseMod() { TreeNode* node = new TreeNode(currentToken); nextToken(); appendArguments(node); skipToken(Token::EndOfLine, *node->token()); return node; } //END GENERATED parser_cpp CODE diff --git a/src/interpreter/translator.cpp b/src/interpreter/translator.cpp index f06c52c..9d469be 100644 --- a/src/interpreter/translator.cpp +++ b/src/interpreter/translator.cpp @@ -1,775 +1,775 @@ /* Copyright (C) 2003-2006 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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. */ #include "translator.h" #include #include "token.h" -Translator* Translator::m_instance = 0; // initialize pointer +Translator* Translator::m_instance = nullptr; // initialize pointer Translator* Translator::instance() { - if (m_instance == 0) m_instance = new Translator; // create sole instance if its the first call + if (m_instance == nullptr) m_instance = new Translator; // create sole instance if its the first call return m_instance; // address of sole instance } Translator::Translator() : localizer(QStringList() << DEFAULT_LANGUAGE_CODE) { } Translator::~Translator() { delete m_instance; - m_instance = 0; + m_instance = nullptr; } int Translator::look2type(QString& look) { if (look2typeMap.contains(look)) return look2typeMap[look]; return Token::Unknown; } int Translator::look2type(QChar& look) { if (look2typeMap.contains(static_cast(look))) return look2typeMap[static_cast(look)]; return Token::Unknown; } QList Translator::type2look(int type) { return look2typeMap.keys(type); } QHash > Translator::token2stringsMap() { QHash > resultMap; QList tokenList = look2typeMap.values(); foreach (int token, tokenList) resultMap.insert(token, look2typeMap.keys(token)); return resultMap; } bool Translator::setLanguage(const QString &lang_code) { // FIXME default to GUI language? return false when language not available? localizer = QStringList() << lang_code << DEFAULT_LANGUAGE_CODE; setDictionary(); setExamples(); return true; } void Translator::setDictionary() { look2typeMap.clear(); default2localizedMap.clear(); QString localizedCommandLook; //BEGIN GENERATED translator_cpp CODE /* The code between the line that start with "//BEGIN GENERATED" and "//END GENERATED" * is generated by "generate.rb" according to the definitions specified in * "definitions.rb". Please make all changes in the "definitions.rb" file, since all * all change you make here will be overwritten the next time "generate.rb" is run. * Thanks for looking at the code! */ look2typeMap["$"] = Token::VariablePrefix; localizedCommandLook = ki18nc( "You are about to translate the 'True' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "true").toString(localizer); default2localizedMap["true"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::True; localizedCommandLook = ki18nc( "You are about to translate the 'False' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "false").toString(localizer); default2localizedMap["false"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::False; look2typeMap["#"] = Token::Comment; look2typeMap["\""] = Token::StringDelimiter; look2typeMap["{"] = Token::ScopeOpen; look2typeMap["}"] = Token::ScopeClose; look2typeMap["("] = Token::ParenthesisOpen; look2typeMap[")"] = Token::ParenthesisClose; localizedCommandLook = ki18nc( "You are about to translate the 'ArgumentSeparator' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", ",").toString(localizer); default2localizedMap[","] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::ArgumentSeparator; localizedCommandLook = ki18nc( "You are about to translate the 'DecimalSeparator' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", ".").toString(localizer); default2localizedMap["."] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::DecimalSeparator; localizedCommandLook = ki18nc( "You are about to translate the 'Exit' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "exit").toString(localizer); default2localizedMap["exit"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Exit; localizedCommandLook = ki18nc( "You are about to translate the 'If' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "if").toString(localizer); default2localizedMap["if"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::If; localizedCommandLook = ki18nc( "You are about to translate the 'Else' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "else").toString(localizer); default2localizedMap["else"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Else; localizedCommandLook = ki18nc( "You are about to translate the 'Repeat' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "repeat").toString(localizer); default2localizedMap["repeat"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Repeat; localizedCommandLook = ki18nc( "You are about to translate the 'While' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "while").toString(localizer); default2localizedMap["while"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::While; localizedCommandLook = ki18nc( "You are about to translate the 'For' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "for").toString(localizer); default2localizedMap["for"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::For; localizedCommandLook = ki18nc( "You are about to translate the 'To' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "to").toString(localizer); default2localizedMap["to"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::To; localizedCommandLook = ki18nc( "You are about to translate the 'Step' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "step").toString(localizer); default2localizedMap["step"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Step; localizedCommandLook = ki18nc( "You are about to translate the 'Break' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "break").toString(localizer); default2localizedMap["break"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Break; localizedCommandLook = ki18nc( "You are about to translate the 'Return' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "return").toString(localizer); default2localizedMap["return"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Return; localizedCommandLook = ki18nc( "You are about to translate the 'Wait' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "wait").toString(localizer); default2localizedMap["wait"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Wait; localizedCommandLook = ki18nc( "You are about to translate the 'Assert' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "assert").toString(localizer); default2localizedMap["assert"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Assert; localizedCommandLook = ki18nc( "You are about to translate the 'And' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "and").toString(localizer); default2localizedMap["and"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::And; localizedCommandLook = ki18nc( "You are about to translate the 'Or' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "or").toString(localizer); default2localizedMap["or"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Or; localizedCommandLook = ki18nc( "You are about to translate the 'Not' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "not").toString(localizer); default2localizedMap["not"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Not; look2typeMap["=="] = Token::Equals; look2typeMap["!="] = Token::NotEquals; look2typeMap[">"] = Token::GreaterThan; look2typeMap["<"] = Token::LessThan; look2typeMap[">="] = Token::GreaterOrEquals; look2typeMap["<="] = Token::LessOrEquals; look2typeMap["+"] = Token::Addition; look2typeMap["-"] = Token::Substracton; look2typeMap["*"] = Token::Multiplication; look2typeMap["/"] = Token::Division; look2typeMap["^"] = Token::Power; look2typeMap["="] = Token::Assign; localizedCommandLook = ki18nc( "You are about to translate the 'Learn' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "learn").toString(localizer); default2localizedMap["learn"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Learn; localizedCommandLook = ki18nc( "You are about to translate the 'Reset' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "reset").toString(localizer); default2localizedMap["reset"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Reset; localizedCommandLook = ki18nc( "You are about to translate the 'Clear' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "clear").toString(localizer); default2localizedMap["clear"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Clear; localizedCommandLook = ki18nc( "You are about to translate the 'Clear' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "ccl").toString(localizer); default2localizedMap["ccl"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Clear; localizedCommandLook = ki18nc( "You are about to translate the 'Center' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "center").toString(localizer); default2localizedMap["center"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Center; localizedCommandLook = ki18nc( "You are about to translate the 'Go' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "go").toString(localizer); default2localizedMap["go"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Go; localizedCommandLook = ki18nc( "You are about to translate the 'GoX' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "gox").toString(localizer); default2localizedMap["gox"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::GoX; localizedCommandLook = ki18nc( "You are about to translate the 'GoX' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "gx").toString(localizer); default2localizedMap["gx"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::GoX; localizedCommandLook = ki18nc( "You are about to translate the 'GoY' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "goy").toString(localizer); default2localizedMap["goy"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::GoY; localizedCommandLook = ki18nc( "You are about to translate the 'GoY' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "gy").toString(localizer); default2localizedMap["gy"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::GoY; localizedCommandLook = ki18nc( "You are about to translate the 'Forward' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "forward").toString(localizer); default2localizedMap["forward"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Forward; localizedCommandLook = ki18nc( "You are about to translate the 'Forward' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "fw").toString(localizer); default2localizedMap["fw"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Forward; localizedCommandLook = ki18nc( "You are about to translate the 'Backward' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "backward").toString(localizer); default2localizedMap["backward"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Backward; localizedCommandLook = ki18nc( "You are about to translate the 'Backward' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "bw").toString(localizer); default2localizedMap["bw"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Backward; localizedCommandLook = ki18nc( "You are about to translate the 'Direction' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "direction").toString(localizer); default2localizedMap["direction"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Direction; localizedCommandLook = ki18nc( "You are about to translate the 'Direction' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "dir").toString(localizer); default2localizedMap["dir"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Direction; localizedCommandLook = ki18nc( "You are about to translate the 'TurnLeft' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "turnleft").toString(localizer); default2localizedMap["turnleft"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::TurnLeft; localizedCommandLook = ki18nc( "You are about to translate the 'TurnLeft' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "tl").toString(localizer); default2localizedMap["tl"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::TurnLeft; localizedCommandLook = ki18nc( "You are about to translate the 'TurnRight' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "turnright").toString(localizer); default2localizedMap["turnright"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::TurnRight; localizedCommandLook = ki18nc( "You are about to translate the 'TurnRight' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "tr").toString(localizer); default2localizedMap["tr"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::TurnRight; localizedCommandLook = ki18nc( "You are about to translate the 'PenWidth' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "penwidth").toString(localizer); default2localizedMap["penwidth"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::PenWidth; localizedCommandLook = ki18nc( "You are about to translate the 'PenWidth' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "pw").toString(localizer); default2localizedMap["pw"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::PenWidth; localizedCommandLook = ki18nc( "You are about to translate the 'PenUp' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "penup").toString(localizer); default2localizedMap["penup"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::PenUp; localizedCommandLook = ki18nc( "You are about to translate the 'PenUp' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "pu").toString(localizer); default2localizedMap["pu"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::PenUp; localizedCommandLook = ki18nc( "You are about to translate the 'PenDown' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "pendown").toString(localizer); default2localizedMap["pendown"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::PenDown; localizedCommandLook = ki18nc( "You are about to translate the 'PenDown' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "pd").toString(localizer); default2localizedMap["pd"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::PenDown; localizedCommandLook = ki18nc( "You are about to translate the 'PenColor' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "pencolor").toString(localizer); default2localizedMap["pencolor"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::PenColor; localizedCommandLook = ki18nc( "You are about to translate the 'PenColor' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "pc").toString(localizer); default2localizedMap["pc"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::PenColor; localizedCommandLook = ki18nc( "You are about to translate the 'CanvasColor' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "canvascolor").toString(localizer); default2localizedMap["canvascolor"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::CanvasColor; localizedCommandLook = ki18nc( "You are about to translate the 'CanvasColor' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "cc").toString(localizer); default2localizedMap["cc"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::CanvasColor; localizedCommandLook = ki18nc( "You are about to translate the 'CanvasSize' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "canvassize").toString(localizer); default2localizedMap["canvassize"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::CanvasSize; localizedCommandLook = ki18nc( "You are about to translate the 'CanvasSize' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "cs").toString(localizer); default2localizedMap["cs"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::CanvasSize; localizedCommandLook = ki18nc( "You are about to translate the 'SpriteShow' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "spriteshow").toString(localizer); default2localizedMap["spriteshow"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::SpriteShow; localizedCommandLook = ki18nc( "You are about to translate the 'SpriteShow' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "ss").toString(localizer); default2localizedMap["ss"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::SpriteShow; localizedCommandLook = ki18nc( "You are about to translate the 'SpriteHide' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "spritehide").toString(localizer); default2localizedMap["spritehide"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::SpriteHide; localizedCommandLook = ki18nc( "You are about to translate the 'SpriteHide' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "sh").toString(localizer); default2localizedMap["sh"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::SpriteHide; localizedCommandLook = ki18nc( "You are about to translate the 'Print' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "print").toString(localizer); default2localizedMap["print"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Print; localizedCommandLook = ki18nc( "You are about to translate the 'FontSize' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "fontsize").toString(localizer); default2localizedMap["fontsize"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::FontSize; localizedCommandLook = ki18nc( "You are about to translate the 'Random' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "random").toString(localizer); default2localizedMap["random"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Random; localizedCommandLook = ki18nc( "You are about to translate the 'Random' COMMAND ALIAS, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "rnd").toString(localizer); default2localizedMap["rnd"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Random; localizedCommandLook = ki18nc( "You are about to translate the 'GetX' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "getx").toString(localizer); default2localizedMap["getx"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::GetX; localizedCommandLook = ki18nc( "You are about to translate the 'GetY' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "gety").toString(localizer); default2localizedMap["gety"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::GetY; localizedCommandLook = ki18nc( "You are about to translate the 'Message' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "message").toString(localizer); default2localizedMap["message"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Message; localizedCommandLook = ki18nc( "You are about to translate the 'Ask' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "ask").toString(localizer); default2localizedMap["ask"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Ask; localizedCommandLook = ki18nc( "You are about to translate the 'Pi' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "pi").toString(localizer); default2localizedMap["pi"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Pi; localizedCommandLook = ki18nc( "You are about to translate the 'Tan' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "tan").toString(localizer); default2localizedMap["tan"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Tan; localizedCommandLook = ki18nc( "You are about to translate the 'Sin' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "sin").toString(localizer); default2localizedMap["sin"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Sin; localizedCommandLook = ki18nc( "You are about to translate the 'Cos' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "cos").toString(localizer); default2localizedMap["cos"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Cos; localizedCommandLook = ki18nc( "You are about to translate the 'ArcTan' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "arctan").toString(localizer); default2localizedMap["arctan"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::ArcTan; localizedCommandLook = ki18nc( "You are about to translate the 'ArcSin' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "arcsin").toString(localizer); default2localizedMap["arcsin"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::ArcSin; localizedCommandLook = ki18nc( "You are about to translate the 'ArcCos' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "arccos").toString(localizer); default2localizedMap["arccos"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::ArcCos; localizedCommandLook = ki18nc( "You are about to translate the 'Sqrt' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "sqrt").toString(localizer); default2localizedMap["sqrt"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Sqrt; localizedCommandLook = ki18nc( "You are about to translate the 'Round' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "round").toString(localizer); default2localizedMap["round"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Round; localizedCommandLook = ki18nc( "You are about to translate the 'GetDirection' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "getdirection").toString(localizer); default2localizedMap["getdirection"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::GetDirection; localizedCommandLook = ki18nc( "You are about to translate the 'Mod' COMMAND, there are some rules on how to translate it." "Please see http://edu.kde.org/kturtle/translator.php to learn how to properly translate it.", "mod").toString(localizer); default2localizedMap["mod"] = localizedCommandLook; look2typeMap[localizedCommandLook] = Token::Mod; //END GENERATED translator_cpp CODE } void Translator::setExamples() { examples.clear(); QString exampleName; exampleName = ki18nc( "This is an EXAMPLE NAME in KTurtle." "Please see http://edu.kde.org/kturtle/translator.php to learn know how to properly translate it.", "triangle").toString(localizer); examples[exampleName] = localizeScript(QString( "@(reset)\n" "@(repeat) 3 {\n" " @(forward) 100\n" " @(turnleft) 120\n" "}\n" )); exampleName = ki18nc( "This is an EXAMPLE NAME in KTurtle." "Please see http://edu.kde.org/kturtle/translator.php to learn know how to properly translate it.", "curly").toString(localizer); examples[exampleName] = localizeScript(QString( "@(reset)\n" "@(penup)\n" "@(forward) 50\n" "@(pendown)\n" "\n" "@(repeat) 4 {\n" " @(for) $x = 1 @(to) 100 {\n" " @(forward) 10\n" " @(turnright) 100 - $x\n" " }\n" "}\n" )); exampleName = ki18nc( "This is an EXAMPLE NAME in KTurtle." "Please see http://edu.kde.org/kturtle/translator.php to learn know how to properly translate it.", "arrow").toString(localizer); examples[exampleName] = localizeScript(QString( "@(reset)\n" "\n" "@(canvassize) 200@(,) 200\n" "@(canvascolor) 0@(,) 0@(,) 0\n" "@(pencolor) 255@(,) 0@(,) 0\n" "@(penwidth) 5\n" "\n" "@(go) 20@(,)20\n" "@(direction) 135\n" "\n" "@(forward) 200\n" "@(turnleft) 135\n" "@(forward) 100\n" "@(turnleft) 135\n" "@(forward) 141\n" "@(turnleft) 135\n" "@(forward) 100\n" "@(turnleft) 45\n" "\n" "@(go) 40@(,) 100" )); exampleName = ki18nc( "This is an EXAMPLE NAME in KTurtle." "Please see http://edu.kde.org/kturtle/translator.php to learn know how to properly translate it.", "flower").toString(localizer); examples[exampleName] = localizeScript(QString( "@(reset)\n" "@(canvascolor) 255@(,) 55@(,) 140\n" "@(pencolor) 160@(,) 0@(,) 255\n" "@(penwidth) 3\n" "\n" "@(repeat) 8 {\n" " @(repeat) 4 {\n" " @(forward) 20\n" " @(turnright) 30\n" " }\n" " @(repeat) 7 {\n" " @(forward) 10\n" " @(turnright) 15\n" " }\n" " @(repeat) 9 {\n" " @(forward) 3\n" " @(turnright) 10\n" " }\n" "}\n" "\n" "@(go) 145@(,) 145\n" "@(direction) 0" )); } QString Translator::localizeScript(const QString& untranslatedScript) { QString result = untranslatedScript; Translator* translator = Translator::instance(); QRegExp rx("@\\(.*\\)"); rx.setMinimal(true); // make it not greedy int pos = 0; while ((pos = rx.indexIn(result, pos)) != -1) { QString original = result.mid(pos, rx.matchedLength()); original = original.mid(2, original.length() - 3); result = result.replace(pos, rx.matchedLength(), translator->default2localized(original)); } return result; } diff --git a/src/interpreter/treenode.cpp b/src/interpreter/treenode.cpp index ef6cb8d..d103c07 100644 --- a/src/interpreter/treenode.cpp +++ b/src/interpreter/treenode.cpp @@ -1,134 +1,134 @@ /* Copyright (C) 2003-2006 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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. */ #include "treenode.h" #include TreeNode::~TreeNode() { - if (childList != 0) { + if (childList != nullptr) { // this should work here: qDeleteAll(*childList); childList->clear(); // but this is nicer (and probably less optimal): // while (!list.isEmpty()) delete list.takeFirst(); } delete _value; delete _token; } void TreeNode::init(TreeNode* parent, Token* token) { setParent(parent); setToken(token); - childList = 0; + childList = nullptr; currentChildIndex = -1; - _value = 0; + _value = nullptr; } void TreeNode::appendChild(TreeNode* newChild) { - if (childList == 0) childList = new ChildList(); + if (childList == nullptr) childList = new ChildList(); newChild->setParent(this); childList->append(newChild); // // // QString out = QString("TreeNode::appendChild(): \"%5\" [%6] @ (%1,%2)-(%3,%4) to parent '%7'") // // // .arg(newChild->token()->startRow()) // // // .arg(newChild->token()->startCol()) // // // .arg(newChild->token()->endRow()) // // // .arg(newChild->token()->endCol()) // // // .arg(newChild->token()->look()) // // // .arg(newChild->token()->type()) // // // .arg(_token->look()); // //qDebug() << "TreeNode::appendChild():" << newChild->token()->look() << " on line" << newChild->token()->startRow() << "to parent" << _token->look(); } TreeNode* TreeNode::child(int i) { - if (childList == 0) return 0; + if (childList == nullptr) return nullptr; if (0 <= i && i < childList->size()) return childList->at(i); - return 0; + return nullptr; } TreeNode* TreeNode::firstChild() { - if (childList == 0 || childList->isEmpty()) return 0; + if (childList == nullptr || childList->isEmpty()) return nullptr; currentChildIndex = 0; return childList->first(); } TreeNode* TreeNode::nextChild() { - if (childList == 0) return 0; + if (childList == nullptr) return nullptr; currentChildIndex++; return child(currentChildIndex); } int TreeNode::findChildIndex(TreeNode* child) { return childList->indexOf(child); } TreeNode* TreeNode::nextSibling() { - if (_parent == 0) return 0; + if (_parent == nullptr) return nullptr; return _parent->child(_parent->findChildIndex(this)+1); } QString TreeNode::toString() { QString str = ""; showTree(str); return str; } // recursively walk through tree and show node names with indentation void TreeNode::showTree(QString& str, int indent) { - if (childList == 0) return; + if (childList == nullptr) return; indent++; TreeNode* node; for (int i = 0; i < childList->size(); i++) { node = childList->at(i); node->show(str, indent); node->showTree(str, indent); } } void TreeNode::show(QString& str, int indent) const { QString indentString = ""; for (int i = 0; i < indent; i++) indentString += "> "; str += indentString + _token->look() + QString(" @ (%1, %2)-(%3, %4)\n") .arg(_token->startRow()) .arg(_token->startCol()) .arg(_token->endRow()) .arg(_token->endCol()); }