PageRenderTime 48ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

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