Package org.jmathml

Source Code of org.jmathml.TextToASTNodeMathParser2

package org.jmathml;

import org.jmathml.ASTFunction.ASTFunctionType;
import org.jmathml.ASTLogical.ASTLogicalType;
import org.jmathml.ASTRelational.ASTRelationalType;
import org.jmathml.TokenStream.TokenIterator;

/**
* Convenience method to parse free text math into an ASTNode. The style of math
* is a C-style syntax, e.g.,<br/>
* . The parsing supports standard arithmetical operations and function calls.
* E.g.,
*
* <ul>
* <li>4 + 2
* <li>sin(pi / 2) // or any other trig function
* <li>log(9,81) // = 2
* <li>root(4,81) //=3
* <li>exp(t)
*
* </ul>
*
*
* <p>
* In addition, the strings <code>pi</code>, <code>NaN</code>,
* <code>infinity</code> and <code>exponentiale</code> are translated into the
* appropriate constants.
* </p>
*
* Functions not supported by this library ( see ASTFunctionType for supported
* functions ) will be parsed into a function call, which will not be evaluable.
* E.g., <br/>
*
* <pre>
* myfunction(a, b)
* </pre>
*
* can be turned into an ASTNode, but will not be evaluable.
*
* @param math
*            A <code>String</code> of math
* @return An {@link ASTNode}. This will be an {@link ASTRootNode} with the math
*         nodes as children. E.g., the string
*
*         <pre>
* 2 * (4 / 5)
* </pre>
*
*         will return the structure:
*
*         <pre>
*  ASTRootNode
*       ASTimes
*            ASTCn(2)
*            ASTDivide
*                 ASTCn(4)
*                 ASTCn(5)
* </pre>
*/
public class TextToASTNodeMathParser2 {

  /**
   * Parses a C -style math string into an ASTNode
   * @param mathString
   * @param toAdd An {@link ASTRootNode}
   * @return
   * @throws RuntimeException if mathString cannot be parsed due to incorrect syntax.
   */
  public ASTNode parseString(String mathString, ASTNode toAdd) {

    // get rid of all whitespace
    String mathToParse = mathString.replaceAll(" ", "");

    Tokenizer tokeniser = new Tokenizer();
    TokenStream tokens = tokeniser.tokenize(mathToParse).trimExtraneousParentheses();
    return parseTokens(tokens, toAdd);
  }

  ASTNode parseTokens(TokenStream tokens, ASTNode toAdd) {
    // iterate over chars, find lowest precedence operator
    int tokIndx = 0;
    Token currLowestPrecedenceToken = null;
    int currLowestPrecedencTokenIndex = -1; // index of any operator in curr
    // string
    int currLowestPrecedence = 10; // higher than any other
    int parDepth = 0; // parenthesis depth
    TokenIterator tokIt = tokens.iterator();
    while (tokIt.hasNext()) {
      Token tok = tokIt.next();
      // keep track of parentheses,
      if (tok.getString().equals("(")) {
        parDepth++;
      } else if (tok.getString().equals(")")) {
        parDepth--;
      }

      // only parse operators if they're not in brackets
      if (parDepth == 0) {
        int precedence = getPrecedenceForToken(tok, tokIt);
        if (precedence <= currLowestPrecedence) {
          currLowestPrecedenceToken = tok;
          currLowestPrecedence = precedence;
          currLowestPrecedencTokenIndex = tokIndx;
        }
      }
      tokIndx++;
    }
    ASTNode rc = null;

    if (currLowestPrecedencTokenIndex != -1) {
      rc = createNodeForLowestPrecedence(currLowestPrecedenceToken);
      if (rc != null)
        toAdd.addChildNode(rc);
      else
        rc = toAdd;
      if (currLowestPrecedenceToken.isOperator()
          && !currLowestPrecedenceToken.isUnaryMinus()) {
        TokenStream left = tokens.subList(0,
            currLowestPrecedencTokenIndex).trimExtraneousParentheses();
        TokenStream right = tokens.subList(
            currLowestPrecedencTokenIndex + 1, tokens.size())
            .trimExtraneousParentheses();
        parseTokens(left, rc);
        parseTokens(right, rc);
      } else if (currLowestPrecedenceToken.isUnary() ) {
        TokenStream child = tokens.subList(
            currLowestPrecedencTokenIndex + 1, tokens.size())
            .trimExtraneousParentheses();
        parseTokens(child, rc);
      }

     else if (currLowestPrecedenceToken.isNumber()) {
        return rc;
      } else if (currLowestPrecedenceToken.isIdentifier()) {
        return rc;
      }

    }

    return rc;
  }

