Java tutorial
/** * Copyright (c) 2014 Baidu, Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.baidu.rigel.biplatform.parser; import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.util.HashMap; import java.util.Map; import java.util.Stack; import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; import com.baidu.rigel.biplatform.parser.exception.IllegalTokenException; import com.baidu.rigel.biplatform.parser.exception.InvokeFunctionException; import com.baidu.rigel.biplatform.parser.exception.NotAllowedOperationException; import com.baidu.rigel.biplatform.parser.node.CalculateNode; import com.baidu.rigel.biplatform.parser.node.FunctionNode; import com.baidu.rigel.biplatform.parser.node.Node; import com.baidu.rigel.biplatform.parser.node.Node.NodeType; import com.baidu.rigel.biplatform.parser.node.impl.AddCalculateNode; import com.baidu.rigel.biplatform.parser.node.impl.DataNode; import com.baidu.rigel.biplatform.parser.node.impl.DivideCalculateNode; import com.baidu.rigel.biplatform.parser.node.impl.MultiplyCalculateNode; import com.baidu.rigel.biplatform.parser.node.impl.NodeFactory; import com.baidu.rigel.biplatform.parser.node.impl.SubtractCalculateNode; import com.baidu.rigel.biplatform.parser.node.impl.VariableNode; import com.baidu.rigel.biplatform.parser.util.ParserConstant; /** * * @author xiaoming.chen * @version 20141218 * @since jdk 1.8 or after */ public class CompileSection { /** * sections */ private Map<String, String> sections; private Map<String, Node> resolveNodes; protected CompileSection(Map<String, String> sections) { this.sections = sections; resolveNodes = new HashMap<String, Node>(sections.size()); } protected Map<String, Node> complie() throws InvokeFunctionException { compileSections(); return this.resolveNodes; } protected void compileSections() throws InvokeFunctionException { for (Map.Entry<String, String> entry : sections.entrySet()) { compileSection(entry.getKey(), entry.getValue()); } } protected void compileSection(String key, String section) throws InvokeFunctionException { int i = 0; char c = ' '; StringBuilder currentToken = new StringBuilder(); boolean isFunction = false; FunctionNode function = null; Stack<Node> resolveSectionNodes = new Stack<Node>(); while (i < section.length()) { c = section.charAt(i); switch (c) { case ' ': // skip blank character break; case '(': // ?token??section if (currentToken.length() > 0) { isFunction = true; String funName = currentToken.toString(); try { function = NodeFactory.makeFunctionNodeByFunctionName(funName); } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { throw new InvokeFunctionException(funName, e.getMessage()); } } currentToken.setLength(0); break; case ',': // ??????? sectionProcess(resolveSectionNodes, resolveToken(currentToken.toString()), null); function.getArgs().add(arrangeNodes(resolveSectionNodes)); currentToken.setLength(0); break; case ')': sectionProcess(resolveSectionNodes, resolveToken(currentToken.toString()), null); // ??? if (isFunction) { if (!resolveSectionNodes.isEmpty()) { function.getArgs().add(arrangeNodes(resolveSectionNodes)); } resolveNodes.put(key, function); } else { resolveNodes.put(key, arrangeNodes(resolveSectionNodes)); } currentToken.setLength(0); break; case '*': //42 sectionProcess(resolveSectionNodes, resolveToken(currentToken.toString()), new MultiplyCalculateNode()); currentToken.setLength(0); break; case '/': //47 sectionProcess(resolveSectionNodes, resolveToken(currentToken.toString()), new DivideCalculateNode()); currentToken.setLength(0); break; case '+': //43 sectionProcess(resolveSectionNodes, resolveToken(currentToken.toString()), new AddCalculateNode()); currentToken.setLength(0); break; case '-': //45 sectionProcess(resolveSectionNodes, resolveToken(currentToken.toString()), new SubtractCalculateNode()); currentToken.setLength(0); break; default: currentToken.append(c); break; } i++; } // ??? if (currentToken.length() > 0) { sectionProcess(resolveSectionNodes, resolveToken(currentToken.toString()), null); resolveNodes.put(key, arrangeNodes(resolveSectionNodes)); } } /** * ?section?? * arrangeNodes * @param nodes * @return */ private Node arrangeNodes(Stack<Node> nodes) { if (!nodes.isEmpty()) { Node node = null; Node leafNode = null; CalculateNode result = null; while (!nodes.isEmpty()) { node = nodes.pop(); if (node.getNodeType().equals(NodeType.Calculate)) { result = (CalculateNode) node; if (leafNode == null) { leafNode = node; } else { result.setRight(leafNode); leafNode = result; } } else { return node; } } return result; } return null; } private void sectionProcess(Stack<Node> nodes, Node tokenNode, CalculateNode calcNode) { if (nodes.isEmpty()) { if (calcNode == null) { nodes.push(tokenNode); } else { calcNode.setLeft(tokenNode); nodes.push(calcNode); } } else { // ? if (!nodes.peek().getNodeType().equals(NodeType.Calculate)) { // ?? throw new NotAllowedOperationException("not allowed"); } CalculateNode node = (CalculateNode) nodes.peek(); if (calcNode == null) { node.setRight(tokenNode); return; } if (node.getOperation().getPriority() >= calcNode.getOperation().getPriority()) { node.setRight(tokenNode); calcNode.setLeft(node); // nodes.pop(); } else { calcNode.setLeft(tokenNode); } nodes.push(calcNode); } } private Node resolveToken(String token) { if (StringUtils.isNotBlank(token)) { // 1.???2??? // 2. if (token.startsWith(CompileExpression.SECTION_PRE)) { return resolveNodes.get(token); } else if (Pattern.matches(ParserConstant.VARIABLE_PATTERN_STR, token)) { // token???? return new VariableNode(token); } else if (Pattern.matches(ParserConstant.NUMBER_PATTERN_STR, token)) { return new DataNode(new BigDecimal(token)); } else { throw new IllegalTokenException(token, "CAN NOT RECONIZE TOKEN:" + token); } } else { throw new IllegalTokenException(token, "NULL TOKEN"); } } }