ExpressionTree.java

Go to the documentation of this file.
00001 package com.graphbuilder.math;
00002 
00003 import com.graphbuilder.struc.Stack;
00004 
00059 public class ExpressionTree {
00060 
00061     private ExpressionTree() {}
00062 
00068     public static Expression parse(String s) {
00069         if (s == null)
00070             throw new ExpressionParseException("Expression string cannot be null.", -1);
00071 
00072         return build(s, 0);
00073     }
00074 
00075     private static Expression build(String s, int indexErrorOffset) {
00076 
00077         // do not remove (required condition for functions with no parameters, e.g. Pi())
00078         if (s.trim().length() == 0)
00079             return null;
00080 
00081         Stack s1 = new Stack(); // contains expression nodes
00082         Stack s2 = new Stack(); // contains open brackets ( and operators ^,*,/,+,-
00083 
00084         boolean term = true; // indicates a term should come next, not an operator
00085         boolean signed = false; // indicates if the current term has been signed
00086         boolean negate = false; // indicates if the sign of the current term is negated
00087 
00088         for (int i = 0; i < s.length(); i++) {
00089             char c = s.charAt(i);
00090 
00091             if (c == ' ' || c == '\t' || c == '\n')
00092                 continue;
00093 
00094             if (term) {
00095                 if (c == '(') {
00096                     if (negate)
00097                         throw new ExpressionParseException("Open bracket found after negate.", i);
00098 
00099                     s2.push("(");
00100                 }
00101                 else if (!signed && (c == '+' || c == '-')) {
00102                     signed = true;
00103                     if (c == '-') negate = true; // by default negate is false
00104                 }
00105                 else if (c >= '0' && c <= '9' || c == '.') {
00106 
00107                     int j = i + 1;
00108                     while (j < s.length()) {
00109                         c = s.charAt(j);
00110                         if (c >= '0' && c <= '9' || c == '.') j++;
00111 
00112                         // code to account for "computerized scientific notation"
00113                         else if (c == 'e' || c == 'E') {
00114                             j++;
00115 
00116                             if (j < s.length()) {
00117                                 c = s.charAt(j);
00118 
00119                                 if (c != '+' && c != '-' && (c < '0' || c > '9'))
00120                                     throw new ExpressionParseException("Expected digit, plus sign or minus sign but found: " + String.valueOf(c), j + indexErrorOffset);
00121 
00122                                 j++;
00123                             }
00124 
00125                             while (j < s.length()) {
00126                                 c = s.charAt(j);
00127                                 if (c < '0' || c > '9')
00128                                     break;
00129                                 j++;
00130                             }
00131                             break;
00132                         }
00133                         else break;
00134                     }
00135 
00136                     double d = 0;
00137                     String _d = s.substring(i, j);
00138 
00139                     try {
00140                         d = Double.parseDouble(_d);
00141                     } catch (Throwable t) {
00142                         throw new ExpressionParseException("Improperly formatted value: " + _d, i + indexErrorOffset);
00143                     }
00144 
00145                     if (negate) d = -d;
00146                     s1.push(new ValNode(d));
00147                     i = j - 1;
00148 
00149                     negate = false;
00150                     term = false;
00151                     signed = false;
00152                 }
00153                 else if (c != ',' && c != ')' && c != '^' && c != '*' && c != '/' && c != '+' && c != '-' && c != '=') {
00154                     int j = i + 1;
00155                     while (j < s.length()) {
00156                         c = s.charAt(j);
00157                         if (c != ',' && c != ' ' && c != '\t' && c != '\n' && c != '(' && c != ')' && c != '^' && c != '*' && c != '/' && c != '+' && c != '-' && c != '=')
00158                             j++;
00159                         else break;
00160                     }
00161 
00162                     if (j < s.length()) {
00163                         int k = j;
00164                         while (c == ' ' || c == '\t' || c == '\n') {
00165                             k++;
00166                             if (k == s.length()) break;
00167                             c = s.charAt(k);
00168                         }
00169 
00170                         if (c == '(') {
00171                             FuncNode fn = new FuncNode(s.substring(i, j), negate);
00172                             int b = 1;
00173                             int kOld = k + 1;
00174                             while (b != 0) {
00175                                 k++;
00176 
00177                                 if (k >= s.length()) {
00178                                     throw new ExpressionParseException("Missing function close bracket.", i + indexErrorOffset);
00179                                 }
00180 
00181                                 c = s.charAt(k);
00182 
00183                                 if (c == ')') {
00184                                     b--;
00185                                 }
00186                                 else if (c == '(') {
00187                                     b++;
00188                                 }
00189                                 else if (c == ',' && b == 1) {
00190                                     Expression o = build(s.substring(kOld, k), kOld);
00191                                     if (o == null) {
00192                                         throw new ExpressionParseException("Incomplete function.", kOld + indexErrorOffset);
00193                                     }
00194                                     fn.add(o);
00195                                     kOld = k + 1;
00196                                 }
00197                             }
00198                             Expression o = build(s.substring(kOld, k), kOld);
00199                             if (o == null) {
00200                                 if (fn.numChildren() > 0) {
00201                                     throw new ExpressionParseException("Incomplete function.", kOld + indexErrorOffset);
00202                                 }
00203                             }
00204                             else {
00205                                 fn.add(o);
00206                             }
00207                             s1.push(fn);
00208                             i = k;
00209                         }
00210                         else {
00211                             s1.push(new VarNode(s.substring(i, j), negate));
00212                             i = k - 1;
00213                         }
00214                     }
00215                     else {
00216                         s1.push(new VarNode(s.substring(i, j), negate));
00217                         i = j - 1;
00218                     }
00219 
00220                     negate = false;
00221                     term = false;
00222                     signed = false;
00223                 }
00224                 else {
00225                     throw new ExpressionParseException("Unexpected character: " + String.valueOf(c), i + indexErrorOffset);
00226                 }
00227             }
00228             else {
00229                 if (c == ')') {
00230                     Stack s3 = new Stack();
00231                     Stack s4 = new Stack();
00232                     while (true) {
00233                         if (s2.isEmpty()) {
00234                             throw new ExpressionParseException("Missing open bracket.", i + indexErrorOffset);
00235                         }
00236                         Object o = s2.pop();
00237                         if (o.equals("(")) break;
00238                         s3.addToTail(s1.pop());
00239                         s4.addToTail(o);
00240                     }
00241                     s3.addToTail(s1.pop());
00242 
00243                     s1.push(build(s3, s4));
00244                 }
00245                 else if (c == '^' || c == '*' || c == '/' || c == '+' || c == '-') {
00246                     term = true;
00247                     s2.push(String.valueOf(c));
00248                 } 
00249                 // comparison operator: = or ==
00250                 else if (c == '=') {
00251                     final char c_next = s.charAt(i+1);
00252                     // check if it is '=' or '==' symbol. we want to make it the same
00253                     if (c_next == '=') {
00254                         i++;
00255                     }
00256                     term = true;
00257                     s2.push(String.valueOf(c));
00258                 }
00259                 else {
00260                     throw new ExpressionParseException("Expected operator or close bracket but found: " + String.valueOf(c), i + indexErrorOffset);
00261                 }
00262             }
00263         }
00264 
00265         if (s1.size() != s2.size() + 1) {
00266             throw new ExpressionParseException("Incomplete expression.", indexErrorOffset + s.length());
00267         }
00268 
00269         return build(s1, s2);
00270     }
00271 
00272     private static Expression build(Stack s1, Stack s2) {
00273         Stack s3 = new Stack();
00274         Stack s4 = new Stack();
00275 
00276         while (!s2.isEmpty()) {
00277             Object o = s2.removeTail();
00278             Object o1 = s1.removeTail();
00279             Object o2 = s1.removeTail();
00280 
00281             if (o.equals("^")) {
00282                 s1.addToTail(new PowNode((Expression) o1, (Expression) o2));
00283             }
00284             else {
00285                 s1.addToTail(o2);
00286                 s4.push(o);
00287                 s3.push(o1);
00288             }
00289         }
00290 
00291         s3.push(s1.pop());
00292 
00293         while (!s4.isEmpty()) {
00294             Object o = s4.removeTail();
00295             Object o1 = s3.removeTail();
00296             Object o2 = s3.removeTail();
00297 
00298             if (o.equals("*")) {
00299                 s3.addToTail(new MultNode((Expression) o1, (Expression) o2));
00300             }
00301             else if (o.equals("/")) {
00302                 s3.addToTail(new DivNode((Expression) o1, (Expression) o2));
00303             }
00304             else {
00305                 s3.addToTail(o2);
00306                 s2.push(o);
00307                 s1.push(o1);
00308             }
00309         }
00310 
00311         s1.push(s3.pop());
00312 
00313         while (!s2.isEmpty()) {
00314             Object o = s2.removeTail();
00315             Object o1 = s1.removeTail();
00316             Object o2 = s1.removeTail();
00317 
00318             if (o.equals("+")) {
00319                 s1.addToTail(new AddNode((Expression) o1, (Expression) o2));
00320             }
00321             else if (o.equals("-")) {
00322                 s1.addToTail(new SubNode((Expression) o1, (Expression) o2));
00323             }
00324             else if (o.equals("=")) {
00325                 s1.addToTail(new EqualNode((Expression) o1, (Expression) o2));
00326             }
00327             else {
00328                 // should never happen
00329                 throw new ExpressionParseException("Unknown operator: " + o, -1);
00330             }
00331         }
00332 
00333         return (Expression) s1.pop();
00334     }
00335 }

Generated on 5 May 2015 for HPCVIEWER by  doxygen 1.6.1