论坛首页 Java企业应用论坛

FEL(表达式语言)——7月30号更新

浏览 13027 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-02-23   最后修改:2011-07-30
                    
Fel使用说明

1:Fel简介
Fel是简单的、高效的、易扩展的开源项目,使用java开发的开源项目。
简单性:语法简单,与java表达式类似,支持中文变量和函数。其实现原理也非常简单,只要稍微有一些java基础就可以看懂源码。
高效性:不会比开源的脚本引擎慢。一些高级应用还可以大大高于其他脚本引擎。
易扩展:在执行表达式的主要环节(解析表达式、函数管理、操作符重载、引擎上下文、节点解释器)都有很高的可定制性。
Fel设计目标是面向最终用户和二次开发用户。它是功能灵活的、可以轻易掌控的和可定制的表达式语言。
2:快速入门
获取Fel
项目地址:http://code.google.com/p/fast-el/
源代码:http://fast-el.googlecode.com/svn/trunk/ 
安装部署
将fel-xx.jar、commons-lang-2.4.jar、antlr-3.2.jar加入classpath就可以使用。

3:组成结构
Fel的主要组成结构如下所示:



模块 说明
解析器(Parser) 将表达式解析成节点。
节  点(Node) 由解析器生成。
执行上下文(Context) 负责解析变量的值
函数(Function) 内置常用数学和字符串函数(abs、trim)
操作符(Operator) 内置基本的操作符(加减乘除等)

未完待续....
项目地址:http://code.google.com/p/fast-el/

演示代码所在类:com.greenpineyu.fel.examples.Example
------------------2010-03-08-------------------------
1:简单的例子
FelEngine fel = new FelEngineImpl();
Object result = fel.eval("5000*12+7500");
System.out.println(result);

输出:
67500

2:使用变量
FelEngine fel = new FelEngineImpl();
FelContext ctx = fel.getContext();         
ctx.set("单价", "5000");                   
ctx.set("数量", new Integer(12));          
ctx.set("运费", "7500");                   
Object result = fel.eval("单价*数量+运费");
System.out.println(result);

输出67500

3:调用对象的方法
FelEngine fel = new FelEngineImpl();
FelContext ctx = fel.getContext();
ctx.set("out", System.out);
fel.eval("out.println('Hello Everybody')");

输出:
Hello Everybody

------------------2010-03-10-------------------------
4:变量命名空间
FelEngine fel = new FelEngineImpl();
String costStr = "成本";                          
FelContext rootContext = fel.getContext();        
rootContext.set(costStr, "60000");                
Object baseCost = fel.eval(costStr);              
System.out.println("基本费用:" + baseCost);      
MyContext myContext = new MyContext();            
myContext.setParent(rootContext);                 
myContext.set(costStr, new Integer(67500));       
Object allCost = fel.eval(costStr, myContext);    
System.out.println("所有费用:" + allCost);  
    
输出:
基本费用:60000
所有费用:67500

------------------2010-03-14-------------------------
5:自定义解释器
FelEngine fel = new FelEngineImpl();
String costStr = "成本";
FelContext rootContext = fel.getContext();
rootContext.set(costStr, "60000");
FelNode node = fel.parse(costStr);
//将变量解析成常量
node.setInterpreter(new ConstInterpreter(rootContext, node));
//下面这段代码执行速度非常高
node.eval(rootContext);

------------------2010-03-15-------------------------
6:数据表应用,计算求字段的乘积。
/*
 * 假设数据表中有两列,单价和数量。
 * 现在需要通过表达式计算金额(表达式:单价*数量)。
 * 通常的做法是通过context获取变量(单价、数量的值),
 * 在小数据量时,这种做法是很好的,但是大数据量时,性能就很差了。
 * 如果使用自定义的解释器,会提高效率。
 */


