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 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() ); }