com.anysoft.formula.Parser Maven / Gradle / Ivy
package com.anysoft.formula;
/**
* Formula Parser
*
* AnyFormula是纯Java实现的公式解析器,具备下列特性:
* - 支持加,减,乘,除,模等算术操作符
* - 支持大于,小于,等于等逻辑操作符
* - 支持下列内置函数
* + choice:{@link Function.Choice}
* + nvl:{@link Function.Nvl}
* + to_date:{@link Function.Char2Date}
* + to_char:{@link Function.Date2Char}
* + to_string:{@link Function.ToString}
* + to_long:{@link Function.ToLong}
* + to_double:{@link Function.ToDouble}
* + substr:{@link Function.SubStr}
* + instr:{@link Function.InStr}
* + strlen:{@link Function.StrLen}
* + match:{@link Function.Match}
* - 通过{@link FunctionHelper}机制支持自定义函数插件
* - 通过{@link DataProvider}机制支持自定义变量
*
* @author duanyy
* @version 1.0
*
* @version 1.6.3.39 [duanyy 20150812]
* - 修正%算法的bug;
* - 修正无参函数的解析错误问题;
*
* @version 1.6.7.1
* - 修改方法为protected,增加可定制性
*/
public class Parser {
/**
* 当前处理的公式文本
*/
protected String text;
/**
* 当前解析的位置
*/
protected int current;
public static final char ADD_OR_POSITIVE = '+';
public static final char SUBTRACT_OR_NEGATIVE = '-';
public static final char MULTIPLY = '*';
public static final char DIVIDE = '/';
public static final char MOD = '%';
public static final char EQUAL = '=';
public static final char LESS = '<';
public static final char GREATER = '>';
public static final char BIT_AND = '&';
public static final char BIT_OR = '|';
public static final char LEFT_BRACKET = '(';
public static final char RIGHT_BRACKET = ')';
public static final char PARAMETER_SEPERATOR = ',';
public static final char NOT = '!';
public static final char STRING = '\'';
public static final char IDENTIFIER = 257;
public static final char FINISHED = 259;
public static final char EQUAL_LESS = 260;
public static final char EQUAL_GREATE = 261;
public static final char NOT_EQUAL = 262;
public static final char AND = 263;
public static final char OR = 264;
public static final char FLOAT = 265;
public static final char INTEGER = 266;
/**
* 当前解析Token的类型
*/
protected char type;
/**
* 当前解析的ID
*/
protected String identifier;
/**
* 当前是否在字符串中
*/
protected boolean inString;
/**
* 函数对象辅助器
*/
protected FunctionHelper funcHelper = null;
/**
* to set function helper
* @param helper helper
*/
public void setFunctionHelper(FunctionHelper helper){
funcHelper = helper;
}
static public boolean isSpace(char ch){
return Character.isSpaceChar(ch);
}
static public boolean isAlpha(char ch){
return ch >= 'a' && ch <='z' || ch >= 'A' && ch <= 'Z';
}
static public boolean isDigital(char ch){
return ch >= '0' && ch <= '9';
}
static public boolean isIdentifierChar(char ch){
return isAlpha(ch) || isDigital(ch) || ch == '_' || ch == '.';
}
static public boolean isIdentifierFirstChar(char ch){
return isAlpha(ch) || ch == '_' || ch == '.';
}
static public boolean isDecimalChar(char ch){
return ch == '.';
}
public Parser(){
funcHelper = new DefaultFunctionHelper();
}
public Parser(FunctionHelper helper){
funcHelper = helper;
}
/**
* 将公式文本解析为Expression模型
* @param _text 公式文本
* @return Expression实例
* @throws FormulaException
*/
public Expression parse(String _text)throws FormulaException{
text = _text;
current = 0;
inString = false;
identifier = "";
lookAhead();
return expression_R_Logical_Or
(
expression_R_Logical_And
(
expression_R_Compare
(
expression_R(higher_expression())
)
)
);
}
protected Expression higher_expression() {
return higher_expression_R( sign_expression() );
}
protected Expression higher_expression_R(Expression left) {
Expression result = left;
if( type == MULTIPLY )
{
match( MULTIPLY );
Expression higher = sign_expression();
result = higher_expression_R( Expression.BinaryExpression.createChild(Expression.Operator.OP_Mul,left,higher) );
}
else if( type == DIVIDE )
{
match( DIVIDE );
Expression higher = sign_expression() ;
result = higher_expression_R( Expression.BinaryExpression.createChild(Expression.Operator.OP_Div,left,higher) );
} else if (type == MOD){
match(MOD);
Expression higher = sign_expression() ;
result = higher_expression_R( Expression.BinaryExpression.createChild(Expression.Operator.OP_Mod,left,higher) );
}
return result;
}
protected Expression sign_expression() {
Expression result;
if( type == ADD_OR_POSITIVE )
{
match( ADD_OR_POSITIVE );
result = sign_expression();
}
else if( type == SUBTRACT_OR_NEGATIVE )
{
match( SUBTRACT_OR_NEGATIVE );
result = new Expression.UnaryExpression(Expression.Operator.OP_Negative,sign_expression());
}
else
result = factor();
return result;
}
protected Expression factor() {
Expression result;
if (type == FLOAT)
{
match(FLOAT);
result = new Expression.DoubleConstant(Double.valueOf(identifier));
}
else
if (type == STRING)
{
match(STRING);
result = new Expression.StringConstant(identifier);
}
else
if (type == INTEGER)
{
match(INTEGER);
result = new Expression.LongConstant(Long.valueOf(identifier));
}
else
if (type == LEFT_BRACKET)
{
match(LEFT_BRACKET);
result = expression_R_Logical_Or
(
expression_R_Logical_And
(
expression_R_Compare
(
expression_R(higher_expression())
)
)
);
match( RIGHT_BRACKET );
}
else
{
result = lang_structure();
}
return result;
}
protected Expression lang_structure() {
String id = identifier;
match(IDENTIFIER);
return lang_tail( id );
}
protected Expression lang_tail(String id) {
if (id.equals("true"))
{
return new Expression.BooleanConstant(true);
}
if (id.equals("false"))
{
return new Expression.BooleanConstant(false);
}
if (type == LEFT_BRACKET)
{
Function result = null;
if (funcHelper != null)
{
result = (Function)funcHelper.customize(id);
}
if (result != null)
{
match( LEFT_BRACKET );
if (type == RIGHT_BRACKET){
match( RIGHT_BRACKET );
}else{
result.addArgument(expression_R_Logical_Or
(
expression_R_Logical_And
(
expression_R_Compare
(
expression_R(higher_expression())
)
)
));
for(;;)
{
if( type == RIGHT_BRACKET )
{
match( RIGHT_BRACKET );
break;
}
match(PARAMETER_SEPERATOR);
result.addArgument(expression_R_Logical_Or
(
expression_R_Logical_And
(
expression_R_Compare
(
expression_R(higher_expression())
)
)
));
}
}
return result;
}
return expression_R_Logical_Or
(
expression_R_Logical_And
(
expression_R_Compare
(
expression_R(higher_expression())
)
)
);
}
return variant(id);
}
protected Expression variant(String id){
return new Expression.Variant(id);
}
protected Expression expression_R_Logical_Or(Expression left) {
Expression result = left;
if( type == OR )
{
match( OR );
Expression higher = expression_R_Logical_And
(
expression_R_Compare
(
expression_R(higher_expression())
)
);
result = expression_R_Logical_Or
(Expression.BinaryExpression.createChild(Expression.Operator.OP_Or,left,higher));
}
return result;
}
protected Expression expression_R_Logical_And(Expression left) {
Expression result = left;
if( type == AND )
{
match( AND );
Expression higher = expression_R_Compare
(
expression_R(higher_expression())
);
result = expression_R_Logical_And
(Expression.BinaryExpression.createChild(Expression.Operator.OP_And,left,higher));
}
return result;
}
protected Expression expression_R_Compare(Expression left) {
Expression result = left;
if( type == EQUAL_LESS )
{
match( EQUAL_LESS );
Expression higher = expression_R(higher_expression());
result = expression_R_Compare(
Expression.BinaryExpression.createChild(Expression.Operator.OP_Less_Equal,left,higher));
}
else if( type == EQUAL_GREATE )
{
match( EQUAL_GREATE );
Expression higher = expression_R(higher_expression());
result = expression_R_Compare(Expression.BinaryExpression.createChild(Expression.Operator.OP_Greater_Equal,left,higher));
}
else if( type == NOT_EQUAL )
{
match( NOT_EQUAL );
Expression higher = expression_R(higher_expression());
result = expression_R_Compare(Expression.BinaryExpression.createChild(Expression.Operator.OP_Not_Equal,left,higher));
}
else if( type == EQUAL )
{
match( EQUAL );
Expression higher = expression_R(higher_expression());
result = expression_R_Compare(Expression.BinaryExpression.createChild(Expression.Operator.OP_Equal,left,higher));
}
else if( type == LESS )
{
match( LESS );
Expression higher = expression_R(higher_expression());
result = expression_R_Compare(Expression.BinaryExpression.createChild(Expression.Operator.OP_Less,left,higher));
}
else if( type == GREATER )
{
match( GREATER );
Expression higher = expression_R(higher_expression());
result = expression_R_Compare(Expression.BinaryExpression.createChild(Expression.Operator.OP_Greater,left,higher));
}
return result;
}
protected Expression expression_R(Expression left) {
Expression result = left;
if( type == ADD_OR_POSITIVE )
{
match( ADD_OR_POSITIVE );
Expression higher = higher_expression();
result = expression_R(Expression.BinaryExpression.createChild(Expression.Operator.OP_Add,left,higher));
}
else if( type == SUBTRACT_OR_NEGATIVE )
{
match( SUBTRACT_OR_NEGATIVE );
Expression higher = higher_expression();
result = expression_R(Expression.BinaryExpression.createChild(Expression.Operator.OP_Sub,left,higher));
}
return result;
}
protected char get(int _current){
if (_current >= text.length()){
return 0;
}
return text.charAt(_current);
}
protected void lookAhead(){
for (;;){
if (get(current) <= 0){
break;
}
if (inString){
if (get(current) != STRING){
identifier += get(current);
++current;
continue;
}
}
if (isSpace(get(current))){
++current;
continue;
}
if (get(current) == STRING){
type = STRING;
++current;
if (!inString){
identifier = "";
inString = true;
continue;
}else{
inString = false;
break;
}
}
if (get(current) == LESS && get(current + 1) == EQUAL){
type = EQUAL_LESS;
current += 2;
}else{
if (get(current) == GREATER && get(current + 1) == EQUAL){
type = EQUAL_GREATE;
current += 2;
}else{
if (get(current) == EQUAL && get(current + 1) == EQUAL){
type = EQUAL;
current += 2;
}else{
if (get(current) == NOT && get(current + 1) == EQUAL){
type = NOT_EQUAL;
current += 2;
}else{
if (get(current) == BIT_AND && get(current + 1) == BIT_AND){
type = AND;
current += 2;
}else{
if (get(current) == BIT_OR && get(current + 1) == BIT_OR){
type = OR;
current += 2;
}else{
char ch = get(current);
if (ch == ADD_OR_POSITIVE
|| ch == SUBTRACT_OR_NEGATIVE
|| ch == MULTIPLY
|| ch == DIVIDE
|| ch == MOD
|| ch == LEFT_BRACKET
|| ch == RIGHT_BRACKET
|| ch == PARAMETER_SEPERATOR
|| ch == EQUAL
|| ch == LESS
|| ch == GREATER){
type = ch;
++current;
}else{
if (isIdentifierFirstChar(get(current))){
type = IDENTIFIER;
identifier = "";
identifier += get(current);
++current;
while(isIdentifierChar(get(current))){
identifier += get(current);
++current;
}
}else{
if (get(current) == 0){
type = FINISHED;
}else{
identifier = "";
identifier += get(current);
++current;
boolean isFloat = false;
while((isDecimalChar(get(current)) && !isFloat) || isDigital(get(current)) ){
identifier += get(current);
if (isDecimalChar(get(current))){
isFloat = true;
}
++current;
}
type = isFloat?FLOAT:INTEGER;
}
}
}
}
}
}
}
}
}
break;
}
}
protected void match(char _type){
if( type == _type )
lookAhead();
else
throw new FormulaException("mismatched token,index:" + current);
}
}