package jmathlib.core.tokens; import jmathlib.core.interpreter.*; import java.util.Enumeration; /**Class implementing a tree where each node has a variable no of children*/ public class Expression extends OperandToken { /**array containing the expressions operands*/ private OperandToken[] children; /**The number of operands*/ private int noChildren = 0; /**the operator being held within the node*/ private OperatorToken data; /**Stores the index of the child being executed*/ private int childNo; /**Default constructor - creates an expression with a null operator and no operands*/ public Expression() { super(50);// , "EXPRESSION"); data = null; children = null; } /**Creates an expression with no operands @param _data = the expressions operator*/ public Expression(OperatorToken _data) { super(50); data = _data; children = null; } /**Creates an expression with one operand @param _data = the expressions operator @param operand = the expressions operand*/ public Expression(OperatorToken _data, OperandToken operand) { super(50); data = _data; children = new OperandToken[1]; children[0] = operand; noChildren = 1; } /**Creates an expression with two operands @param _data = the expressions operator @param left = the left hand operand @param right = the right hand operand*/ public Expression(OperatorToken _data, OperandToken left, OperandToken right) { super(50); data = _data; children = new OperandToken[2]; children[0] = left; children[1] = right; noChildren = 2; } /**Creates an expression with three operands @param _data = the expressions operator @param first = the left hand operand @param second = the middle operand @param third = the right hand operand*/ public Expression(OperatorToken _data, OperandToken op1, OperandToken op2, OperandToken op3) { super(50); data = _data; children = new OperandToken[3]; children[0] = op1; children[1] = op2; children[2] = op3; noChildren = 3; } /**Creates an expression with an array of operands @param data = the expressions operator @param operands = and array of operands @param _noChildren = the number of operands*/ public Expression(OperatorToken _data, OperandToken[] _children, int _noChildren) { super(50); data = _data; children = _children; noChildren = _noChildren; } /**retrieves the data object @return the operator assigned to the expression*/ public OperatorToken getData() { return data; } /**@return the number of children*/ public int getNumberOfChildren() { return noChildren; } /**Sets the operator of the expression @param _data = the expressions operator*/ public void setData(OperatorToken _data) { data = _data; } /**Get the a child with a specific index @param childNo = the index of the operand @return the specified operand*/ public OperandToken getChild(int childNo) { return children[childNo]; } /**set the child with a specific index @param childNo = the index of the child @param child = the value to set it to */ public void setChild(int childNo, OperandToken child) { children[childNo] = child; } /**Get the first child of this node @return the first operand*/ public OperandToken getLeft() { return children[0]; } /**Get the last child of this node @return the last operand*/ public OperandToken getRight() { return children[noChildren - 1]; } /**insert a child node on this Expression if _data is a Expression then it just gets added to the current node Otherwise a new node is created and this is added to the current node @param _data = the operand to add*/ public void insert(Token _data) { OperandToken subExpression; //if the item is a Expression node then just add it to the Expression //without creating a new node if(_data instanceof Expression) subExpression = ((Expression)_data); else if(_data instanceof OperandToken) subExpression = ((OperandToken)_data); else subExpression = new Expression(((OperatorToken)_data)); // check if no of children exceeds dimension of array if (children != null) { if (noChildren >= children.length ) { int childrenOldLength = children.length; ErrorLogger.debugLine("Expression: expand children array "+childrenOldLength); OperandToken[] childrenTemp = new OperandToken[childrenOldLength]; // save old children array to temporary array for (int i=0; i<childrenOldLength; i++) { childrenTemp[i] = children[i]; } // create new children array: size +1 children = new OperandToken[ childrenOldLength + 1 ]; // restore temporary array to new children array for (int i=0; i<childrenOldLength; i++) { children[i] = childrenTemp[i]; } } } else { // create first children. Expression didn't have children before children = new OperandToken[1]; } children[noChildren] = subExpression; noChildren++; } /**evaluate the data item held within this node @param ops = the expressions operands @return the result of the expression as an OperandToken*/ public OperandToken evaluate(Token[] ops, GlobalValues globals) { OperandToken result = null; ErrorLogger.debugLine("Expression: evaluate " + toString()); // for assignments (e.g.: a=3+3) only evaluate the right side if(data instanceof AssignmentOperatorToken) { // data is an assignment (e.g. a=3 or [x,t]=func(....) or a(:,3) = [...] ) OperandToken left = children[0]; OperandToken right = children[1]; //ErrorLogger.debugLine("Expression: evaluate assignment"); //ErrorLogger.debugLine("Expression: evaluate assignment "+left.toString()); //ErrorLogger.debugLine("Expression: evaluate assignment "+right.toString()); /* Check how many arguments are on the LEFT-hand side and pass this */ /* number to a possible function token on the RIGHT-hand side. */ if ((left instanceof MatrixToken) && (right instanceof FunctionToken) ) { int x = 1; x = ((MatrixToken)left).getSizeX(); ErrorLogger.debugLine("Expression: [ "+x+" ]=func()"); FunctionToken func = ((FunctionToken)right); func.setNoOfLeftHandArguments(x); children[1] = func; } // evaluate right-hand argument (e.g. a= 2+3) children[1] = right.evaluate(null, globals); //check LEFT side for submatrices (e.g. a(1,:) = [1,2,3] ) if (left instanceof FunctionToken) { // A function can never be valid on the left side of an expression // therefore this MUST be variable // (e.g. a(3,2)=5 ) FunctionToken function = (FunctionToken)left; ErrorLogger.debugLine("Expression: eval: function/variable on left side"); // create variable token from function data children[0] = new VariableToken(function.getName(), function.getOperands()); } } else if(data instanceof UnaryOperatorToken && (((UnaryOperatorToken)data).getValue() == '+' || ((UnaryOperatorToken)data).getValue() == '-' ) ) { //!!! is this line really necessary !!!!??? //do nothing } else if(data instanceof DotOperatorToken) { // (e.g. a.getLambda() or a.color or a.argument1) // don't evaluate children. } else { // the data of this expression is null or of no interest // evaluate all children boolean dispB = false; for(int i = 0; i < noChildren; i++) { if(children[i] != null) { ErrorLogger.debugLine("Expression: child: "+children[i].toString()); //ErrorLogger.debugLine("Expression: globals: "+globals); // check if result should be displayed dispB = children[i].isDisplayResult(); // evaluate children children[i] = children[i].evaluate(null, globals); // check if result should be displayed before if (dispB && children[i]!=null) children[i].setDisplayResult(true); } } // end for } // ****************************************************************************** // evaluate operator with its children if(data != null) { // display "a=11", do not display "a=11;" if (isDisplayResult() && (data instanceof AssignmentOperatorToken)) data.setDisplayResult(true); // evaluate expression result = data.evaluate(children, globals); /* set the display state of the result, if the original expression also has the display state set */ if (isDisplayResult() && (result != null)) result.setDisplayResult(true); } else { // operator data is null // the result of this expression might be hidden in the first child // (e.g. (2+3)*4 here (2+3) will be hidden inside an expression) result = children[0]; /*store operand of expressions without data in "ans" variable*/ for(int i = 0; i < noChildren; i++) { if (children[i]!=null) { ErrorLogger.debugLine("Expression: store ans "+children[i].toString()); Variable answervar = globals.createVariable("ans"); answervar.assign(children[i]); } /* display the result this expression in the user console*/ if ((children[i] != null) && children[i].isDisplayResult() ) { //ErrorLogger.debugLine("Expression: !!!!!!!!! showResult"); globals.getInterpreter().displayText(" ans = "+ children[i].toString(globals)); } } } return result; } // end evaluate /**Converts the expression to a string @return string representation of expression */ public String toString() { String result = ""; if (data != null) { result = data.toString(children); } else { if (children == null) return ""; if (children[0] != null) result = children[0].toString(); } return result; } /**Builds an expression tree @param op = the expressions operator @param left = the left hand operand @param right = the right hand operand @return the expression created*/ private Expression buildTree(OperatorToken op, OperandToken left, OperandToken right) { Expression tree = new Expression(op); tree.insert(left); tree.insert(right); return tree; } /**Checks if this operand is a numeric value @return true if this is a number, false if it's an algebraic expression*/ public boolean isNumeric() { boolean numeric = true; for(int childNo = 0; childNo < noChildren; childNo++) { if(!children[childNo].isNumeric()) numeric = false; } return numeric; } /**@return the index number of the current child expression*/ public int getChildNo() { return childNo; } /**@return the expression being executed*/ public OperandToken getCurrentChild() { return children[childNo]; } /**checks if this is a leaf node of the expression tree @return false if this expression has any children*/ public boolean isLeaf() { return (noChildren == 0); } /**function to access all children of a node within the expression tree @return all the nodes children as a enumeration*/ public Enumeration getChildren() { return new ExpressionEnumeration(); } class ExpressionEnumeration implements Enumeration { private int index; public ExpressionEnumeration() { index = 0; } public boolean hasMoreElements() { return (index < noChildren); } public Object nextElement() { OperandToken element = children[index]; index++; return element; } } }