//数据表中单价列的记录
String[] price = new String[] {
"2", "3", "4"
};
//数据表中数量列的记录
String[] number = new String[] {
"10.99", "20.99", "9.9"
};
FelEngine fel = new FelEngineImpl();
String exp = "单价*数量";
FelNode node = fel.parse(exp);
List<FelNode> children = node.getChildren();
MutableInt index = new MutableInt(0);
//替换节点的解释器
for (Iterator iterator = children.iterator(); iterator.hasNext();) {
	FelNode child = (FelNode) iterator.next();
	if ("单价".equals(child.getText())) {
child.setInterpreter(new ColumnInterpreter(index, price));
	} else if ("数量".equals(child.getText())) {
child.setInterpreter(new ColumnInterpreter(index, number));
	}
}

for (int i = 0; i < number.length; i++) {
	index.setValue(i);
	Object eval = node.eval(null);
	System.out.println("金额[" + price[i] + "*" + number[i] + "=" + eval + "]");
}


数据表中列解析器,用于解析字段变量(单价或数量)
class ColumnInterpreter implements Interpreter {
	MutableInt index;

	String[] records;

	ColumnInterpreter(MutableInt index, String[] records) {
		this.index = index;
		this.records = records;
	}

	public Object interpret(FelContext context, FelNode node) {
		return records[index.intValue()];
	}

}

输出结果
金额[2*10.99=21.98]
金额[3*20.99=62.97]
金额[4*9.9=39.6]


------------------2010-07-30-------------------------
新版本做了一些简化,加入编译成java源码功能。效率大大提高,生成java源码的逻辑挺简单,方便修改和扩展。
支持新的表达式,如下所示:
1:"abc".substring(1)及所有的String类方法
2:对象.方法、对象.属性

代码刚刚写好,晚些时候加上文档。

  • 大小: 16.4 KB
   发表时间:2011-02-25  
也不说下有什么特性之类

效率高、简单、易扩展的特点用什么体现呢?
0 请登录后投票
   发表时间:2011-02-25  
眼高手低 没啥意义
0 请登录后投票
   发表时间:2011-02-25  
我现在用JSEL,你搞点例子看看啊!
0 请登录后投票
   发表时间:2011-02-25  
请问你这个轮子是四方形的吗?
0 请登录后投票
   发表时间:2011-03-10  
只能利用业余慢慢补充相关资料,并对代码进行持续更新。希望大家看一看,交流交流。
0 请登录后投票
   发表时间:2011-03-10  
以前做过,用java解决不了对变量的值高速访问的问题,用c或者c++的指针很容易能提高这块的效率,用java最低限度也需要使用1次hash
0 请登录后投票
   发表时间:2011-03-10   最后修改:2011-03-10
ppgunjack 写道
以前做过,用java解决不了对变量的值高速访问的问题,用c或者c++的指针很容易能提高这块的效率,用java最低限度也需要使用1次hash

可以有不同的设计思路。例如说在传入“context”的时候不是一定要用Map,在表达式引擎内部也不是一定要用Map来维持binding。如果允许使用任意Object来做context,那就在表达式引擎内部根据profile对表达式做优化编译,
例如说编译这个表达式:
bar + 1

生成类似这样的代码:
if (arg instanceof Foo) {
  return ((Foo) arg).bar + 1
} else {
  return slowPath(); //...
}


仅供参考
0 请登录后投票
   发表时间:2011-03-10  
ppgunjack 写道
以前做过,用java解决不了对变量的值高速访问的问题,用c或者c++的指针很容易能提高这块的效率,用java最低限度也需要使用1次hash

如果需要调整访问变量,可以对变量节点进行預处理,以提高访问速度。代码如下所示:

FelEngine fel = new FelEngineImpl();
String costStr = "成本";                                           
FelContext rootContext = fel.getContext();                         
rootContext.set(costStr, "60000");                                 
FelNode node = fel.parse(costStr);                                 
//将变量解析成常量                                                 
node.setInterpreter(new ConstInterpreter(rootContext, node));      
//下面这段代码执行速度非常高                                       
node.eval(rootContext);   
                                        
0 请登录后投票
   发表时间:2011-03-11  
发布0.2版本。主要是代码重构和完善。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics