public ParseTree parse(String ea) throws ParseError { String e = ea; if (verbose) { E.info("Parsing: " + e); } e = e.trim(); if (e.lastIndexOf("(") == 0 && e.indexOf(")") == e.length() - 1) { e = e.substring(1, e.length() - 1); // E.info("Replaced with: " + e); } ArrayList<Node> nodes = tokenize(e); // now we've got a list of tokens, and each is linked to is neighbor on either side if (verbose) { E.info("tokens: " + nodes); } // a group node to hold the whole lot, the same as is used for the content of bracketed chunks GroupNode groot = new GroupNode(null); groot.addAll(nodes); // some nodes will get replaced, but the operators remain throughout and will be needed later // to claim their operands. Use a list here so we can sort by precedence. ArrayList<AbstractOperatorNode> ops = new ArrayList<AbstractOperatorNode>(); ArrayList<GroupNode> gnodes = new ArrayList<GroupNode>(); ArrayList<FunctionNode> fnodes = new ArrayList<FunctionNode>(); for (Node n : nodes) { if (n instanceof AbstractOperatorNode) { ops.add((AbstractOperatorNode) n); } if (n instanceof GroupNode) { gnodes.add((GroupNode) n); } if (n instanceof FunctionNode) { fnodes.add((FunctionNode) n); } } // Right parentheses have been mapped to group nodes. Left parentheses // are still present. Make each group node claim the content back to the corresponding // opening parenthesis. By starting at the left and processing groups as // we come to them we don't need recursion for (GroupNode gn : gnodes) { gn.gatherPreceeding(); } if (verbose) { E.info("Root group: " + groot.toString()); } AbstractOperatorNode[] aops = ops.toArray(new AbstractOperatorNode[ops.size()]); Arrays.sort(aops, new PrecedenceComparator()); for (FunctionNode fn : fnodes) { fn.claim(); } for (AbstractOperatorNode op : aops) { op.claim(); } for (GroupNode gn : gnodes) { gn.supplantByChild(); } ParseTreeNode root = null; if (groot.getChildren().size() == 1) { Node fc = groot.getChildren().get(0); if (fc instanceof ParseTreeNode) { root = (ParseTreeNode) fc; } else { throw new ParseError("root node is not evaluable " + fc); } } else { StringBuilder sb = new StringBuilder(); sb.append(" too many children left in container: " + groot.getChildren().size()); sb.append("\n"); for (Node n : groot.getChildren()) { sb.append("Node: " + n + "\n"); } throw new ParseError(sb.toString()); } ParseTree ret = new ParseTree(root); return ret; }
static void addOperator(AbstractOperatorNode op) { opHM.put(op.getSymbol(), op); }