  private ASTNode createNodeForLowestPrecedence(Token token) {
    String tokenStr = token.getString();
    if (tokenStr.equals("+"))
      return new ASTPlus();
    else if (tokenStr.equals("-")) {
      return new ASTMinus();
    } else if (tokenStr.equals("*"))
      return new ASTTimes();
    else if (token.isConstant()) {
      ASTNumber num = ASTNumber.getConstant(tokenStr);

      return num;
    } else if (token.isFunction()) {
      ASTNode fn = ASTFunction.createFunctionNode(ASTFunction
          .getFunctionTypeForName(tokenStr));
      if (fn.getType().equals(ASTFunctionType.MISCELLANEOUS)) {
        ASTSymbol sym = SymbolRegistry.getInstance().createSymbolFor(token.getString());
        if(sym!=null){
          fn=sym;
        }
      }
      return fn;
    } else if (token.isNumber()) {
      ASTNumber cn = null;
      if (token.isInteger()) {
        cn = ASTNumber.createNumber(Integer.parseInt(tokenStr));
      } else {
        cn = ASTNumber.createNumber(Double.parseDouble(tokenStr));
      }

      return cn;
    } else if (token.isIdentifier()) {
      ASTCi ci = new ASTCi(tokenStr);

      return ci;
    }

    else if (tokenStr.equals("/"))

      return new ASTDivide();
    else if (tokenStr.equals("^"))
      return new ASTPower();
    else if (tokenStr.equals(">"))
      return new ASTRelational(ASTRelationalType.GT);
    else if (tokenStr.equals("<"))
      return new ASTRelational(ASTRelationalType.LT);
    else if (tokenStr.equals("<="))
      return new ASTRelational(ASTRelationalType.LEQ);
    else if (tokenStr.equals(">="))
      return new ASTRelational(ASTRelationalType.GEQ);
    else if (tokenStr.equals("=="))
      return new ASTRelational(ASTRelationalType.EQ);
    else if (tokenStr.equals("!="))
      return new ASTRelational(ASTRelationalType.NEQ);
    else if (tokenStr.equals("||"))
      return new ASTLogical(ASTLogicalType.OR);
    else if (tokenStr.equals("&&"))
      return new ASTLogical(ASTLogicalType.AND);
    else if (tokenStr.equals("!"))
      return new ASTLogical(ASTLogicalType.NOT);
    else if (tokenStr.equals(","))
      return null;
    else
      return new ASTCi("");

  }

  private int getPrecedenceForToken(Token tok, TokenIterator tokIt) {
    String test = tok.getString();

    if (test.equals("+") || test.equals("-")) {
      if (test.equals("-")) {

        if (tokIt.previous() == null || tokIt.previous().isOperator()
            || tokIt.previous().isLPar()) {
          tok.setIsUnaryMinus(true);
          return 7;
        } else {
          return 4;
        }
      } else {
        return 4;
      }
    }

    else if (tok.isRelationalOperator()) {
      return 3;
    } else if (tok.isLogicalOperator()) {
      return 2;
    } else if (test.equals("*") || test.equals("/")) {
      return 5;
    } else if (test.equals("^")) {
      return 6;
    } else if (test.equals(",")) {
      return 1;
    } else if (tok.isIdentifier()) {
      if (tokIt.peek() != null && tokIt.peek().isLPar()) {
        tok.setIsFunction(true);
        return 8;
      } else {
        return 9;
      }

    } else if (tok.isNumber()) {

      return 9;

    } else
      return 12;
  }

}
TOP

Related Classes of org.jmathml.TextToASTNodeMathParser2

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.