All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.firefly.template.support.RPNUtils Maven / Gradle / Ivy

There is a newer version: 4.0.20
Show newest version
package com.firefly.template.support;

import java.util.Arrays;
import java.util.Deque;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import com.firefly.template.exception.ExpressionError;
import com.firefly.utils.VerifyUtils;

public class RPNUtils {
	
	private static final Set CONDITIONAL_OPERATOR = new HashSet(Arrays.asList("==", "!=", ">", "<", ">=", "<="));
	private static final Set ARITHMETIC_OR_LOGICAL_OPERATOR = new HashSet(Arrays.asList("&", "|"));
	private static final Set LOGICAL_OPERATOR = new HashSet(Arrays.asList("&&", "||"));
	private static final Set ASSIGNMENT_OPERATOR = new HashSet(Arrays.asList("=", "+=", "-=", "*=", "/=", "%=", "^=", "&=", "|=", "<<=", ">>=", ">>>="));
	
	/**
	 * This method parses the expression and creates Reverse Polish notation 
	 * symbol priority:
	 * 10: "*", "/", "%"
	 *	9: "+", "-" 
	 *	8: ">>", ">>>", "<<"
	 *	7: ">", "<", ">=", "<="
	 *	6: "==", "!="
	 *	5: "&"
	 *	4: "|"
	 *	3: "^"
	 *	2: "&&"
	 *	1: "||"
	 *	0: "=", "+=", "-=", "*=", "/=", "%=", "^=", "&=", "|=", "<<=", ">>=", ">>>=" //0
	 * @param text the infix notation 
	 * @return A list has many tokens and the sequence of postfix notation
	 */
	public static List getReversePolishNotation(String text) {
		String content = preprocessing(text);
		StringBuilder pre = new StringBuilder();
		Deque symbolDeque = new LinkedList();
		List list = new LinkedList();
		char c, n, n1, n2;
		
		for (int i = 0; i < content.length(); i++) {
			switch (content.charAt(i)) {
			case '\'':
			case '"':
				int next = content.indexOf(content.charAt(i), i + 1);
				while(content.charAt(next - 1) == '\\')
					next = content.indexOf(content.charAt(i), next + 1);

				pre.append(content.substring(i, next + 1));
				i += next - i;
				break;
			case '(':
				pre.delete(0, pre.length());
				
				Fragment f0 = new Fragment();
				f0.priority = -1000;
				f0.value = "(";
				symbolDeque.push(f0);
				break;
			case '*':
			case '/':
			case '%':
				n = content.charAt(i + 1);
				if(n == '=') { // *= /= %=
					outValue(pre, list);
					outSymbol(String.valueOf(content.charAt(i)) + "=", 0, symbolDeque, list);
					i++;
					break;
				}
				
				// * / %
				outValue(pre, list);
				outSymbol(String.valueOf(content.charAt(i)), 10, symbolDeque, list);
				break;
			case '+':
			case '-':
				n = content.charAt(i + 1);
				if(n == '=') { // += -=
					outValue(pre, list);
					outSymbol(String.valueOf(content.charAt(i)) + "=", 0, symbolDeque, list);
					i++;
					break;
				}
				
				if(n == content.charAt(i)) {
					pre.append(content.charAt(i)).append(content.charAt(i + 1));
					i++;
					break;
				}
				
				// 正负号判断
				boolean s = false;
				String left0 = "*/%+-><=&|(^";
				if(i == 0) {
					s = true;
				} else {
					for(int j = i - 1; j >= 0; j--) {
						char ch = content.charAt(j);
						if(!Character.isWhitespace(ch) ) {
							if(left0.indexOf(ch) >= 0) {
								int _n = j - 1;
								s = _n < 0 || !(ch == '+' && content.charAt(_n) == '+' || ch == '-' && content.charAt(_n) == '-');
							}
							break;
						}
					}
				}
				
				
				// + -
				if(s) {
					pre.append(content.charAt(i));
				} else {
					outValue(pre, list);
					outSymbol(String.valueOf(content.charAt(i)), 9, symbolDeque, list);
				}
				break;
				
			case '>':
			case '<':
				c = content.charAt(i);
				n = content.charAt(i + 1);
				
				if(c == n) {
					if(i + 2 < content.length()) {
						n1 = content.charAt(i + 2);
						if(n1 == '=') { // <<= >>=
							outValue(pre, list);
							outSymbol(String.valueOf(content.charAt(i)) + content.charAt(i + 1) + "=", 0, symbolDeque, list);
							i += 2;
							break;
						}
					}
					
					// << >>
					outValue(pre, list);
					outSymbol(String.valueOf(content.charAt(i)) + content.charAt(i + 1), 8, symbolDeque, list);
					i++;
					break;
				}
				
				if(i + 2 < content.length()) {
					n1 = content.charAt(i + 2);
					if(c == '>' && n == '>' && n1 == '>') { 
						n2 = content.charAt(i + 3);
						if(i + 3 < content.length()) {
							if(n2 == '=') { // >>>=
								outValue(pre, list);
								outSymbol(">>>=", 0, symbolDeque, list);
								i += 3;
								break;
							}
						}
						
						// >>>
						outValue(pre, list);
						outSymbol(">>>", 8, symbolDeque, list);
						i += 2;
						break;
					}
				}
				
				if(n == '=') { // <= >=
					outValue(pre, list);
					outSymbol(String.valueOf(content.charAt(i)) + "=", 7, symbolDeque, list);
					i++;
					break;
				}
				
				// < >
				outValue(pre, list);
				outSymbol(String.valueOf(content.charAt(i)), 7, symbolDeque, list);
				break;
			
			case '=':
				n = content.charAt(i + 1);
				if(n == '=') { // ==
					outValue(pre, list);
					outSymbol(String.valueOf(content.charAt(i)) + "=", 6, symbolDeque, list);
					i++;
					break;
				}
				
				// =
				outValue(pre, list);
				outSymbol(String.valueOf(content.charAt(i)), 0, symbolDeque, list);
				break;
			
			case '!':
				n = content.charAt(i + 1);
				if(n == '=') { // !=
					outValue(pre, list);
					outSymbol(String.valueOf(content.charAt(i)) + "=", 6, symbolDeque, list);			
					i++;
					break;
				}
				pre.append('!');
				break;
				
			case '&':
				n = content.charAt(i + 1);
				if(n == '&') { // &&
					outValue(pre, list);
					outSymbol("&&", 2, symbolDeque, list);
					i++;
					break;
				}
				
				if(n == '=') { // &=
					outValue(pre, list);
					outSymbol("&=", 0, symbolDeque, list);
					i++;
					break;
				}
				
				// &
				outValue(pre, list);
				outSymbol("&", 5, symbolDeque, list);
				break;
			case '|':
				n = content.charAt(i + 1);
				if(n == '|') { // ||
					outValue(pre, list);
					outSymbol("||", 1, symbolDeque, list);
					i++;
					break;
				}
				
				if(n == '=') { // |=
					outValue(pre, list);
					outSymbol("|=", 0, symbolDeque, list);
					i++;
					break;
				}
				
				// |
				outValue(pre, list);
				outSymbol("|", 4, symbolDeque, list);
				break;
			case '^':
				n = content.charAt(i + 1);
				if(n == '=') {// ^=
					outValue(pre, list);
					outSymbol(String.valueOf(content.charAt(i)) + "=", 0, symbolDeque, list);
					i++;
					break;
				}
				
				// ^
				outValue(pre, list);
				outSymbol("^", 3, symbolDeque, list);
				break;
			case ')':
				outValue(pre, list);
				outSymbol(")", -1000, symbolDeque, list);
				break;
			default:
				pre.append(content.charAt(i));
				break;
			}
		}
		
		outValue(pre, list);
		while(!symbolDeque.isEmpty())
			list.add(symbolDeque.pop());
		
		return list;
	}
	
