PageRenderTime 96ms CodeModel.GetById 20ms app.highlight 54ms RepoModel.GetById 16ms app.codeStats 1ms

/firefly-template/src/main/java/com/firefly/template/support/RPNUtils.java

https://github.com/zen7280110/firefly
Java | 483 lines | 460 code | 6 blank | 17 comment | 5 complexity | 0f6fcb256591546b6971e6717d446abd MD5 | raw file
  1package com.firefly.template.support;
  2
  3import java.util.Arrays;
  4import java.util.Deque;
  5import java.util.HashSet;
  6import java.util.LinkedList;
  7import java.util.List;
  8import java.util.Set;
  9
 10import com.firefly.template.exception.ExpressionError;
 11import com.firefly.utils.VerifyUtils;
 12
 13public class RPNUtils {
 14	
 15	private static final Set<String> CONDITIONAL_OPERATOR = new HashSet<String>(Arrays.asList("==", "!=", ">", "<", ">=", "<="));
 16	private static final Set<String> ARITHMETIC_OR_LOGICAL_OPERATOR = new HashSet<String>(Arrays.asList("&", "|"));
 17	private static final Set<String> LOGICAL_OPERATOR = new HashSet<String>(Arrays.asList("&&", "||"));
 18	private static final Set<String> ASSIGNMENT_OPERATOR = new HashSet<String>(Arrays.asList("=", "+=", "-=", "*=", "/=", "%=", "^=", "&=", "|=", "<<=", ">>=", ">>>="));
 19	
 20	/**
 21	 * This method parses the expression and creates Reverse Polish notation 
 22	 * symbol priority:
 23	 * 10: "*", "/", "%"
 24	 *	9: "+", "-" 
 25	 *	8: ">>", ">>>", "<<"
 26	 *	7: ">", "<", ">=", "<="
 27	 *	6: "==", "!="
 28	 *	5: "&"
 29	 *	4: "|"
 30	 *	3: "^"
 31	 *	2: "&&"
 32	 *	1: "||"
 33	 *	0: "=", "+=", "-=", "*=", "/=", "%=", "^=", "&=", "|=", "<<=", ">>=", ">>>=" //0
 34	 * @param text the infix notation 
 35	 * @return A list has many tokens and the sequence of postfix notation
 36	 */
 37	public static List<Fragment> getReversePolishNotation(String text) {
 38		String content = preprocessing(text);
 39		StringBuilder pre = new StringBuilder();
 40		Deque<Fragment> symbolDeque = new LinkedList<Fragment>();
 41		List<Fragment> list = new LinkedList<Fragment>();
 42		char c, n, n1, n2;
 43		
 44		for (int i = 0; i < content.length(); i++) {
 45			switch (content.charAt(i)) {
 46			case '\'':
 47			case '"':
 48				int next = content.indexOf(content.charAt(i), i + 1);
 49				while(content.charAt(next - 1) == '\\')
 50					next = content.indexOf(content.charAt(i), next + 1);
 51
 52				pre.append(content.substring(i, next + 1));
 53				i += next - i;
 54				break;
 55			case '(':
 56				pre.delete(0, pre.length());
 57				
 58				Fragment f0 = new Fragment();
 59				f0.priority = -1000;
 60				f0.value = "(";
 61				symbolDeque.push(f0);
 62				break;
 63			case '*':
 64			case '/':
 65			case '%':
 66				n = content.charAt(i + 1);
 67				if(n == '=') { // *= /= %=
 68					outValue(pre, list);
 69					outSymbol(String.valueOf(content.charAt(i)) + "=", 0, symbolDeque, list);
 70					i++;
 71					break;
 72				}
 73				
 74				// * / %
 75				outValue(pre, list);
 76				outSymbol(String.valueOf(content.charAt(i)), 10, symbolDeque, list);
 77				break;
 78			case '+':
 79			case '-':
 80				n = content.charAt(i + 1);
 81				if(n == '=') { // += -=
 82					outValue(pre, list);
 83					outSymbol(String.valueOf(content.charAt(i)) + "=", 0, symbolDeque, list);
 84					i++;
 85					break;
 86				}
 87				
 88				if(n == content.charAt(i)) {
 89					pre.append(content.charAt(i)).append(content.charAt(i + 1));
 90					i++;
 91					break;
 92				}
 93				
 94				// 正负号判断
 95				boolean s = false;
 96				String left0 = "*/%+-><=&|(^";
 97				if(i == 0) {
 98					s = true;
 99				} else {
100					for(int j = i - 1; j >= 0; j--) {
101						char ch = content.charAt(j);
102						if(!Character.isWhitespace(ch) ) {
103							if(left0.indexOf(ch) >= 0) {
104								int _n = j - 1;
105								s = _n < 0 || !(ch == '+' && content.charAt(_n) == '+' || ch == '-' && content.charAt(_n) == '-');
106							}
107							break;
108						}
109					}
110				}
111				
112				
113				// + -
114				if(s) {
115					pre.append(content.charAt(i));
116				} else {
117					outValue(pre, list);
118					outSymbol(String.valueOf(content.charAt(i)), 9, symbolDeque, list);
119				}
120				break;
121				
122			case '>':
123			case '<':
124				c = content.charAt(i);
125				n = content.charAt(i + 1);
126				
127				if(c == n) {
128					if(i + 2 < content.length()) {
129						n1 = content.charAt(i + 2);
130						if(n1 == '=') { // <<= >>=
131							outValue(pre, list);
132							outSymbol(String.valueOf(content.charAt(i)) + content.charAt(i + 1) + "=", 0, symbolDeque, list);
133							i += 2;
134							break;
135						}
136					}
137					
138					// << >>
139					outValue(pre, list);
140					outSymbol(String.valueOf(content.charAt(i)) + content.charAt(i + 1), 8, symbolDeque, list);
141					i++;
142					break;
143				}
144				
145				if(i + 2 < content.length()) {
146					n1 = content.charAt(i + 2);
147					if(c == '>' && n == '>' && n1 == '>') { 
148						n2 = content.charAt(i + 3);
149						if(i + 3 < content.length()) {
150							if(n2 == '=') { // >>>=
151								outValue(pre, list);
152								outSymbol(">>>=", 0, symbolDeque, list);
153								i += 3;
154								break;
155							}
156						}
157						
158						// >>>
159						outValue(pre, list);
160						outSymbol(">>>", 8, symbolDeque, list);
161						i += 2;
162						break;
163					}
164				}
165				
166				if(n == '=') { // <= >=
167					outValue(pre, list);
168					outSymbol(String.valueOf(content.charAt(i)) + "=", 7, symbolDeque, list);
169					i++;
170					break;
171				}
172				
173				// < >
174				outValue(pre, list);
175				outSymbol(String.valueOf(content.charAt(i)), 7, symbolDeque, list);
176				break;
177			
178			case '=':
179				n = content.charAt(i + 1);
180				if(n == '=') { // ==
181					outValue(pre, list);
182					outSymbol(String.valueOf(content.charAt(i)) + "=", 6, symbolDeque, list);
183					i++;
184					break;
185				}
186				
187				// =
188				outValue(pre, list);
189				outSymbol(String.valueOf(content.charAt(i)), 0, symbolDeque, list);
190				break;
191			
192			case '!':
193				n = content.charAt(i + 1);
194				if(n == '=') { // !=
195					outValue(pre, list);
196					outSymbol(String.valueOf(content.charAt(i)) + "=", 6, symbolDeque, list);			
197					i++;
198					break;
199				}
200				pre.append('!');
201				break;
202				
203			case '&':
204				n = content.charAt(i + 1);
205				if(n == '&') { // &&
206					outValue(pre, list);
207					outSymbol("&&", 2, symbolDeque, list);
208					i++;
209					break;
210				}
211				
212				if(n == '=') { // &=
213					outValue(pre, list);
214					outSymbol("&=", 0, symbolDeque, list);
215					i++;
216					break;
217				}
218				
219				// &
220				outValue(pre, list);
221				outSymbol("&", 5, symbolDeque, list);
222				break;
223			case '|':
224				n = content.charAt(i + 1);
225				if(n == '|') { // ||
226					outValue(pre, list);
227					outSymbol("||", 1, symbolDeque, list);
228					i++;
229					break;
230				}
231				
232				if(n == '=') { // |=
233					outValue(pre, list);
234					outSymbol("|=", 0, symbolDeque, list);
235					i++;
236					break;
237				}
238				
239				// |
240				outValue(pre, list);
241				outSymbol("|", 4, symbolDeque, list);
242				break;
243			case '^':
244				n = content.charAt(i + 1);
245				if(n == '=') {// ^=
246					outValue(pre, list);
247					outSymbol(String.valueOf(content.charAt(i)) + "=", 0, symbolDeque, list);
248					i++;
249					break;
250				}
251				
252				// ^
253				outValue(pre, list);
254				outSymbol("^", 3, symbolDeque, list);
255				break;
256			case ')':
257				outValue(pre, list);
258				outSymbol(")", -1000, symbolDeque, list);
259				break;
260			default:
261				pre.append(content.charAt(i));
262				break;
263			}
264		}
265		
266		outValue(pre, list);
267		while(!symbolDeque.isEmpty())
268			list.add(symbolDeque.pop());
269		
270		return list;
271	}
272	
273	private static String preprocessing(String content) {
274		StringBuilder ret = new StringBuilder();
275		if(preprocessing0(content, ret))
276			return ret.toString();
277		else
278			return preprocessing(ret.toString());
279	}
280	
281	private static boolean preprocessing0(String content, StringBuilder ret) {
282		boolean t = true;
283		StringBuilder pre = new StringBuilder();
284		int c = 0;
285		int start = 0;
286		for (int i = 0; i < content.length(); i++) {
287			char ch = content.charAt(i);
288			switch (ch) {
289			case '!':
290			case '+':
291			case '-':
292				boolean l = false;
293				boolean r = false;
294				String left0 = "*/%+-><=&|(^";
295				if(i == 0 || ch == '!') {
296					l = true;
297				} else {
298					for(int j = i - 1; j >= 0; j--) {
299						char c0 = content.charAt(j);
300						if(!Character.isWhitespace(c0) ) {
301							if(left0.indexOf(c0) >= 0) {
302								int _n = j - 1;
303								l = _n < 0 || !(c0 == '+' && content.charAt(_n) == '+' || c0 == '-' && content.charAt(_n) == '-');
304							}
305							break;
306						}
307					}
308				}
309				
310				if(l) {
311					for (int j = i + 1; j < content.length(); j++) {
312						char c0 = content.charAt(j);
313						if(!Character.isWhitespace(c0)) {
314							if(c0 == '(') {
315								start = j + 1;
316								r = true;
317								pre.append(c0);
318							}
319							break;
320						}
321					}
322				}
323				if(l && r) {
324					t = false;
325					c += 1;
326					while(c != 0) {
327						char c0 = content.charAt(start++);
328						if(c0 == '(')
329							c++;
330						else if(c0 == ')')
331							c--;
332						pre.append(c0);
333					}
334					if(ch == '!')
335						ret.append("(").append(pre).append(" == false) ");
336					else
337						ret.append("(0 ").append(ch).append(' ').append(pre).append(") ");
338
339					pre.delete(0, pre.length());
340					i = start;
341				} else
342					ret.append(ch);
343				break;
344			default:
345				ret.append(ch);
346				break;
347			}
348		}
349		return t;
350	}
351	
352	/**
353	 * remove redundant symbols, such as +, -
354	 * @param v
355	 * @return
356	 */
357	private static String getSimpleValue(String v) {
358		int left = 0;
359		boolean n = false;
360		for (int i = 0; i < v.length(); i++) {
361			char ch = v.charAt(i);
362			if(ch == '-')
363				n = true;
364			if(ch != '+' && ch != '-' && !Character.isWhitespace(ch)) {
365				left = i;
366				break;
367			}
368		}
369		String s = v.substring(left);
370		return n ? "-" + s : s;
371	}
372	
373	private static boolean isString(String v) {
374		int start = v.charAt(0);
375		int end = v.charAt(v.length() - 1);
376		return (start == '"' && end == '"') || (start == '\'' && end == '\'');
377	}
378	
379	private static boolean isBoolean(String v) {
380		int start = v.charAt(0) == '!' ? 1 : 0;
381		return v.substring(start).trim().equals("true") || v.substring(start).trim().equals("false");
382	}
383	
384	private static boolean isVariable(String v) {
385		int start = v.indexOf("${");
386		int end = v.indexOf('}');
387		return start >= 0 && start < end;
388	}
389	
390	private static void outValue(StringBuilder pre, List<Fragment> list) {
391		String v = pre.toString().trim();
392		if(v.length() > 0) {
393			Fragment f= new Fragment();
394			f.priority = -200;
395			f.value = getSimpleValue(v);
396			
397			if(isVariable(f.value)) {
398				f.type = Type.VARIABLE;
399			} else if(isBoolean(f.value)) {
400				f.type = Type.BOOLEAN;
401			} else if(isString(f.value)) {
402				f.type = Type.STRING;
403				f.value = "\"" + f.value.substring(1, f.value.length() - 1) + "\"";
404			} else if(VerifyUtils.isFloat(f.value)) {
405				f.type = Type.FLOAT;
406				char end = f.value.charAt(f.value.length() - 1);
407				if(end == 'f' || end == 'F')
408					f.value = f.value.substring(0, f.value.length() - 1);
409			} else if(VerifyUtils.isDouble(f.value)) {
410				f.type = Type.DOUBLE;
411			} else if(VerifyUtils.isInteger(f.value)) {
412				f.type = Type.INTEGER;
413			} else if(VerifyUtils.isLong(f.value)) {
414				f.type = Type.LONG;
415				char end = f.value.charAt(f.value.length() - 1);
416				if(end == 'l' || end == 'L')
417					f.value = f.value.substring(0, f.value.length() - 1);
418			} else if(f.value.equals("null")) { 
419				f.type = Type.NULL;
420			} else
421				throw new ExpressionError("Can not determine the type: " + f.value);
422			
423			list.add(f);
424		}
425		pre.delete(0, pre.length());
426	}
427	
428	private static void outSymbol(String value, int priority, Deque<Fragment> symbolDeque, List<Fragment> list) {
429		Fragment f = new Fragment();
430		f.value = value;
431		f.priority = priority;
432		if(ARITHMETIC_OR_LOGICAL_OPERATOR.contains(value)) {
433			f.type = Type.ARITHMETIC_OR_LOGICAL_OPERATOR;
434		} else if(LOGICAL_OPERATOR.contains(value)) {
435			f.type = Type.LOGICAL_OPERATOR;
436		} else if(ASSIGNMENT_OPERATOR.contains(value)) {
437			f.type = Type.ASSIGNMENT_OPERATOR;
438		} else if(CONDITIONAL_OPERATOR.contains(value)) {
439			f.type = Type.CONDITIONAL_OPERATOR;
440		} else
441			f.type = Type.ARITHMETIC_OPERATOR;
442		
443		if(f.value.equals(")")) {
444			for(Fragment top = null; !symbolDeque.isEmpty() 
445					&& !(top = symbolDeque.pop()).value.equals("("); )
446				list.add(top);
447		} else {
448			for(Fragment top = null; !symbolDeque.isEmpty() 
449					&& (top = symbolDeque.peek()).priority >= f.priority; ) {
450				list.add(top);
451				symbolDeque.pop();
452			}
453			symbolDeque.push(f);
454		}
455	}
456	
457	public static class Fragment {
458		public int priority;
459		public String value;
460		public Type type;
461		
462		public String toString() {
463			return value;
464		}
465	}
466	
467	public static enum Type {
468		VARIABLE,
469		INTEGER,
470		LONG,
471		FLOAT,
472		DOUBLE,
473		BOOLEAN,
474		STRING,
475		NULL,
476		
477		ARITHMETIC_OPERATOR,
478		LOGICAL_OPERATOR,
479		ASSIGNMENT_OPERATOR,
480		ARITHMETIC_OR_LOGICAL_OPERATOR,
481		CONDITIONAL_OPERATOR
482	}
483}