Browse Source

增加流程控制语句(分支控制、循环控制)

leichangchun 1 year ago
parent
commit
c25c87a32f

+ 5 - 0
pom.xml

@@ -43,6 +43,11 @@
 			<groupId>mysql</groupId>
 			<artifactId>mysql-connector-java</artifactId>
 		</dependency>
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+             <version>9.3-1102-jdbc41</version>
+        </dependency>
 		<dependency>
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-test</artifactId>

+ 8 - 0
src/engine/java/xbc/formula/engine/exp/datatype/XbcExpExpOpKind.java

@@ -48,5 +48,13 @@ public class XbcExpExpOpKind {
     public static final int AFTDEC_OK   = 43;    /* var --                      */
     public static final int ITV_OK      = 44;    /* 层差计算                       */
     public static final int DIV0_OK     = 45;    /* div0                        */
+    public static final int IF_OK       = 60;    /* if                          */
+    public static final int FOR_OK      = 61;    /* for循环                       */
+    public static final int BREAK_OK    = 62;    /* break                       */
+    public static final int CONTINUE_OK = 63;    /* continue                    */
+    public static final int WHILE_OK    = 64;    /* while                       */
+    public static final int EXIT_OK     = 66;    /* exit                        */
+    public static final int NEW_OK      = 67;    /* new                         */
+    public static final int INVOKE_OK   = 68;    /* invoke                      */
     public static final int NULL_OK     = 99;    /* null op                     */
 }

+ 22 - 3
src/engine/java/xbc/formula/engine/exp/datatype/XbcExpExpTree.java