	private static String preprocessing(String content) {
		StringBuilder ret = new StringBuilder();
		if(preprocessing0(content, ret))
			return ret.toString();
		else
			return preprocessing(ret.toString());
	}
	
	private static boolean preprocessing0(String content, StringBuilder ret) {
		boolean t = true;
		StringBuilder pre = new StringBuilder();
		int c = 0;
		int start = 0;
		for (int i = 0; i < content.length(); i++) {
			char ch = content.charAt(i);
			switch (ch) {
			case '!':
			case '+':
			case '-':
				boolean l = false;
				boolean r = false;
				String left0 = "*/%+-><=&|(^";
				if(i == 0 || ch == '!') {
					l = true;
				} else {
					for(int j = i - 1; j >= 0; j--) {
						char c0 = content.charAt(j);
						if(!Character.isWhitespace(c0) ) {
							if(left0.indexOf(c0) >= 0) {
								int _n = j - 1;
								l = _n < 0 || !(c0 == '+' && content.charAt(_n) == '+' || c0 == '-' && content.charAt(_n) == '-');
							}
							break;
						}
					}
				}
				
				if(l) {
					for (int j = i + 1; j < content.length(); j++) {
						char c0 = content.charAt(j);
						if(!Character.isWhitespace(c0)) {
							if(c0 == '(') {
								start = j + 1;
								r = true;
								pre.append(c0);
							}
							break;
						}
					}
				}
				if(l && r) {
					t = false;
					c += 1;
					while(c != 0) {
						char c0 = content.charAt(start++);
						if(c0 == '(')
							c++;
						else if(c0 == ')')
							c--;
						pre.append(c0);
					}
					if(ch == '!')
						ret.append("(").append(pre).append(" == false) ");
					else
						ret.append("(0 ").append(ch).append(' ').append(pre).append(") ");

					pre.delete(0, pre.length());
					i = start;
				} else
					ret.append(ch);
				break;
			default:
				ret.append(ch);
				break;
			}
		}
		return t;
	}
	
	/**
	 * remove redundant symbols, such as +, -
	 * @param v
	 * @return
	 */
	private static String getSimpleValue(String v) {
		int left = 0;
		boolean n = false;
		for (int i = 0; i < v.length(); i++) {
			char ch = v.charAt(i);
			if(ch == '-')
				n = true;
			if(ch != '+' && ch != '-' && !Character.isWhitespace(ch)) {
				left = i;
				break;
			}
		}
		String s = v.substring(left);
		return n ? "-" + s : s;
	}
	
	private static boolean isString(String v) {
		int start = v.charAt(0);
		int end = v.charAt(v.length() - 1);
		return (start == '"' && end == '"') || (start == '\'' && end == '\'');
	}
	
	private static boolean isBoolean(String v) {
		int start = v.charAt(0) == '!' ? 1 : 0;
		return v.substring(start).trim().equals("true") || v.substring(start).trim().equals("false");
	}
	
	private static boolean isVariable(String v) {
		int start = v.indexOf("${");
		int end = v.indexOf('}');
		return start >= 0 && start < end;
	}
	
	private static void outValue(StringBuilder pre, List list) {
		String v = pre.toString().trim();
		if(v.length() > 0) {
			Fragment f= new Fragment();
			f.priority = -200;
			f.value = getSimpleValue(v);
			
			if(isVariable(f.value)) {
				f.type = Type.VARIABLE;
			} else if(isBoolean(f.value)) {
				f.type = Type.BOOLEAN;
			} else if(isString(f.value)) {
				f.type = Type.STRING;
				f.value = "\"" + f.value.substring(1, f.value.length() - 1) + "\"";
			} else if(VerifyUtils.isFloat(f.value)) {
				f.type = Type.FLOAT;
				char end = f.value.charAt(f.value.length() - 1);
				if(end == 'f' || end == 'F')
					f.value = f.value.substring(0, f.value.length() - 1);
			} else if(VerifyUtils.isDouble(f.value)) {
				f.type = Type.DOUBLE;
			} else if(VerifyUtils.isInteger(f.value)) {
				f.type = Type.INTEGER;
			} else if(VerifyUtils.isLong(f.value)) {
				f.type = Type.LONG;
				char end = f.value.charAt(f.value.length() - 1);
				if(end == 'l' || end == 'L')
					f.value = f.value.substring(0, f.value.length() - 1);
			} else if(f.value.equals("null")) { 
				f.type = Type.NULL;
			} else
				throw new ExpressionError("Can not determine the type: " + f.value);
			
			list.add(f);
		}
		pre.delete(0, pre.length());
	}
	
	private static void outSymbol(String value, int priority, Deque symbolDeque, List list) {
		Fragment f = new Fragment();
		f.value = value;
		f.priority = priority;
		if(ARITHMETIC_OR_LOGICAL_OPERATOR.contains(value)) {
			f.type = Type.ARITHMETIC_OR_LOGICAL_OPERATOR;
		} else if(LOGICAL_OPERATOR.contains(value)) {
			f.type = Type.LOGICAL_OPERATOR;
		} else if(ASSIGNMENT_OPERATOR.contains(value)) {
			f.type = Type.ASSIGNMENT_OPERATOR;
		} else if(CONDITIONAL_OPERATOR.contains(value)) {
			f.type = Type.CONDITIONAL_OPERATOR;
		} else
			f.type = Type.ARITHMETIC_OPERATOR;
		
		if(f.value.equals(")")) {
			for(Fragment top = null; !symbolDeque.isEmpty() 
					&& !(top = symbolDeque.pop()).value.equals("("); )
				list.add(top);
		} else {
			for(Fragment top = null; !symbolDeque.isEmpty() 
					&& (top = symbolDeque.peek()).priority >= f.priority; ) {
				list.add(top);
				symbolDeque.pop();
			}
			symbolDeque.push(f);
		}
	}
	
	public static class Fragment {
		public int priority;
		public String value;
		public Type type;
		
		@Override
		public String toString() {
			return value;
		}
	}
	
	public static enum Type {
		VARIABLE,
		INTEGER,
		LONG,
		FLOAT,
		DOUBLE,
		BOOLEAN,
		STRING,
		NULL,
		
		ARITHMETIC_OPERATOR,
		LOGICAL_OPERATOR,
		ASSIGNMENT_OPERATOR,
		ARITHMETIC_OR_LOGICAL_OPERATOR,
		CONDITIONAL_OPERATOR
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy