Package com.wesleyhome.math.equation

Source Code of com.wesleyhome.math.equation.InfixEvaluator

package com.wesleyhome.math.equation;

import static com.wesleyhome.math.equation.EquationGrammerUtil.getOperatorFromToken;
import static com.wesleyhome.math.equation.EquationGrammerUtil.getType;
import static com.wesleyhome.math.equation.grammer.EquationGrammarParser.DECIMAL;
import static com.wesleyhome.math.equation.grammer.EquationGrammarParser.DIV;
import static com.wesleyhome.math.equation.grammer.EquationGrammarParser.FRACTION;
import static com.wesleyhome.math.equation.grammer.EquationGrammarParser.FSEP;
import static com.wesleyhome.math.equation.grammer.EquationGrammarParser.IDENT;
import static com.wesleyhome.math.equation.grammer.EquationGrammarParser.INTEGER;
import static com.wesleyhome.math.equation.grammer.EquationGrammarParser.LPAREN;
import static com.wesleyhome.math.equation.grammer.EquationGrammarParser.MINUS;
import static com.wesleyhome.math.equation.grammer.EquationGrammarParser.MULT;
import static com.wesleyhome.math.equation.grammer.EquationGrammarParser.PLUS;
import static com.wesleyhome.math.equation.grammer.EquationGrammarParser.POW;
import static com.wesleyhome.math.equation.grammer.EquationGrammarParser.RPAREN;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import java.util.Queue;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
import com.wesleyhome.math.equation.grammer.EquationGrammarParser.NegexpContext;

class InfixEvaluator {

  private final String expression;

  InfixEvaluator(final String expression) {
    this.expression = expression;
  }

  EquationNode getNode(final TerminalNode token) {
    Queue<TerminalNode> queue = new ArrayDeque<TerminalNode>();
    queue.add(token);
    return getNode(queue);
  }

  EquationNode getNode(final Queue<TerminalNode> tokenList) {
    Deque<EquationNode> outputQueue = new ArrayDeque<EquationNode>();
    Deque<Operator> operatorStack = new ArrayDeque<Operator>();
    while (!tokenList.isEmpty()) {
      TerminalNode nextNode = tokenList.poll();
      int type = getType(nextNode);
      switch (type) {
        case IDENT:
          TerminalNode peek = tokenList.peek();
          if (peek != null && getType(peek) == LPAREN) {
            String functionName = nextNode.getText();
            // Function call
            Queue<TerminalNode> newTokenList = new ArrayDeque<TerminalNode>();
            int passParens = 0;
            tokenList.poll();
            nextNode = tokenList.poll();
            int type2 = getType(nextNode);
            while (true) {
              if (type2 == LPAREN) {
                passParens++;
              }
              if (type2 == RPAREN) {
                if (passParens == 0) {
                  break;
                }
                passParens--;
              }
              newTokenList.add(nextNode);
              nextNode = tokenList.poll();
              type2 = getType(nextNode);
            }
            outputQueue.push(getFunctionNode(functionName, newTokenList));
          } else {
            outputQueue.push(new VariableNode(nextNode.getText()));
          }
          break;
        case INTEGER:
        case DECIMAL:
          outputQueue.push(new NumericNode(nextNode.getText()));
          break;
        case FRACTION:
          outputQueue.push(new FractionNode(nextNode.getText()));
          break;
        case MINUS: {
          ParseTree parent = nextNode.getParent();
          if (parent instanceof NegexpContext) {
            nextNode = tokenList.poll();
            EquationNode node = null;
            if (LPAREN == getType(nextNode)) {
              Queue<TerminalNode> newTokenList = new ArrayDeque<TerminalNode>();
              int passParens = 0;
              nextNode = tokenList.poll();
              int type2 = getType(nextNode);
              while (true) {
                if (type2 == LPAREN) {
                  passParens++;
                }
                if (type2 == RPAREN) {
                  if (passParens == 0) {
                    break;
                  }
                  passParens--;
                }
                newTokenList.add(nextNode);
                nextNode = tokenList.poll();
                type2 = getType(nextNode);
              }
              node = getNode(newTokenList);
            } else {
              node = getNode(nextNode);
            }
            outputQueue.push(new NegateNode(node));
            break;
          }
        }
        case PLUS:
        case MULT:
        case DIV:
        case POW: {
          Operator o1 = getOperatorFromToken(nextNode);
          Operator o2 = operatorStack.peek();
          while (o2 != null
            && (o1.isLeftAssociative() && o1.getPrecedence() <= o2.getPrecedence() || o1.getPrecedence() < o2.getPrecedence())) {
            popExpression(outputQueue, operatorStack.pop());
            o2 = operatorStack.peek();
          }
          operatorStack.push(o1);
          break;
        }
        case LPAREN: {
          Queue<TerminalNode> newTokenList = new ArrayDeque<TerminalNode>();
          int passParens = 0;
          nextNode = tokenList.poll();
          int type2 = getType(nextNode);
          while (true) {
            if (type2 == LPAREN) {
              passParens++;
            }
            if (type2 == RPAREN) {
              if (passParens == 0) {
                break;
              }
              passParens--;
            }
            newTokenList.add(nextNode);
            nextNode = tokenList.poll();
            type2 = getType(nextNode);
          }
          outputQueue.push(getNode(newTokenList));
        }
      }
    }
    while (!operatorStack.isEmpty()) {
      Operator pop = operatorStack.pop();
      popExpression(outputQueue, pop);
    }
    return outputQueue.pop();
  }

  public void popExpression(final Deque<EquationNode> outputQueue, final Operator o2) {
    EquationNode rhs = outputQueue.poll();
    EquationNode lhs = outputQueue.poll();
    outputQueue.push(new OperationNode(lhs, o2, rhs));
  }

  private FunctionNode getFunctionNode(final String functionName, final Queue<TerminalNode> newTokenList) {
    Queue<Queue<TerminalNode>> parameterList = split(newTokenList);
    return getFunctionNode(parameterList, functionName);
  }

  private FunctionNode getFunctionNode(final Queue<Queue<TerminalNode>> parameterList, final String functionName) {
    FunctionNode functionNode = new FunctionNode(functionName);
    Function function = FunctionFactory.getFunction(functionName);
    int totalParameters = parameterList.size();
    EquationNode node1 = getNode(parameterList.poll());
    functionNode.setParamOneNode(node1);
    if (function.isBinary()) {
      if (totalParameters == 2) {
        functionNode.setParamTwoNode(getNode(parameterList.poll()));
      } else {
        functionNode.setParamTwoNode(getFunctionNode(parameterList, functionName));
      }
    }
    return functionNode;
  }

  private Queue<Queue<TerminalNode>> split(final Queue<TerminalNode> tokenList) {
    Queue<Queue<TerminalNode>> list = new ArrayDeque<Queue<TerminalNode>>();
    while (!tokenList.isEmpty()) {
      Queue<TerminalNode> newTokenList = new ArrayDeque<TerminalNode>();
      TerminalNode poll = tokenList.poll();
      int type = getType(poll);
      while (type != FSEP) {
        newTokenList.add(poll);
        if (tokenList.isEmpty()) {
          break;
        }
        poll = tokenList.poll();
        type = getType(poll);
      }
      list.add(newTokenList);
    }
    return list;
  }

  EquationNode compile() {
    StringEquationParser parser = new StringEquationParser();
    List<TerminalNode> savedTokenList = parser.parseEquation(expression);
    Queue<TerminalNode> tokenList = new ArrayDeque<TerminalNode>(savedTokenList);
    EquationNode rootNode = getNode(tokenList);
    return rootNode;
  }
}
TOP

Related Classes of com.wesleyhome.math.equation.InfixEvaluator

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.