void BTreeBase::pruneTree(BTreeNode *root, bool /*conditionalRoot*/) { Traverser t(root); t.descendLeftwardToTerminal(); bool done = false; while(!done) { //t.descendLeftwardToTerminal(); if( t.current()->parent() ) { if( t.oppositeNode()->hasChildren() ) pruneTree(t.oppositeNode()); } t.moveToParent(); if( !t.current()->hasChildren() ) { //if(t.current() == t.root()) done = true; if(!t.current()->parent()) done = true; continue; } BTreeNode *l = t.current()->left(); BTreeNode *r = t.current()->right(); BTreeNode *n = 0; BTreeNode *z = 0; // Deal with situations where there are two constants so we want // to evaluate at compile time if( (l->type() == number && r->type() == number) ) // && !(t.current()==root&&conditionalRoot) ) { if(t.current()->childOp() == Expression::division && r->value() == "0" ) { t.current()->setChildOp(Expression::divbyzero); return; } QString value = QString::number(Parser::doArithmetic(l->value().toInt(),r->value().toInt(),t.current()->childOp())); t.current()->deleteChildren(); t.current()->setChildOp(Expression::noop); t.current()->setType(number); t.current()->setValue(value); } // Addition and subtraction else if(t.current()->childOp() == Expression::addition || t.current()->childOp() == Expression::subtraction) { // See if one of the nodes is 0, and set n to the node that actually has data, // z to the one containing zero. bool zero = false; if( l->value() == "0" ) { zero = true; n = r; z = l; } else if( r->value() == "0" ) { zero = true; n = l; z = r; } // Now get rid of the useless nodes if(zero) { BTreeNode *p = t.current(); // save in order to delete after replaceNode(p,n); t.setCurrent(n); // Delete the old nodes delete p; delete z; } } // Multiplication and division else if(t.current()->childOp() == Expression::multiplication || t.current()->childOp() == Expression::division) { // See if one of the nodes is 0, and set n to the node that actually has data, // z to the one containing zero. bool zero = false; bool one = false; if( l->value() == "1" ) { one = true; n = r; z = l; } else if( r->value() == "1" ) { one = true; n = l; z = r; } if( l->value() == "0" ) { zero = true; n = r; z = l; } else if( r->value() == "0" ) { // since we can't call compileError from in this class, we have a special way of handling it: // Leave the children as they are, and set childOp to divbyzero if( t.current()->childOp() == Expression::division ) { t.current()->setChildOp(Expression::divbyzero); return; // no point doing any more since we are going to raise a compileError later anyway. } zero = true; n = l; z = r; } // Now get rid of the useless nodes if(one) { BTreeNode *p = t.current(); // save in order to delete after replaceNode(p,n); t.setCurrent(n); // Delete the old nodes delete p; delete z; } if(zero) { BTreeNode *p = t.current(); p->deleteChildren(); p->setChildOp(Expression::noop); p->setType(number); p->setValue("0"); } } else if( t.current()->childOp() == Expression::bwand || t.current()->childOp() == Expression::bwor || t.current()->childOp() == Expression::bwxor ) { bool zero = false; if( l->value() == "0" ) { zero = true; n = r; z = l; } else if( r->value() == "0" ) { zero = true; n = l; z = r; } // Now get rid of the useless nodes if(zero) { BTreeNode *p = t.current(); QString value; if( p->childOp() == Expression::bwand ) { value = "0"; p->deleteChildren(); p->setChildOp(Expression::noop); p->setType(number); } if( p->childOp() == Expression::bwor || p->childOp() == Expression::bwxor ) { value = n->value(); BTreeNode *p = t.current(); // save in order to delete after replaceNode(p,n); t.setCurrent(n); // Delete the old nodes delete p; delete z; } p->setValue(value); } } if(!t.current()->parent() || t.current() == root) done = true; else { } } }
void Expression::traverseTree( BTreeNode *root, bool conditionalRoot ) { Traverser t(root); t.start(); // special case: if we are starting at the root node then // we are dealing with something of the form variable = 6 // or variable = portb ///TODO reimplement assignments as two branched trees? if ( t.current() == root && !root->hasChildren() && t.current()->childOp() != pin && t.current()->childOp() != notpin && t.current()->childOp() != function && t.current()->childOp() != read_keypad ) { switch(root->type()) { case number: m_pic->assignNum(root->value()); break; case variable: m_pic->assignVar(root->value()); break; default: break; // Should never get here } // no need to traverse the tree as there is none. return; } t.setCurrent(root); if(t.current()->hasChildren()) { // Here we work out what needs evaulating, and in which order. // To minimize register usage, if only one branch needs traversing, // then that branch should be done first. bool evaluateLeft = t.current()->left()->needsEvaluating(); BTreeNode *evaluateFirst; BTreeNode *evaluateSecond; // If both need doing, then it really doesn't matter which we do // first (unless we are looking to do really complex optimizations... // Cases: // - Both need evaluating, // - or left needs doing first, // in both cases we evaluate left, then right. if( evaluateLeft ) { evaluateFirst = t.current()->left(); evaluateSecond = t.current()->right(); } // Otherwise it is best to evaluate right first for reasons given above. else { evaluateFirst = t.current()->right(); evaluateSecond = t.current()->left(); } QString dest1 = mb->dest(); mb->incDest(); QString dest2 = mb->dest(); mb->decDest(); bool evaluated = false; if( evaluateFirst->hasChildren() ) { traverseTree(evaluateFirst); evaluated = true; } else if( isUnaryOp(evaluateFirst->childOp()) ) { doUnaryOp( evaluateFirst->childOp(), evaluateFirst ); evaluated = true; } if ( evaluated ) { // We need to save the result if we are going tro traverse the other // branch, or if we are performing a subtraction in which case the // value wanted in working is not the current value. // But as the optimizer will deal with unnecessary variables anyway, // always save to a register evaluateFirst->setReg( dest1 ); evaluateFirst->setType( variable ); m_pic->saveToReg( dest1 ); } evaluated = false; if( evaluateSecond->hasChildren() ) { mb->incDest(); mb->incDest(); traverseTree(evaluateSecond); evaluated = true; mb->decDest(); mb->decDest(); } else if( isUnaryOp(evaluateSecond->childOp()) ) { doUnaryOp( evaluateSecond->childOp(), evaluateSecond ); evaluated = true; } if ( evaluated ) { evaluateSecond->setReg( dest2 ); evaluateSecond->setType( variable ); m_pic->saveToReg( dest2 ); } } if(t.current()->childOp()==divbyzero) { mistake( Microbe::DivisionByZero ); } // If we are at the top level of something like 'if a == 3 then', then we are ready to put // in the if code, else the expression just evaluates to 0 or 1 if(conditionalRoot && t.current() == root) m_pic->setConditionalCode(m_ifCode, m_elseCode); // Handle operations // (functions are not actually supported) if(isUnaryOp(t.current()->childOp())) doUnaryOp( t.current()->childOp(), t.current() ); else doOp( t.current()->childOp(), t.current()->left(), t.current()->right() ); }
void Expression::compileConditional( const QString & expression, Code * ifCode, Code * elseCode ) { if( expression.contains(QRegExp("=>|=<|=!")) ) { mistake( Microbe::InvalidComparison, expression ); return; } if( expression.contains(QRegExp("[^=><!][=][^=]"))) { mistake( Microbe::InvalidEquals ); return; } // Make a tree to put the expression in. BTreeBase *tree = new BTreeBase(); BTreeNode *root = new BTreeNode(); // parse the expression into the tree buildTree(expression,tree,root,0); // Modify the tree so it is always at the top level of the form (kwoerpkwoep) == (qwopekqpowekp) if ( root->childOp() != equals && root->childOp() != notequals && root->childOp() != gt && root->childOp() != lt && root->childOp() != ge && root->childOp() != le && root->childOp() != pin && root->childOp() != notpin && root->childOp() != read_keypad ) { BTreeNode *newRoot = new BTreeNode(); BTreeNode *oneNode = new BTreeNode(); oneNode->setChildOp(noop); oneNode->setType(number); oneNode->setValue("1"); newRoot->setLeft(root); newRoot->setRight(oneNode); newRoot->setType(unset); newRoot->setChildOp(ge); tree->setRoot(newRoot); root = newRoot; } // compile the tree into assembly code tree->setRoot(root); tree->pruneTree(tree->root(),true); // We might have just a constant expression, in which case we can just always do if or else depending // on whether it is true or false. if( root->childOp() == noop ) { if( root->value().toInt() == 0 ) m_pic->mergeCode( elseCode ); else m_pic->mergeCode( ifCode ); return; } // traverse tree with argument conditionalRoot true // so that 3 == x gets integrated with code for if, repeat until etc... m_ifCode = ifCode; m_elseCode = elseCode; traverseTree(tree->root(),true); // Note deleting the tree deletes all nodes, so the root // doesn't need deleting separately. delete tree; }
void Expression::buildTree( const QString & unstrippedExpression, BTreeBase *tree, BTreeNode *node, int level ) { int firstEnd = 0; int secondStart = 0; bool unary = false; Operation op = noop; QString expression = stripBrackets( unstrippedExpression ); switch(level) { // ==, != case 0: { int equpos = findSkipBrackets(expression, "=="); int neqpos = findSkipBrackets(expression, "!="); if( equpos != -1 ) { op = equals; firstEnd = equpos; secondStart = equpos + 2; } else if( neqpos != -1 ) { op = notequals; firstEnd = neqpos; secondStart = neqpos + 2; } else op = noop; break; } // <, <=, >=, > case 1: { int ltpos = findSkipBrackets(expression, "<"); int lepos = findSkipBrackets(expression, "<="); int gepos = findSkipBrackets(expression, ">="); int gtpos = findSkipBrackets(expression, ">"); // Note: if (for example) "<=" is present, "<" will also be present. This // means that we have to check for "<=" before "<", etc. if( lepos != -1 ) { op = le; firstEnd = lepos; secondStart = lepos + 2; } else if( gepos != -1 ) { op = ge; firstEnd = gepos; secondStart = gepos + 2; } else if( ltpos != -1 ) { op = lt; firstEnd = ltpos; secondStart = ltpos + 1; } else if( gtpos != -1 ) { op = gt; firstEnd = gtpos; secondStart = gtpos + 1; } else op = noop; break; } // +,- case 2: { int addpos = findSkipBrackets(expression, '+'); int subpos = findSkipBrackets(expression, '-'); if( subpos != -1 ) { op = subtraction; firstEnd = subpos; secondStart = subpos + 1; } else if( addpos != -1 ) { op = addition; firstEnd = addpos; secondStart = addpos + 1; } else op = noop; break; } // *,/ case 3: { int mulpos = findSkipBrackets(expression, '*'); int divpos = findSkipBrackets(expression, '/'); if( divpos != -1 ) { op = division; firstEnd = divpos; secondStart = divpos + 1; } else if( mulpos != -1 ) { op = multiplication; firstEnd = mulpos; secondStart = mulpos + 1; } else op = noop; break; } // ^ case 4: { int exppos = findSkipBrackets(expression, '^'); if( exppos != -1 ) { op = exponent; firstEnd = exppos; secondStart = exppos + 1; } else op = noop; break; } // AND, OR, XOR case 5: { int bwAndPos = findSkipBrackets(expression, " AND "); int bwOrPos = findSkipBrackets(expression, " OR "); int bwXorPos = findSkipBrackets(expression, " XOR "); if( bwAndPos != -1 ) { op = bwand; firstEnd = bwAndPos; secondStart = bwAndPos + 5; } else if( bwOrPos != -1 ) { op = bwor; firstEnd = bwOrPos; secondStart = bwOrPos + 4; } else if( bwXorPos != -1 ) { op = bwxor; firstEnd = bwXorPos; secondStart = bwXorPos + 5; } else op = noop; break; } // NOT case 6: { int bwNotPos = findSkipBrackets(expression, " NOT "); if( bwNotPos != -1 ) { op = bwnot; unary = true; firstEnd = bwNotPos; // this line is not needed for unary things/ secondStart = bwNotPos + 5; } else op = noop; break; } } node->setChildOp(op); QString tokens[2]; tokens[0] = expression.left(firstEnd).trimmed(); tokens[1] = expression.mid(secondStart).trimmed(); if( op != noop ) { for( int j = 0; j < 2; j++ ) { BTreeNode *newNode = new BTreeNode(); tree->addNode( node, newNode, (j == 0) ); // we need to strip any brackets from the sub-expression // try each token again at the same level, if they // don't have any of this level's operators, then the function // will go to the next level as below. // For unary opertaions, e.g NOT, we have no special // code for nodes with only one child, so we leave the left // hand child blank and put the rest in the right hand node. if( unary && j == 0 ) { newNode->setValue(""); newNode->setType(number); } else buildTree(tokens[j], tree, newNode, 0 ); } } else { // if there was no relevant operation i.e. " 3*4 / 6" as opposed to " 3*4 + 6" // then just pass the node onto the next parsing level. // unless we are at the lowest level, in which case we have reached a final value. if( level == 6 ) expressionValue(expression,tree,node); else { buildTree(expression,tree,node,level + 1); } } }