summaryrefslogtreecommitdiffstats
path: root/microbe/expression.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'microbe/expression.cpp')
-rw-r--r--microbe/expression.cpp842
1 files changed, 842 insertions, 0 deletions
diff --git a/microbe/expression.cpp b/microbe/expression.cpp
new file mode 100644
index 0000000..33fd514
--- /dev/null
+++ b/microbe/expression.cpp
@@ -0,0 +1,842 @@
+/***************************************************************************
+ * Copyright (C) 2004-2005 by Daniel Clarke *
+ * *
+ * 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 "btreebase.h"
+#include "btreenode.h"
+#include "expression.h"
+#include "traverser.h"
+#include "parser.h"
+#include "pic14.h"
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <qregexp.h>
+
+Expression::Expression( PIC14 *pic, Microbe *master, SourceLine sourceLine, bool suppressNumberTooBig )
+ : m_sourceLine(sourceLine)
+{
+ m_pic = pic;
+ mb = master;
+ m_bSupressNumberTooBig = suppressNumberTooBig;
+}
+
+Expression::~Expression()
+{
+}
+
+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::doOp( Operation op, BTreeNode *left, BTreeNode *right )
+{
+ QString lvalue;
+ if(left->reg().isEmpty())
+ lvalue = left->value();
+ else
+ lvalue = left->reg();
+
+ QString rvalue;
+ if(right->reg().isEmpty())
+ rvalue = right->value();
+ else
+ rvalue = right->reg();
+
+ // Handle if stuff
+ PIC14::LocationType leftType;
+ switch ( left->type() )
+ {
+ case number:
+ leftType = PIC14::num;
+ break;
+
+ case variable:
+ leftType = PIC14::var;
+ break;
+
+ case working:
+ leftType = PIC14::work;
+ break;
+
+ case unset:
+ case extpin:
+ case keypad:
+ kdError() << k_funcinfo << "Bad left->type(): " << left->type() << endl;
+ };
+
+ PIC14::LocationType rightType;
+ switch ( right->type() )
+ {
+ case number:
+ rightType = PIC14::num;
+ break;
+
+ case variable:
+ rightType = PIC14::var;
+ break;
+
+ case working:
+ rightType = PIC14::work;
+ break;
+
+ case unset:
+ case extpin:
+ case keypad:
+ kdError() << k_funcinfo << "Bad right->type(): " << right->type() << endl;
+ };
+
+ switch(op)
+ {
+ case equals: m_pic->equal( lvalue, rvalue, leftType, rightType ); break;
+ case notequals: m_pic->notEqual( lvalue, rvalue, leftType, rightType ); break;
+ case lt: m_pic->lessThan( lvalue, rvalue, leftType, rightType ); break;
+ case gt: m_pic->greaterThan( lvalue, rvalue, leftType, rightType ); break;
+ case le: m_pic->lessOrEqual( lvalue, rvalue, leftType, rightType ); break;
+ case ge: m_pic->greaterOrEqual( lvalue, rvalue, leftType, rightType ); break;
+
+ case addition: m_pic->add( lvalue, rvalue, leftType, rightType ); break;
+ case subtraction: m_pic->subtract( lvalue, rvalue, leftType, rightType ); break;
+ case multiplication: m_pic->mul( lvalue, rvalue, leftType, rightType ); break;
+ case division: m_pic->div( lvalue, rvalue, leftType, rightType ); break;
+
+ case bwand: m_pic->bitwise( bwand, lvalue, rvalue, leftType, rightType ); break;
+ case bwor: m_pic->bitwise( bwor, lvalue, rvalue, leftType, rightType ); break;
+ case bwxor: m_pic->bitwise( bwxor, lvalue, rvalue, leftType, rightType ); break;
+ case bwnot: m_pic->bitwise( bwnot, lvalue, rvalue, leftType, rightType ); break;
+
+ default: break;
+ }
+}
+
+void Expression::buildTree( const QString & unstrippedExpression, BTreeBase *tree, BTreeNode *node, int level )
+{
+ int firstEnd = 0;
+ int secondStart = 0;
+ bool unary = false;
+ Operation op;
+ 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).stripWhiteSpace();
+ tokens[1] = expression.mid(secondStart).stripWhiteSpace();
+
+ 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);
+ }
+ }
+}
+
+void Expression::doUnaryOp(Operation op, BTreeNode *node)
+{
+ /* Note that this isn't for unary operations as such,
+ rather for things that are operations that have no direct children,
+ e.g. portx.n is high, and functionname(args)*/
+
+ if ( op == pin || op == notpin )
+ m_pic->Spin( m_pic->toPortPin( node->value() ), (op==notpin) );
+
+ else if ( op == read_keypad )
+ m_pic->Skeypad( mb->variable( node->value() ) );
+}
+
+void Expression::compileExpression( const QString & expression )
+{
+ // 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);
+ // compile the tree into assembly code
+ tree->setRoot(root);
+ tree->pruneTree(tree->root());
+ traverseTree(tree->root());
+
+ // Note deleting the tree deletes all nodes, so the root
+ // doesn't need deleting separately.
+ delete tree;
+ return;
+}
+
+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;
+}
+
+bool Expression::isUnaryOp(Operation op)
+{
+ return op == pin || op == notpin || op == function || op == read_keypad;
+}
+
+
+void Expression::mistake( Microbe::MistakeType type, const QString & context )
+{
+ mb->compileError( type, context, m_sourceLine );
+}
+
+int Expression::findSkipBrackets( const QString & expr, char ch, int startPos)
+{
+ bool found = false;
+ int i = startPos;
+ int bracketLevel = 0;
+ while(!found)
+ {
+ if(expr[i].latin1() == '\'')
+ {
+ if( i + 2 < int(expr.length()) )
+ {
+ if( expr[i+2].latin1() == '\'' )
+ {
+ i = i + 2;
+ found = true;
+ }
+ }
+ }
+
+ if(expr[i].latin1() == '(') bracketLevel++;
+ else if(expr[i].latin1() == ')') bracketLevel--;
+
+ if( bracketLevel == 0 )
+ {
+ if(expr[i].latin1() == ch) found = true;
+ else i++;
+ }
+ else i++;
+
+ if( i >= int(expr.length()) )
+ {
+ found = true;
+ i = -1;
+ }
+ }
+ return i;
+}
+
+int Expression::findSkipBrackets( const QString & expr, QString phrase, int startPos)
+{
+ bool found = false;
+ int i = startPos;
+ int bracketLevel = 0;
+ while(!found)
+ {
+ if(expr[i].latin1() == '\'')
+ {
+ if( i + 2 < int(expr.length()) )
+ {
+ if( expr[i+2].latin1() == '\'' )
+ {
+ i = i + 2;
+ found = true;
+ }
+ }
+ }
+
+ if(expr[i].latin1() == '(') bracketLevel++;
+ else if(expr[i].latin1() == ')') bracketLevel--;
+
+ if( bracketLevel == 0 )
+ {
+ if(expr.mid(i,phrase.length()) == phrase) found = true;
+ else i++;
+ }
+ else i++;
+
+ if( i >= int(expr.length()) )
+ {
+ found = true;
+ i = -1;
+ }
+ }
+ return i;
+}
+
+QString Expression::stripBrackets( QString expression )
+{
+ bool stripping = true;
+ int bracketLevel = 0;
+ int i = 0;
+ expression = expression.stripWhiteSpace();
+ while(stripping)
+ {
+ if( expression.at(i) == '(' ) bracketLevel++;
+ else if( expression.at(i) == ')' )
+ {
+ if( i == int(expression.length() - 1) && bracketLevel == 1)
+ {
+ expression = expression.mid(1,expression.length() - 2).stripWhiteSpace();
+ }
+ bracketLevel--;
+ }
+ if( i == int(expression.length() - 1) && bracketLevel > 0 )
+ {
+ mistake( Microbe::MismatchedBrackets, expression );
+ // Stray brackets might cause the expressionession parser some problems,
+ // so we just avoid parsing anything altogether
+ expression = "";
+ stripping = false;
+ }
+ i++;
+ if( bracketLevel == 0 ) stripping = false;
+ }
+ return expression;
+}
+
+void Expression::expressionValue( QString expr, BTreeBase */*tree*/, BTreeNode *node)
+{
+ /* The "end of the line" for the expression parsing, the
+ expression has been broken down into the fundamental elements of expr.value()=="to"||
+ variable, number, special etc... so we now just set value and type */
+
+
+
+ /* Alternatively we might have a function call
+ e.g. somefunction(3,potatoes,hairstyle + 6)
+ In which case we need to call back to parseExpr to process the arguments,
+ saving them on the basic stack then making the function call.
+ Of course we also need to mark the terminal node type as a function.
+ */
+ expr = expr.stripWhiteSpace();
+
+ // My intention is so that these error checks are ordered
+ // so that e.g. for x = 3 it picks up the = rather than the spaces first.
+
+
+ expr = mb->alias(expr);
+ ExprType t = expressionType(expr);
+
+
+ // See if it is a single qouted character, e.g. 'A'
+ if( expr.left(1) == "\'" && expr.right(1) == "\'" )
+ {
+ if( expr.length() == 3 ) // fall through to report as unknown variable if not of form 'x'
+ {
+ // If so, turn it into a number, and use the ASCII code as the value
+ t = number;
+ expr = QString::number(expr[1].latin1());
+ }
+ }
+
+ // Check for the most common mistake ever!
+ if(expr.contains("="))
+ mistake( Microbe::InvalidEquals );
+ // Check for reserved keywords
+ if(expr=="to"||expr=="step"||expr=="then")
+ mistake( Microbe::ReservedKeyword, expr );
+
+ // Check for empty expressions, or expressions contating spaces
+ // both indicating a Mistake.
+ if(expr.isEmpty())
+ mistake( Microbe::ConsecutiveOperators );
+ else if(expr.contains(QRegExp("\\s")) && t!= extpin)
+ mistake( Microbe::MissingOperator );
+
+ if( t == variable && !mb->isVariableKnown(expr) && !m_pic->isValidPort( expr ) && !m_pic->isValidTris( expr ) )
+ mistake( Microbe::UnknownVariable, expr );
+
+ if ( mb->isVariableKnown(expr) && !mb->variable(expr).isReadable() )
+ mistake( Microbe::WriteOnlyVariable, expr );
+
+ node->setType(t);
+
+ // Since we currently only implement 8 bit unsigned integers, we should disallow
+ // anything outside the range [0-255].
+ if( t == number && !m_bSupressNumberTooBig && (expr.toInt() > 255) )
+ {
+ mistake( Microbe::NumberTooBig );
+ }
+
+ // if there was a pin, we need to decocde it.
+ // For now and sacrificing syntax error checking
+ // we just look for the word "is" then "high" or "low".
+ if( t == extpin )
+ {
+ bool NOT;
+ int i = expr.find("is");
+ if(i > 0)
+ {
+ NOT = expr.contains("low");
+ if(!expr.contains("high") && !expr.contains("low"))
+ mistake( Microbe::HighLowExpected, expr );
+ expr = expr.left(i-1);
+ }
+ else NOT = false;
+ node->setChildOp(NOT?notpin:pin);
+ }
+
+ else if ( t == keypad )
+ node->setChildOp( read_keypad );
+
+ node->setValue(expr);
+}
+
+ExprType Expression::expressionType( const QString & expression )
+{
+ // So we can't handle complex expressions yet anyway,
+ // let's just decide whether it is a variable or number.
+
+ // Thanks to the convention that variable names must not
+ // begin with a number this is extremely simple to do!
+
+ /* But now there is a catch, because there can also be
+ things that have a first character alpha, but are of the form
+ "portb.3 is high", general syntax: portx.n is <high|low>
+ additionally, there can be things that are just porta.6, which just return the truth of that port.
+ In reality it is just:
+ portx.n is high === portx.n
+ portx.n is low === !(portx.n)
+ These types of expression can be identified by the fact
+ that they should be the only things that contain a '.'
+ */
+
+ /* Note that at the moment, literalToInt returns -1 if it is
+ not literal so isLiteral is redundant, but this may change if say
+ negative numbers are implemented
+ */
+
+ int value = Parser::literalToInt(expression);
+ if ( value != -1 )
+ return number;
+
+ if( expression.contains('.') )
+ return extpin;
+
+ if ( mb->variable( expression ).type() == Variable::keypadType )
+ return keypad;
+
+ return variable;
+}
+
+QString Expression::processConstant( const QString & expr, bool * isConstant )
+{
+ bool temp;
+ if (!isConstant)
+ isConstant = &temp;
+
+ QString code;
+
+ // Make a tree to put the expression in.
+ BTreeBase *tree = new BTreeBase();
+ BTreeNode *root = new BTreeNode();
+
+ // parse the expression into the tree
+ buildTree(expr,tree,root,0);
+ // compile the tree into assembly code
+ tree->setRoot(root);
+ tree->pruneTree(tree->root());
+ //code = traverseTree(tree->root());
+ // Look to see if it is a number
+ if( root->type() == number )
+ {
+ code = root->value();
+ *isConstant = true;
+ }
+ else
+ {
+ code = "";
+ *isConstant = false;
+ }
+
+ // Note deleting the tree deletes all nodes, so the root
+ // doesn't need deleting separately.
+ delete tree;
+ return code;
+}