@@ -15,12 +15,15 @@ public class XbcExpExpTree {
 	public int ek;   // ExpKind
 	public int ok;   // OpKind
 	public XbcExpExpTree lchild;
+	public XbcExpExpTree mchild;
 	public XbcExpExpTree rchild;
 	public Object value;
 	public List<XbcExpExpTree> params;
 
 	public List<XbcExpIntervalVo> itvs; // 层差计算用
-	
+
+	public XbcExpExpTree body; // 下一个表达式
+
 	public XbcExpExpTree next; // 下一个表达式
 
 	public XbcExpExpTree() {
@@ -36,8 +39,8 @@ public class XbcExpExpTree {
 		exp.ek = XbcExpExpKind.CST_EK;
 		exp.ok = XbcExpExpVarKind.INT_VK;
 		try {
-			BigDecimal bv = new BigDecimal(tokenContent);
-			exp.value = bv;
+			int iv = Integer.valueOf(tokenContent).intValue();
+			exp.value = iv;
 		} catch(NumberFormatException nx) {
 			throw new XbcExpParseException("无法将【" + tokenContent + "】转换成整数。" + " 公式: " + expStr);
 		}
@@ -57,6 +60,22 @@ public class XbcExpExpTree {
 		return exp;
 	}
 
+	public static XbcExpExpTree newConstBoolExptree(boolean bv) {
+		XbcExpExpTree exp = new XbcExpExpTree();
+		exp.ek = XbcExpExpKind.CST_EK;
+		exp.ok = XbcExpExpVarKind.BOOL_VK;
+		exp.value = bv;
+		return exp;
+	}
+
+	public static XbcExpExpTree newConstNullExptree() {
+		XbcExpExpTree exp = new XbcExpExpTree();
+		exp.ek = XbcExpExpKind.CST_EK;
+		exp.ok = XbcExpExpVarKind.UNK_VK;
+		exp.value = null;
+		return exp;
+	}
+
 	public static XbcExpExpTree newConstStrExptree(String tokenContent) {
 		XbcExpExpTree exp = new XbcExpExpTree();
 		exp.ek = XbcExpExpKind.CST_EK;

+ 5 - 3
src/engine/java/xbc/formula/engine/exp/datatype/XbcExpExpVarKind.java

@@ -6,7 +6,9 @@ package xbc.formula.engine.exp.datatype;
  * @author leichangchun
  */
 public class XbcExpExpVarKind {
-	public static final int INT_VK = 100;
-	public static final int STR_VK = 101;
-	public static final int DBL_VK = 102;
+	public static final int INT_VK  = 100;
+	public static final int STR_VK  = 101;
+	public static final int DBL_VK  = 102;
+	public static final int BOOL_VK = 103;
+	public static final int UNK_VK  = 104;
 }

+ 11 - 0
src/engine/java/xbc/formula/engine/exp/datatype/XbcExpToken.java

@@ -106,6 +106,8 @@ public class XbcExpToken {
 	public static final int SEMI_TT = 47;
 	@XbcExpTokenAnnotation(id="div0", name="div0", value="div0")
 	public static final int DIV0_TT = 48;
+	@XbcExpTokenAnnotation(id="period", name="点号", value=".")
+	public static final int PRD_TT = 49;
 	@XbcExpTokenAnnotation(id="if", name="if", value="if")
 	public static final int IF_TT = 60;
 	@XbcExpTokenAnnotation(id="for", name="for", value="for")
@@ -116,6 +118,14 @@ public class XbcExpToken {
 	public static final int CONTINUE_TT = 63;
 	@XbcExpTokenAnnotation(id="break", name="break", value="break")
 	public static final int BREAK_TT = 64;
+	@XbcExpTokenAnnotation(id="else", name="else", value="else")
+	public static final int ELSE_TT = 65;
+	@XbcExpTokenAnnotation(id="exit", name="exit", value="exit")
+	public static final int EXIT_TT = 66;
+	@XbcExpTokenAnnotation(id="new", name="new", value="new")
+	public static final int NEW_TT = 67;
+	@XbcExpTokenAnnotation(id="invoke", name="invoke", value="invoke")
+	public static final int INVOKE_TT = 68;
 	@XbcExpTokenAnnotation(id="eof", name="结束符", value="eof")
 	public static final int EOF_TT = 99;
 	
@@ -170,4 +180,5 @@ public class XbcExpToken {
 			}
 		}
 	}
+
 }

+ 7 - 0
src/engine/java/xbc/formula/engine/exp/exec/XbcExpBreakException.java

@@ -0,0 +1,7 @@
+package xbc.formula.engine.exp.exec;
+
+public class XbcExpBreakException extends RuntimeException {
+	
+	private static final long serialVersionUID = 6209313546048811716L;
+
+}

+ 188 - 10
src/engine/java/xbc/formula/engine/exp/exec/XbcExpCalculateExp.java

@@ -1,5 +1,6 @@
 package xbc.formula.engine.exp.exec;
 
+import java.lang.reflect.Field;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.util.ArrayList;
@@ -35,7 +36,9 @@ public class XbcExpCalculateExp {
 	
 	private XbcExpCalculatorExpFunc calculatorExpFunc;
 	
-	private Map<String, Object> varMap;
+	private XbcExpCalculatorExpNew calculatorExpNew;
+	
+	private Map<String, XbcExpResultVo> varMap;
 	
 	private List<BigDecimal> div0List;
 	
@@ -52,20 +55,38 @@ public class XbcExpCalculateExp {
 		calculatorExp2Op = new XbcExpCalculatorExp2Op(this, weishu, roundMode, expStr);
 		calculatorExpItv = new XbcExpCalculatorExpItv(this, weishu, roundMode, expStr);
 		calculatorExpFunc = new XbcExpCalculatorExpFunc(this, weishu, roundMode, expStr, formulaParams);
+		calculatorExpNew = new XbcExpCalculatorExpNew(calculatorExpFunc, expStr);
 	}
 
 	public Object calculate(XbcExpExpTree exp) {
-		if(exp == null) {
+		Object ret = null;
+		try {
+			ret = calculateEx(exp);
+		} catch(XbcExpExitException x) {
+			ret = x.getResult().value;
+		}
+		return ret;
+	}
+
+	public Object calculateEx(XbcExpExpTree exp) {
+		if (exp == null) {
 			return null;
 		}
 		XbcExpResultVo result = new XbcExpResultVo();
-		while(exp != null) { // 执行完所有表达式,输出最后一个表达式的值
-			calcExp(exp, result);
+		while (exp != null) { // 执行完所有表达式,输出最后一个表达式的值
+			if (exp.ek != XbcExpExpKind.OP_EK || exp.ok != XbcExpExpOpKind.NULL_OK) {
+				try {
+					calcExp(exp, result);
+				} catch (XbcExpExitException x) {
+					// result.value = x.getResult().value;
+					throw x;
+				}
+			}
 			exp = exp.next;
 		}
 		return result.value;
 	}
-	
+
 	protected void calcExp(XbcExpExpTree exp, XbcExpResultVo result) {
 		if(exp.ek == XbcExpExpKind.OP_EK) {
 			calcOpExp(exp, result);
@@ -76,8 +97,8 @@ public class XbcExpCalculateExp {
 			XbcExpResultVo pv = indicatorMap.get(key);
 			if(pv == null) {
 				if(varMap.containsKey(key)) {
-					Object varVal = varMap.get(key);
-					result.value = varVal;
+					XbcExpResultVo varVal = varMap.get(key);
+					result.value = varVal.value;
 					return;
 				}
 				throw new XbcExpExecException("需要传入一个名为【" + key + "】的参数。公式: " + expStr);
@@ -188,9 +209,165 @@ public class XbcExpCalculateExp {
 	    case XbcExpExpOpKind.DIV0_OK:
 	    	calcDiv0Exp(exp, result);
 	    	break;
+	    case XbcExpExpOpKind.EXIT_OK:
+	    	calcExitExp(exp, result);
+	    	break;
+	    case XbcExpExpOpKind.NEW_OK:
+	    	calculatorExpNew.calcNewExp(exp, result);
+	    	break;
+	    case XbcExpExpOpKind.INVOKE_OK:
+	    	calculatorExpNew.calcInvokeExp(exp, result);
+	    	break;
+
+	    case XbcExpExpOpKind.PRD_OK:
+	    	calcPrdExp(exp, result);
+	    	break;
+	    case XbcExpExpOpKind.FOR_OK:
+	    	calcForExp(exp, result);
+	    	break;
+	    case XbcExpExpOpKind.BREAK_OK:
+	    	calcBreakExp(exp, result);
+	    	break;
+	    case XbcExpExpOpKind.CONTINUE_OK:
+	    	calcContinueExp(exp, result);
+	    	break;
+	    case XbcExpExpOpKind.WHILE_OK:
+	    	calcWhileExp(exp, result);
+	    	break;
+	    case XbcExpExpOpKind.IF_OK:
+	    	calcIfExp(exp, result);
+	    	break;
+		}
+	}
+	
+	private void calcExitExp(XbcExpExpTree exp, XbcExpResultVo result) {
+		calcExp(exp.lchild, result);
+		throw new XbcExpExitException(result);
+	}
+	
+	private void calcIfExp(XbcExpExpTree exp, XbcExpResultVo result) {
+		XbcExpResultVo pr = new XbcExpResultVo();
+		calcExp(exp.lchild, pr);
+		boolean ifResult = false;
+		if(pr.value != null && (pr.value.getClass() == Boolean.class || pr.value.getClass() == boolean.class)) {
+			if(pr.value.getClass() == Boolean.class) {
+				ifResult = ((Boolean)(pr.value)).booleanValue();
+			} else {
+				ifResult = (boolean)(pr.value);
+			}
+		} else {
+			throw new XbcExpExecException("if语句的条件表达式的结果不是bool类型。公式: " + expStr);
+		}
+		Object ov = null;
+		if(ifResult) {
+			ov = calculateEx(exp.mchild);
+		} else if(exp.rchild != null) {
+			ov = calculateEx(exp.rchild);
+		}
+		result.value = ov;
+	}
+	
+	private void calcBreakExp(XbcExpExpTree exp, XbcExpResultVo result) {
+		throw new XbcExpBreakException();
+	}
+
+	private void calcContinueExp(XbcExpExpTree exp, XbcExpResultVo result) {
+		throw new XbcExpContinueException();
+	}
+	
+	private void calcWhileExp(XbcExpExpTree exp, XbcExpResultVo result) {
+		XbcExpResultVo pr = new XbcExpResultVo();
+		while(true) {
+			calcExp(exp.lchild, pr);
+			if(pr.value != null && (pr.value.getClass() == Boolean.class || pr.value.getClass() == boolean.class)) {
+				if(pr.value.getClass() == Boolean.class) {
+					Boolean bv = (Boolean)(pr.value);
+					if(!bv) {
+						break;
+					}
+				} else {
+					boolean bv = (boolean)(pr.value);
+					if(!bv) {
+						break;
+					}
+				}
+			} else {
+				throw new XbcExpExecException("while语句的条件表达式的结果不是bool类型。公式: " + expStr);
+			}
+			try {
+				if(exp.body != null) {
+					result.value = calculateEx(exp.body);
+				}
+			} catch(XbcExpBreakException cx) {
+				break;
+			} catch(XbcExpContinueException cx) {
+				// continue;
+			}
+		}
+	}
+	
+	private void calcForExp(XbcExpExpTree exp, XbcExpResultVo result) {
+		XbcExpResultVo pr = new XbcExpResultVo();
+		if(exp.lchild != null) {
+			calcExp(exp.lchild, pr);
+		}
+		while(true) {
+			if(exp.mchild != null) {
+				calcExp(exp.mchild, pr);
+				if(pr.value != null && (pr.value.getClass() == Boolean.class || pr.value.getClass() == boolean.class)) {
+					if(pr.value.getClass() == Boolean.class) {
+						Boolean bv = (Boolean)(pr.value);
+						if(!bv) {
+							break;
+						}
+					} else {
+						boolean bv = (boolean)(pr.value);
+						if(!bv) {
+							break;
+						}
+					}
+				} else {
+					throw new XbcExpExecException("for语句的中间表达式的结果不是bool类型。公式: " + expStr);
+				}
+			}
+			try {
+				if(exp.body != null) {
+					result.value = calculateEx(exp.body);
+				}
+			} catch(XbcExpBreakException cx) {
+				break;
+			} catch(XbcExpContinueException cx) {
+				// continue;
+			}
+			if(exp.rchild != null) {
+				calcExp(exp.rchild, pr);
+			}
 		}
 	}
 	
+	private void calcPrdExp(XbcExpExpTree exp, XbcExpResultVo result) {
+		XbcExpExpTree lchild = exp.lchild;
+		String fieldName = (String)exp.value;
+		XbcExpResultVo pr = new XbcExpResultVo();
+		calcExp(lchild, pr);
+		if(pr.value == null) {
+			throw new XbcExpExecException(fieldName + " 的前面为空值。公式: " + expStr);
+		}
+		try {
+			Field field = pr.value.getClass().getDeclaredField(fieldName);
+			if(field == null) {
+				throw new XbcExpExecException(fieldName + " 不是成员变量。");
+			}
+			field.setAccessible(true);
+			Object ret = field.get(pr.value);
+			result.value = ret;
+		} catch (NoSuchFieldException nx) {
+			throw new XbcExpExecException(fieldName + " 不是成员变量。");
+		} catch(SecurityException | IllegalArgumentException | IllegalAccessException sx) {
+			throw new XbcExpExecException(sx, fieldName + "执行出错。");
+		}
+	}
+
 	private void calcDiv0Exp(XbcExpExpTree exp, XbcExpResultVo result) {
 		calcExp(exp.lchild, result);
 		BigDecimal bv = XbcExpNumericUtil.translate2BigDecimal(result.value, weishu, roundMode, expStr);
@@ -225,9 +402,10 @@ public class XbcExpCalculateExp {
 			String key = (String)exp.value;
 			result = indicatorMap.get(key);
 			if(result == null) {
-				result = new XbcExpResultVo();
 				if(varMap.containsKey(key)) {
-					result.value = varMap.get(key);
+					result = varMap.get(key);
+				} else {
+					result = new XbcExpResultVo();
 				}
 				return result;
 			}
@@ -250,7 +428,7 @@ public class XbcExpCalculateExp {
 		if(varMap.containsKey(key)) {
 			varMap.remove(key);
 		}
-		varMap.put(key, rr.value);
+		varMap.put(key, rr);
 	}
 
 	private void calcQryExp(XbcExpExpTree exp, XbcExpResultVo result) {

+ 131 - 0
src/engine/java/xbc/formula/engine/exp/exec/XbcExpCalculatorExpFunc.java

@@ -1,10 +1,14 @@
 package xbc.formula.engine.exp.exec;
 
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.util.ArrayList;
 import java.util.List;
 
+import xbc.formula.engine.exp.datatype.XbcExpExpKind;
+import xbc.formula.engine.exp.datatype.XbcExpExpOpKind;
 import xbc.formula.engine.exp.datatype.XbcExpExpTree;
 import xbc.formula.engine.exp.exception.XbcExpExecException;
 import xbc.formula.engine.exp.ext.XbcExpExtFuncManager;
@@ -42,12 +46,118 @@ public class XbcExpCalculatorExpFunc {
 		calculatorExpFuncDate = new XbcExpCalculatorExpFuncDate(this, expStr);
 	}
 
+	protected Method findMethod(Class<?> clazz, String methodName, List<Object> pvs) {
+		boolean hasNullParam = false;
+		Class<?>[] pts = new Class<?>[pvs.size()];
+		for(int k = 0;k < pvs.size();k ++) {
+			if(pvs.get(k) == null) {
+				hasNullParam = true;
+				break;
+			} else {
+				pts[k] = pvs.get(k).getClass();
+			}
+		}
+		if(!hasNullParam) {
+			Method method = null;
+			try {
+				method = clazz.getDeclaredMethod(methodName, pts);
+			} catch (NoSuchMethodException | SecurityException e) {
+				//throw new XbcExpExecException("获取方法" + methodName + "失败。公式: " + expStr);
+			}
+			if(method != null) {
+				return method;
+			}
+		}
+		Method[] methods = clazz.getMethods();
+		for(Method method : methods) {
+			if(method.getParameterCount() == pvs.size() && method.getName().equals(methodName)) {
+				if(!hasNullParam) {
+					Class<?>[] pts2 = method.getParameterTypes();
+					boolean matched = true;
+					for(int k = 0;k < pts.length;k ++) {
+						Class<?> c1 = translateClass(pts[k]);
+						Class<?> c2 = translateClass(pts2[k]);
+						if(c1 != c2) {
+							matched = false;
+							break;
+						}
+					}
+					if(matched) {
+						return method;
+					}
+				} else {
+					return method;
+				}
+			}
+		}
+		return null;
+	}
+	
+	private Class<?> translateClass(Class<?> c) {
+		if(c == Integer.class) {
+			return int.class;
+		}
+		if(c == Long.class) {
+			return long.class;
+		}
+		if(c == Double.class) {
+			return double.class;
+		}
+		if(c == Float.class) {
+			return float.class;
+		}
+		if(c == Boolean.class) {
+			return boolean.class;
+		}
+		if(c == Short.class) {
+			return short.class;
+		}
+		if(c == Byte.class) {
+			return byte.class;
+		}
+		return c;
+	}
+	
+	private void calcPrdExp(XbcExpExpTree exp, XbcExpResultVo result) {
+		XbcExpExpTree lchild = exp.lchild;
+		String methodName = (String)lchild.value;
+		List<Object> pvs = getFuncParams(exp);
+		XbcExpResultVo pr = new XbcExpResultVo();
+		calculateExp.calcExp(lchild.lchild, pr);
+		if(pr.value == null) {
+			throw new XbcExpExecException(methodName + " 的前面为空值。公式: " + expStr);
+		}
+		Method method = findMethod(pr.value.getClass(), methodName, pvs);
+		if(method == null) {
+			throw new XbcExpExecException(pr.value.getClass().getName() + " 里面,没有找到参数个数为 " + pvs.size() + "个的名称为" + methodName + "的方法。公式: " + expStr);
+		}
+		Object[] args = new Object[pvs.size()];
+		for(int k = 0;k < pvs.size();k ++) {
+			args[k] = pvs.get(k);
+		}
+		try {
+			Object ret = method.invoke(pr.value, args);
+			result.value = ret;
+		} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+			throw new XbcExpExecException(e, methodName + "执行出错。");
+		}
+	}
+
 	public void calcFuncExp(XbcExpExpTree exp, XbcExpResultVo result) {
+		XbcExpExpTree lchild = exp.lchild;
+		if(lchild.ek == XbcExpExpKind.OP_EK && lchild.ok == XbcExpExpOpKind.PRD_OK) {
+			calcPrdExp(exp, result);
+			return;
+		}
 		String funcName = (String)exp.lchild.value;
 		if(funcName.equals("min")) {
 			calcMinFunc(exp, result);
 		} else if(funcName.equals("max")) {
 			calcMaxFunc(exp, result);
+		} else if(funcName.equals("write")) {
+			calcWriteFunc(exp, result);
+		} else if(funcName.equals("writeln")) {
+			calcWritelnFunc(exp, result);
 		} else if(funcName.equals("roundUp")) {
 			calculatorExpFuncRound.calcRoundUpFunc(exp, result);
 		} else if(funcName.equals("roundHalfUp")) {
@@ -118,4 +228,25 @@ public class XbcExpCalculatorExpFunc {
 		}
 		result.value = maxBv;
 	}
+
+	private void calcWriteFunc(XbcExpExpTree exp, XbcExpResultVo result) {
+		if(exp.params.size() < 1) {
+			throw new XbcExpExecException("write函数至少需要一个参数。");
+		}
+		List<Object> pvs = getFuncParams(exp);
+		for(int k = 0;k < pvs.size();k ++) {
+			if(pvs.get(k) != null) {
+				System.out.print(pvs.get(k).toString());
+			} else {
+				System.out.print("null");
+			}
+		}
+	}
+	
+	private void calcWritelnFunc(XbcExpExpTree exp, XbcExpResultVo result) {
+		if(exp.params.size() >= 1) {
+			calcWriteFunc(exp, result);
+		}
+		System.out.println();
+	}
 }

+ 139 - 0
src/engine/java/xbc/formula/engine/exp/exec/XbcExpCalculatorExpNew.java

@@ -0,0 +1,139 @@
+package xbc.formula.engine.exp.exec;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import xbc.formula.engine.exp.datatype.XbcExpExpTree;
+import xbc.formula.engine.exp.exception.XbcExpExecException;
+import xbc.formula.engine.exp.vo.XbcExpResultVo;
+
+public class XbcExpCalculatorExpNew {
+	
+	private XbcExpCalculatorExpFunc calculatorExpFunc;
+
+	private String expStr;
+
+	public XbcExpCalculatorExpNew(XbcExpCalculatorExpFunc calculatorExpFunc, String expStr) {
+		this.calculatorExpFunc = calculatorExpFunc;
+		this.expStr = expStr;
+	}
+
+	public void calcInvokeExp(XbcExpExpTree exp, XbcExpResultVo result) {
+		List<Object> pvs = calculatorExpFunc.getFuncParams(exp);
+		if(pvs == null || pvs.size() < 2) {
+			throw new XbcExpExecException((String)exp.value + "函数至少需要两个参数: 类名, 方法名。公式: " + expStr);
+		}
+		Object p2 = pvs.get(1);
+		if(p2 == null) {
+			throw new XbcExpExecException((String)exp.value + "函数的第二个参数不能为null。公式: " + expStr);
+		}
+		if(p2.getClass() != String.class) {
+			throw new XbcExpExecException((String)exp.value + "函数的第二个参数必须为字符串。公式: " + expStr);
+		}
+		Class<?> clazz = getClass4Create(exp, pvs);
+		String methodName = (String)p2;
+		List<Object> mpvs = new ArrayList<>();
+		for(int k = 2;k < pvs.size();k ++) {
+			mpvs.add(pvs.get(k));
+		}
+		Method method = calculatorExpFunc.findMethod(clazz, methodName, mpvs);
+		if(method == null) {
+			throw new XbcExpExecException(clazz.getName() + " 里面,没有找到参数个数为 " + mpvs.size() + "个的名称为" + methodName + "的方法。公式: " + expStr);
+		}
+		Object[] args = new Object[mpvs.size()];
+		for(int k = 0;k < mpvs.size();k ++) {
+			args[k] = mpvs.get(k);
+		}
+		try {
+			Object ret = method.invoke(null, args);
+			result.value = ret;
+		} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+			e.printStackTrace();
+			throw new XbcExpExecException(e, methodName + "执行出错。");
+		}
+	}
+
+	public void calcNewExp(XbcExpExpTree exp, XbcExpResultVo result) {
+		List<Object> pvs = calculatorExpFunc.getFuncParams(exp);
+		if(pvs == null || pvs.size() == 0) {
+			throw new XbcExpExecException((String)exp.value + "函数必须要跟参数。公式: " + expStr);
+		}
+		Class<?> clazz = getClass4Create(exp, pvs);
+		Constructor<?> cc = getConstructor4Class(exp, clazz, pvs);
+		Object[] pts = new Object[pvs.size() - 1];
+		for(int k = 1;k < pvs.size();k ++) {
+			pts[k - 1] = pvs.get(k);
+		}
+		try {
+			Object inst = cc.newInstance(pts);
+			result.value = inst;
+		} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
+				| InvocationTargetException e) {
+			throw new XbcExpExecException((String)exp.value + "函数运行失败,实例化类[" + (String)(pvs.get(0)) + "]失败。公式: " + expStr);
+		}
+	}
+
+	private Class<?> getClass4Create(XbcExpExpTree exp, List<Object> pvs) {
+		Object p1 = pvs.get(0);
+		if(p1 == null) {
+			throw new XbcExpExecException((String)exp.value + "函数的第一个参数不能为null。公式: " + expStr);
+		}
+		Class<?> clazz = p1.getClass();
+		if(clazz != Class.class && clazz != String.class) {
+			throw new XbcExpExecException((String)exp.value + "函数的第一个参数必须是 Class 类型或 String 类型。公式: " + expStr);
+		}
+		if(clazz == String.class) {
+			try {
+				clazz = Class.forName((String)p1);
+			} catch (ClassNotFoundException e) {
+				throw new XbcExpExecException((String)exp.value + "函数运行失败,类[" + (String)p1 + "]无法被加载。公式: " + expStr);
+			}
+		}
+		return clazz;
+	}
+	
+	private Constructor<?> getConstructor4Class(XbcExpExpTree exp, Class<?> clazz, List<Object> pvs) {
+		Object p1 = pvs.get(0);
+		Constructor<?>[] cs = clazz.getConstructors();
+		if(cs == null || cs.length == 0) {
+			throw new XbcExpExecException((String)exp.value + "函数运行失败,类[" + (String)p1 + "]没有构造函数。公式: " + expStr);
+		}
+		int pc = pvs.size() - 1;
+		boolean dup = false;
+		Constructor<?> cc = null;
+		for(Constructor<?> c : cs) {
+			if(c.getParameterCount() == pc) {
+				if(cc != null) {
+					dup = true;
+				} else {
+					cc = c;
+				}
+			}
+		}
+		if(dup) {
+			boolean hasNullParam = false;
+			Class<?>[] pts = new Class<?>[pvs.size() - 1];
+			for(int k = 1;k < pvs.size();k ++) {
+				if(pvs.get(k) == null) {
+					hasNullParam = true;
+					break;
+				} else {
+					pts[k - 1] = pvs.get(k).getClass();
+				}
+			}
+			if(hasNullParam) {
+				throw new XbcExpExecException((String)exp.value + "函数运行失败,无法匹配到类[" + (String)p1 + "]的构造函数。公式: " + expStr);
+			}
+			try {
+				cc = clazz.getConstructor(pts);
+			} catch (NoSuchMethodException | SecurityException e) {
+				throw new XbcExpExecException((String)exp.value + "函数运行失败,获取类[" + (String)p1 + "]的构造函数失败。公式: " + expStr);
+			}
+		}
+		return cc;
+	}
+
+}

+ 7 - 0
src/engine/java/xbc/formula/engine/exp/exec/XbcExpContinueException.java

@@ -0,0 +1,7 @@
+package xbc.formula.engine.exp.exec;
+
+public class XbcExpContinueException extends RuntimeException {
+	
+	private static final long serialVersionUID = -2320763075227861770L;
+
+}

+ 19 - 0
src/engine/java/xbc/formula/engine/exp/exec/XbcExpExitException.java

@@ -0,0 +1,19 @@
+package xbc.formula.engine.exp.exec;
+
+import xbc.formula.engine.exp.vo.XbcExpResultVo;
+
+public class XbcExpExitException extends RuntimeException {
+
+	private static final long serialVersionUID = 1928428482871266235L;
+
+	private XbcExpResultVo result;
+	
+	public XbcExpExitException(XbcExpResultVo result) {
+		this.result = result;
+	}
+	
+	public XbcExpResultVo getResult() {
+		return result;
+	}
+
+}

+ 248 - 46
src/engine/java/xbc/formula/engine/exp/parser/XbcExpParser.java

@@ -47,7 +47,7 @@ public class XbcExpParser {
 	public Set<String> getParamSet() {
 		return paramSet;
 	}
-
+	
 	public List<XbcExpDrawnInfoVo> getDrawnInfoVos() {
 		if(es == null) {
 			return null;
@@ -57,50 +57,81 @@ public class XbcExpParser {
 	
 	public XbcExpExpTree parse() {
 		es = new XbcExpScanner(expStr, mkDiv);
-		XbcExpExpTree firstExp = null;
-		XbcExpExpTree exp = null;
-		XbcExpExpTree lastExp = null;
 		token = es.readToken();
-		while(token != XbcExpToken.EOF_TT) {
-			switch(token) {
-			case XbcExpToken.EXPNAME_TT: // variable-name
-			case XbcExpToken.INT_TT:     // integer
-			case XbcExpToken.DBL_TT:     // double
-			case XbcExpToken.STR_TT:     // string
-			case XbcExpToken.LPRN_TT:    // (
-			case XbcExpToken.SELFMNS_TT: // --
-			case XbcExpToken.SELFPLS_TT: // ++
-			case XbcExpToken.PLS_TT:     // +
-			case XbcExpToken.MNS_TT:     // -
-			case XbcExpToken.BNOT_TT:    // ~
-			case XbcExpToken.NOT_TT:     // !
-				exp = readExpTree();
-				break;
-			case XbcExpToken.DIV0_TT:     // div0
-				exp = readDiv0Exp();
-				break;
-			default:
-				throw new XbcExpParseException("未知的符号: " + XbcExpToken.getTokenName(token) + ", 公式: " + expStr);
-			}
-			if(firstExp == null) {
-				firstExp = exp;
-			}
-			if(lastExp != null) {
-				lastExp.next = exp;
-			}
-			lastExp = exp;
-			//token = es.readToken();
-			if(token == XbcExpToken.EOF_TT) {
+		XbcExpExpTree exp = readExpSequence();
+		return exp;
+	}
+
+	private XbcExpExpTree readExpSequence() {
+		XbcExpExpTree exp = readNextExp();
+		XbcExpExpTree next = exp;
+		while(next != null && next.next != null) {
+			next = next.next;
+		}
+		while(next != null) {
+			next.next = readNextExp();
+			if(next.next == null) {
 				break;
 			}
-			if(token != XbcExpToken.SEMI_TT) { // 用分号来分隔多个表达式
-				throw new XbcExpParseException("多余的符号: " + XbcExpToken.getTokenName(token) + ", 公式: " + expStr);
-			}
-			while(token == XbcExpToken.SEMI_TT) {
-				match(XbcExpToken.SEMI_TT);
+			while(next.next != null) {
+				next = next.next;
 			}
 		}
-		return firstExp;
+		return exp;
+	}
+
+	private XbcExpExpTree readNextExp() {
+		XbcExpExpTree exp = null;
+		switch(token) {
+		case XbcExpToken.EXPNAME_TT: // variable-name
+		case XbcExpToken.INT_TT:     // integer
+		case XbcExpToken.DBL_TT:     // double
+		case XbcExpToken.STR_TT:     // string
+		case XbcExpToken.LPRN_TT:    // (
+		case XbcExpToken.SELFMNS_TT: // --
+		case XbcExpToken.SELFPLS_TT: // ++
+		case XbcExpToken.PLS_TT:     // +
+		case XbcExpToken.MNS_TT:     // -
+		case XbcExpToken.BNOT_TT:    // ~
+		case XbcExpToken.NOT_TT:     // !
+		case XbcExpToken.NEW_TT:     // new
+		case XbcExpToken.INVOKE_TT:
+			exp = readAsnExp();
+			break;
+		case XbcExpToken.FOR_TT:     // for
+			exp = readForExp();
+			break;
+		case XbcExpToken.BREAK_TT:   // break;
+			exp = readBreakExp();
+			break;
+		case XbcExpToken.CONTINUE_TT: // continue
+			exp = readContinueExp();
+			break;
+		case XbcExpToken.WHILE_TT:    // while
+			exp = readWhileExp();
+			break;
+		case XbcExpToken.IF_TT:      // if
+			exp = readIfExp();
+			break;
+		case XbcExpToken.LSQB_TT:    // {
+			exp = readBlockExp();
+			break;
+		case XbcExpToken.DIV0_TT:     // div0
+			exp = readDiv0Exp();
+			break;
+		case XbcExpToken.EXIT_TT:     // exit
+			exp = readExitExp();
+			break;
+		case XbcExpToken.SEMI_TT:
+			match(XbcExpToken.SEMI_TT);
+			exp = new XbcExpExpTree(XbcExpExpOpKind.NULL_OK);
+			break;
+		case XbcExpToken.EOF_TT:
+			break;
+		default:
+			throw new XbcExpParseException("未知的符号: " + XbcExpToken.getTokenName(token) + ", 公式: " + expStr);
+		}
+		return exp;
 	}
 	
 	private void match(int expectedToken) {
@@ -109,7 +140,64 @@ public class XbcExpParser {
 		}
 		token = es.readToken();
 	}
+
+	private XbcExpExpTree readExitExp() {
+		match(XbcExpToken.EXIT_TT);
+		XbcExpExpTree exp = new XbcExpExpTree(XbcExpExpOpKind.EXIT_OK);
+		exp.lchild = readAsnExp();
+		return exp;
+	}
+
+	private XbcExpExpTree readInvokeExp() {
+		String tokenContent = es.getTokenContent();
+		match(XbcExpToken.INVOKE_TT);
+		XbcExpExpTree exp = new XbcExpExpTree(XbcExpExpOpKind.INVOKE_OK);
+		exp.value = tokenContent;
+		exp.params = new ArrayList<>();
+
+		match(XbcExpToken.LPRN_TT);
+		while(token != XbcExpToken.RPRN_TT) {
+			XbcExpExpTree pexp = readAsnExp();
+			exp.params.add(pexp);
+			if(token == XbcExpToken.CMM_TT) {
+				match(token);
+				if(token == XbcExpToken.RPRN_TT) {
+					throw new XbcExpParseException("解析函数【" + tokenContent + "】的参数时出错。" + " 公式: " + expStr);
+				}
+			} else if(token != XbcExpToken.RPRN_TT) {
+				throw new XbcExpParseException("解析函数【" + tokenContent + "】的参数时出错。" + " 公式: " + expStr);
+			}
+		}
+		match(XbcExpToken.RPRN_TT);
+		
+		return exp;
+	}
 	
+	private XbcExpExpTree readNewExp() {
+		String tokenContent = es.getTokenContent();
+		match(XbcExpToken.NEW_TT);
+		XbcExpExpTree exp = new XbcExpExpTree(XbcExpExpOpKind.NEW_OK);
+		exp.value = tokenContent;
+		exp.params = new ArrayList<>();
+
+		match(XbcExpToken.LPRN_TT);
+		while(token != XbcExpToken.RPRN_TT) {
+			XbcExpExpTree pexp = readAsnExp();
+			exp.params.add(pexp);
+			if(token == XbcExpToken.CMM_TT) {
+				match(token);
+				if(token == XbcExpToken.RPRN_TT) {
+					throw new XbcExpParseException("解析函数【" + tokenContent + "】的参数时出错。" + " 公式: " + expStr);
+				}
+			} else if(token != XbcExpToken.RPRN_TT) {
+				throw new XbcExpParseException("解析函数【" + tokenContent + "】的参数时出错。" + " 公式: " + expStr);
+			}
+		}
+		match(XbcExpToken.RPRN_TT);
+		
+		return exp;
+	}
+
 	private XbcExpExpTree readDiv0Exp() {
 		match(XbcExpToken.DIV0_TT);
 		XbcExpExpTree exp = new XbcExpExpTree(XbcExpExpOpKind.DIV0_OK);
@@ -119,9 +207,97 @@ public class XbcExpParser {
 		exp.lchild = texp;
 		return exp;
 	}
+
+	private XbcExpExpTree readBlockExp() {
+		match(XbcExpToken.LSQB_TT);
+		XbcExpExpTree exp = null;
+		if(token == XbcExpToken.RSQB_TT) {
+			match(XbcExpToken.RSQB_TT);
+			exp = new XbcExpExpTree(XbcExpExpOpKind.NULL_OK);
+		} else {
+			exp = readNextExp();
+			XbcExpExpTree tail = exp;
+			XbcExpExpTree next = exp;
+			while(tail.next != null) {
+				tail = tail.next;
+			}
+			while(token != XbcExpToken.RSQB_TT) {
+				if(next == null) {
+					throw new XbcExpParseException("没有结束的\"}\"。 公式: " + expStr);
+				}
+				next = readNextExp();
+				tail.next = next;
+				tail = next;
+				if(next != null) {
+					while(tail.next != null) {
+						tail = tail.next;
+					}
+				}
+			}
+			match(XbcExpToken.RSQB_TT);
+		}
+		return exp;
+	}
+	
+	private XbcExpExpTree readIfExp() {
+		match(XbcExpToken.IF_TT);
+		XbcExpExpTree exp = new XbcExpExpTree(XbcExpExpOpKind.IF_OK);
+		match(XbcExpToken.LPRN_TT);
+		exp.lchild = readAsnExp();
+		match(XbcExpToken.RPRN_TT);
+		exp.mchild = readNextExp();
+		if(token == XbcExpToken.ELSE_TT) {
+			match(XbcExpToken.ELSE_TT);
+			exp.rchild = readNextExp();
+		}
+		return exp;
+	}
+
+	private XbcExpExpTree readBreakExp() {
+		match(XbcExpToken.BREAK_TT);
+		XbcExpExpTree exp = new XbcExpExpTree(XbcExpExpOpKind.BREAK_OK);
+		return exp;
+	}
+
+	private XbcExpExpTree readContinueExp() {
+		match(XbcExpToken.CONTINUE_TT);
+		XbcExpExpTree exp = new XbcExpExpTree(XbcExpExpOpKind.CONTINUE_OK);
+		return exp;
+	}
 	
-	private XbcExpExpTree readExpTree() {
-		XbcExpExpTree exp = readAsnExp();
+	private XbcExpExpTree readWhileExp() {
+		match(XbcExpToken.WHILE_TT);
+		XbcExpExpTree exp = new XbcExpExpTree(XbcExpExpOpKind.WHILE_OK);
+		match(XbcExpToken.LPRN_TT);
+		exp.lchild = readAsnExp();
+		match(XbcExpToken.RPRN_TT);
+		exp.body = readNextExp();
+		return exp;
+	}
+	
+	private XbcExpExpTree readForExp() {
+		match(XbcExpToken.FOR_TT);
+		XbcExpExpTree exp = new XbcExpExpTree(XbcExpExpOpKind.FOR_OK);
+		match(XbcExpToken.LPRN_TT);
+		if(token != XbcExpToken.SEMI_TT) {
+			exp.lchild = readAsnExp();
+		} else {
+			exp.lchild = null;
+		}
+		match(XbcExpToken.SEMI_TT);
+		if(token != XbcExpToken.SEMI_TT) {
+			exp.mchild = readAsnExp();
+		} else {
+			exp.mchild = null;
+		}
+		match(XbcExpToken.SEMI_TT);
+		if(token != XbcExpToken.SEMI_TT) {
+			exp.rchild = readAsnExp();
+		} else {
+			exp.rchild = null;
+		}
+		match(XbcExpToken.RPRN_TT);
+		exp.body = readNextExp();
 		return exp;
 	}
 	
@@ -503,6 +679,7 @@ public class XbcExpParser {
 
 	private boolean isPfEt(int t) {
 		switch(t) {
+	    case XbcExpToken.PRD_TT:
 	    case XbcExpToken.LPRN_TT:
 	        return true;
 		}
@@ -535,6 +712,17 @@ public class XbcExpParser {
 		}
 		while(isPfEt(token)) {
 			switch(token) {
+			case XbcExpToken.PRD_TT:
+				match(token);
+				if(token != XbcExpToken.EXPNAME_TT) {
+					throw new XbcExpParseException("点号后面应该接一个成员变量名或方法名。" + " 公式: " + expStr);
+				}
+				XbcExpExpTree exp2 = new XbcExpExpTree(XbcExpExpOpKind.PRD_OK);
+				exp2.lchild = exp;
+				exp2.value =  es.getTokenContent();
+				match(token);
+				exp = exp2;
+				break;
 			case XbcExpToken.LPRN_TT:
 				match(token);
 				XbcExpExpTree exp1 = new XbcExpExpTree(XbcExpExpOpKind.FUNC_OK);
@@ -566,9 +754,17 @@ public class XbcExpParser {
 		switch(token) {
 		case XbcExpToken.EXPNAME_TT:
 			String tokenContent = es.getTokenContent();
-			exp = XbcExpExpTree.newIdExptree(tokenContent);
-			if(!removedParamSet.contains(tokenContent)) {
-				paramSet.add(tokenContent);
+			if(tokenContent.equals("true")) {
+				exp = XbcExpExpTree.newConstBoolExptree(true);
+			} else if(tokenContent.equals("false")) {
+				exp = XbcExpExpTree.newConstBoolExptree(false);
+			} else if(tokenContent.equals("null")) {
+				exp = XbcExpExpTree.newConstNullExptree();
+			} else {
+				exp = XbcExpExpTree.newIdExptree(tokenContent);
+				if(!removedParamSet.contains(tokenContent)) {
+					paramSet.add(tokenContent);
+				}
 			}
 			match(token);
 			break;
@@ -586,9 +782,15 @@ public class XbcExpParser {
 			break;
 		case XbcExpToken.LPRN_TT:
 			match(token);
-			exp = readExpTree();
+			exp = readAsnExp();
 			match(XbcExpToken.RPRN_TT);
 			break;
+		case XbcExpToken.NEW_TT:     // new
+			exp = readNewExp();
+			break;
+		case XbcExpToken.INVOKE_TT:
+			exp = readInvokeExp();
+			break;
 		default:
 			throw new XbcExpParseException("读取表达式出错: " + es.getTokenContent() + ", 公式: " + expStr);
 		}

+ 76 - 10
src/engine/java/xbc/formula/engine/exp/scanner/XbcExpScanner.java

@@ -275,6 +275,20 @@ public class XbcExpScanner {
                     token = XbcExpToken.CMM_TT;
 	                state = SCAN_DONE_STATE;
 	                break;
+	            case '.':
+					appendDivChar(c);
+	            	nextC = getNextChar();
+	            	if(nextC >= '0' && nextC <= '9') {
+		            	tokenContent.append('0');
+		            	tokenContent.append('.');
+		            	tokenContent.append(nextC);
+		                state = SCAN_DBL_STATE;
+	            	}   else {
+	            		ungetNextChar();
+	            		token = XbcExpToken.PRD_TT;
+		                state = SCAN_DONE_STATE;
+	            	}
+	            	break;
 	            case ':':
 					appendDivChar(c);
 					addDiv(XbcExpDrawnInfoVo.OPERATOR_TYPE);
@@ -460,11 +474,7 @@ public class XbcExpScanner {
 	            	tokenContent.append(c);
 	            } else {
 					addDiv(XbcExpDrawnInfoVo.VARIABLE_TYPE);
-					if(tokenContent.toString().equals("div0")) {
-						token = XbcExpToken.DIV0_TT;
-					} else {
-						token = XbcExpToken.EXPNAME_TT;
-					}
+					token = XbcExpToken.EXPNAME_TT;
                     state = SCAN_DONE_STATE;
                     ungetNextChar();
 	            }
@@ -475,11 +485,7 @@ public class XbcExpScanner {
 	            	tokenContent.append(c);
 	            } else {
 					addDiv(XbcExpDrawnInfoVo.VARIABLE_TYPE);
-					if(tokenContent.toString().equals("div0")) {
-						token = XbcExpToken.DIV0_TT;
-					} else {
-						token = XbcExpToken.EXPNAME_TT;
-					}
+					token = XbcExpToken.EXPNAME_TT;
                     state = SCAN_DONE_STATE;
                     ungetNextChar();
 	            }
@@ -612,6 +618,8 @@ public class XbcExpScanner {
 					addDiv(XbcExpDrawnInfoVo.CONSTANT_STRING_TYPE);
 					token = XbcExpToken.STR_TT;
 	                state = SCAN_DONE_STATE;
+	            }   else if(c == 92) {
+	            	charEscape();
 	            }   else {
 					appendDivChar(c);
 	            	tokenContent.append(c);
@@ -619,9 +627,67 @@ public class XbcExpScanner {
 	            break;
 			}
 		}
+		if(token == XbcExpToken.EXPNAME_TT) {
+			String ts = tokenContent.toString();
+			if(ts.equals("for")) {
+				token = XbcExpToken.FOR_TT;
+			} else if(ts.equals("break")) {
+				token = XbcExpToken.BREAK_TT;
+			} else if(ts.equals("continue")) {
+				token = XbcExpToken.CONTINUE_TT;
+			} else if(ts.equals("while")) {
+				token = XbcExpToken.WHILE_TT;
+			} else if(ts.equals("if")) {
+				token = XbcExpToken.IF_TT;
+			} else if(ts.equals("else")) {
+				token = XbcExpToken.ELSE_TT;
+			} else if(ts.equals("div0")) {
+				token = XbcExpToken.DIV0_TT;
+			} else if(ts.equals("exit")) {
+				token = XbcExpToken.EXIT_TT;
+			} else if(ts.equals("new") || ts.equals("create")) {
+				token = XbcExpToken.NEW_TT;
+			} else if(ts.equals("invoke")) {
+				token = XbcExpToken.INVOKE_TT;
+			}
+		}
 		return token;
 	}
 
+	private void charEscape() {
+	    char c = getNextChar();
+	    switch(c) {
+	    case 92:
+	    	tokenContent.append(c);
+	        return;
+	    case 'b':
+	    	tokenContent.append("\b");
+	        return;
+	    case 'f':
+	    	tokenContent.append("\f");
+	        return;
+	    case 'n':
+	    	tokenContent.append("\n");
+	        return;
+	    case 'r':
+	    	tokenContent.append("\r");
+	        return;
+	    case 't':
+	    	tokenContent.append("\t");
+	        return;
+	    case '\'':
+	    	tokenContent.append("\\");
+	        return;
+	    case '"':
+	    	tokenContent.append("\"");
+	        return;
+	    case '?':
+	    	tokenContent.append("?");
+	        return;
+	    }
+    	throw new XbcExpScanException("未知的转义符【" + c + "】" + ", 公式: " + expStr);
+	}
+
 	private void ungetNextChar() {
 		pos --;
 	}

+ 4 - 4
src/main/resources/application.properties

@@ -1,9 +1,9 @@
 server.port=12389
 
-spring.datasource.url=jdbc:mysql://localhost:3306/calcmgr?serverTimezone=Asia/Shanghai&zeroDateTimeBehavior=CONVERT_TO_NULL&useUnicode=true&characterEncoding=utf-8&useSSL=false
-spring.datasource.username=root
-spring.datasource.password=chengdu
-spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
+spring.datasource.username=cm
+spring.datasource.password=sichuan
+spring.datasource.driver-class-name=org.postgresql.Driver
 
 mybatis.mapper-locations=classpath:mapper/*.xml
 #mybatis.configuration.logImpl=org.apache.ibatis.logging.stdout.StdOutImpl

+ 28 - 0
table/reset_ddl_pg.txt

@@ -0,0 +1,28 @@
+-- 重新设置公式表数据
+TRUNCATE TABLE fml_formula;
+INSERT INTO fml_formula VALUES (1000, '个人所得税', 'gerensuodeshui', '(工资 {\r\n  <= 5000 : 0,\r\n  (5000, 8000] : (工资 - 5000) * 0.03,\r\n  (8000, 17000] : 90 + (工资 - 8000) * 0.1,\r\n  (17000, 30000] : 990 + (工资 - 17000) * 0.2,\r\n  (30000, 40000] : 3590 + (工资 - 30000) * 0.25,\r\n  (40000, 60000] : 6090 + (工资 - 40000) * 0.3,\r\n  (60000, 85000] : 12090 + (工资 - 60000) * 0.35,\r\n  > 850000 : 20840 + (工资 - 85000) * 0.45\r\n}) + 杂税', '', 0, current_timestamp);
+INSERT INTO fml_formula VALUES (1001, '工资', 'gongzi', '基本工资 + 绩效工资 + 其它收入', '', 0, current_timestamp);
+INSERT INTO fml_formula VALUES (1002, '其它收入', 'qitashouru', '兼职收入 * 0.8 + 彩票收入 * 0.5', '', 0, current_timestamp);
+INSERT INTO fml_formula VALUES (1003, '绩效工资', 'jixiaogongzi', '基本绩效 + 其它收入', '', 0, current_timestamp);
+
+-- 重新设置指标表数据
+TRUNCATE TABLE fml_formula_indicator;
+INSERT INTO fml_formula_indicator VALUES (3001, 4, '基本工资', 'jibengongzi', 'jibengongzi', '', 0, current_timestamp);
+INSERT INTO fml_formula_indicator VALUES (3002, 4, '基本绩效', 'jibenjixiao', 'jibenjixiao', '', 0, current_timestamp);
+INSERT INTO fml_formula_indicator VALUES (3003, 4, '兼职收入', 'jianzhishouru', 'jianzhishouru', '', 0, current_timestamp);
+INSERT INTO fml_formula_indicator VALUES (3004, 4, '彩票收入', 'caipiaoshouru', 'caipiaoshouru', '', 0, current_timestamp);
+INSERT INTO fml_formula_indicator VALUES (3005, 4, '杂税', 'zashui', 'zashui', '', 0, current_timestamp);
+
+-- 重新设置业务使用公式配置表数据
+TRUNCATE TABLE calc_formula;
+INSERT INTO calc_formula VALUES (1, 1, 'geshui', 'gerensuodeshui', 1, 0, current_timestamp);
+
+-- 重新设置运行结果id管理表数据
+TRUNCATE TABLE calc_no_manager;
+insert into calc_no_manager (result_type, formula_no, indicator_no, create_time, modify_time) values (1, 0, 0, current_timestamp, current_timestamp);
+
+-- 清除公式运算结果表数据
+TRUNCATE TABLE calc_result;
+
+-- 清除公式运算结果指标表数据
+TRUNCATE TABLE calc_indicator_result;

+ 91 - 0
table/table_dml_pg.txt

@@ -0,0 +1,91 @@
+-- 基础公式配置表(开始)
+
+CREATE TABLE fml_formula(
+	key_id                           bigint               NOT NULL DEFAULT 0                ,
+	formula_name                     varchar(40)          NOT NULL DEFAULT ''               ,
+	formula_code                     varchar(40)          NOT NULL DEFAULT ''               ,
+	formula_value                    varchar(2000)        NOT NULL DEFAULT ''               ,
+	formula_desc                     varchar(255)         NOT NULL DEFAULT ''               ,
+	del_status                       smallint             NOT NULL DEFAULT 0                ,
+	create_time                      timestamp            NOT NULL DEFAULT CURRENT_TIMESTAMP,
+	PRIMARY KEY ( key_id )
+);
+
+
+CREATE TABLE fml_formula_indicator(
+	key_id                           bigint               NOT NULL DEFAULT 0                ,
+	indicator_type                   smallint             NOT NULL DEFAULT 0                ,
+	indicator_name                   varchar(50)          NOT NULL DEFAULT ''               ,
+	indicator_code                   varchar(40)          NOT NULL DEFAULT ''               ,
+	specified_val                    varchar(50)          NOT NULL DEFAULT ''               ,
+	indicator_comment                varchar(200)         NOT NULL DEFAULT ''               ,
+	del_status                       smallint             NOT NULL DEFAULT 0                ,
+	create_time                      timestamp            NOT NULL DEFAULT CURRENT_TIMESTAMP,
+	PRIMARY KEY ( key_id )
+);
+
+-- 基础公式配置表(结束)
+
+
+
+-- 业务使用公式配置表(开始)
+
+CREATE TABLE calc_formula(
+	key_id                           bigint               NOT NULL DEFAULT 0                ,
+	product_id                       bigint               NOT NULL DEFAULT 0                ,
+	biz_type                         varchar(40)          NOT NULL DEFAULT ''               ,
+	formula_code                     varchar(40)          NOT NULL DEFAULT ''               ,
+	show_index                       integer              NOT NULL DEFAULT 0                ,
+	del_status                       smallint             NOT NULL DEFAULT 0                ,
+	create_time                      timestamp            NOT NULL DEFAULT CURRENT_TIMESTAMP,
+	PRIMARY KEY ( key_id )
+);
+
+-- 业务使用公式配置表(结束)
+
+
+
+-- 公式计算结果管理表(开始)
+
+CREATE TABLE calc_no_manager(
+    result_type                      smallint             NOT NULL DEFAULT 0                ,
+    formula_no                       bigint               NOT NULL DEFAULT 0                ,
+    indicator_no                     bigint               NOT NULL DEFAULT 0                ,
+	create_time                      timestamp            NOT NULL DEFAULT CURRENT_TIMESTAMP,
+	modify_time                      timestamp            NOT NULL DEFAULT CURRENT_TIMESTAMP,
+	PRIMARY KEY ( result_type )
+);
+
+insert into calc_no_manager (result_type, formula_no, indicator_no, create_time, modify_time) values (1, 0, 0, current_timestamp, current_timestamp);
+
+CREATE TABLE calc_result(
+	key_id                           bigint               NOT NULL DEFAULT 0                ,
+	product_id                       bigint               NOT NULL DEFAULT 0                ,
+	biz_type                         varchar(40)          NOT NULL DEFAULT ''               ,
+	biz_code                         varchar(40)          NOT NULL DEFAULT ''               ,
+	formula_code                     varchar(40)          NOT NULL DEFAULT ''               ,
+	calc_result_type                 varchar(50)          NOT NULL DEFAULT ''               ,
+	calc_result                      varchar(255)         NOT NULL DEFAULT ''               ,
+	formula_name                     varchar(40)          NOT NULL DEFAULT ''               ,
+	formula_value                    varchar(1000)        NOT NULL DEFAULT ''               ,
+	create_time                      timestamp            NOT NULL DEFAULT CURRENT_TIMESTAMP,
+	PRIMARY KEY ( key_id )
+);
+
+CREATE TABLE calc_indicator_result(
+	key_id                           bigint               NOT NULL DEFAULT 0                ,
+	calc_result_id                   bigint               NOT NULL DEFAULT 0                ,
+	indicator_id                     bigint               NOT NULL DEFAULT 0                ,
+	indicator_type                   smallint             NOT NULL DEFAULT 0                ,
+	indicator_name                   varchar(50)          NOT NULL DEFAULT ''               ,
+	specified_val                    varchar(50)          NOT NULL DEFAULT ''               ,
+	calc_result_type                 varchar(50)          NOT NULL DEFAULT ''               ,
+	calc_result                      varchar(255)         NOT NULL DEFAULT ''               ,
+	parent_id                        bigint               NOT NULL DEFAULT 0                ,
+	node_code                        varchar(100)         NOT NULL DEFAULT ''               ,
+	formula_value                    varchar(1000)        NOT NULL DEFAULT ''               ,
+	create_time                      timestamp            NOT NULL DEFAULT CURRENT_TIMESTAMP,
+	PRIMARY KEY ( key_id )
+);
+
+-- 公式计算结果管理表(结束)