问题:
java中输入输入“算术表达式”的文本,如何计算表达式的值?例如输入1+2/2+2*(3+1);如何直接给出10.
方法:
在动态语言中如python,groovy中,这些根本不是问题,到java语言中,就变成了一件挺难的事。我想到几个解决方案:
1)java中调用动态语言groovy,scala
利用动态语言能支持的这个特性,java集成调用下,当然能完成这个功能
2)手动自定义语言解析器,解析表达式文本,然后执行表达式
具体的做法可参考这篇文章,用解释器模式来做 http://blog.youkuaiyun.com/tnt32/article/details/7829288
3)用antlr自定义DSL
这个比较强大,antlr用来作这个有点大材小用,antlr是什么可参见:http://www.antlr.org/
参考资料:
http://www.antlr.org/wiki/display/ANTLR3/ANTLR+v3+documentation
http://www.antlr.org.cn/ 出品的 《antlr教材.pdf》
antlr实现
自定义文法:
grammar D; options{output=AST;} program:statement+; statement:expression';'!; expression:multExpr(('+'^|'-' ^)multExpr)*; multExpr:atom(('*'^|'/'^)atom)*; atom:INT| '('!expression')'!; INT:'0'..'9' +; WS:(' ' |'\t' |'\n' |'\r' )+{skip();};
然后利用antlrWorks工具,自动生成解析器:DLexer.java,,DParser.java
因为antlr只完成了词法、语法的识别,所以需要自己编写语义:
package org.mike;
import org.antlr.runtime.ANTLRInputStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.tree.BaseTree;
import org.antlr.runtime.tree.Tree;
//1+1*3+(1+1)*3;
public class App {
public static void main(String[] args) throws Exception {
ANTLRInputStream input = new ANTLRInputStream(System.in);
DLexer lexer = new DLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
DParser parser = new DParser(tokens);
DParser.program_return r = parser.program();
System.out.println(((BaseTree) r.getTree()).toStringTree());
BaseTree tree = (BaseTree) r.getTree();
System.out.println(calcNode(tree));
}
public static int calcNode(Tree tree) {
if (tree.getChildCount() == 0) {
return Integer.parseInt(tree.getText());
}
if (tree.getChildCount() != 2) {
throw new RuntimeException("node " + tree.getText() + "illegal expression"
+ "tree.getChildCount() = " + tree.getChildCount());
}
int leftChildValue = calcNode(tree.getChild(0));
int rightChildVale = calcNode(tree.getChild(1));
String sign = tree.getText().trim();
return doCalc(sign, leftChildValue, rightChildVale);
}
private static int doCalc(String sign, int leftChildValue, int rightChildVale) {
if (sign.equals("+")) {
return leftChildValue + rightChildVale;
} else if (sign.equals("-")) {
return leftChildValue - rightChildVale;
} else if (sign.equals("*")) {
return leftChildValue * rightChildVale;
} else if (sign.equals("/")) {
return leftChildValue / rightChildVale;
}
throw new RuntimeException("unknown sign " + sign);
}
}
运行结果
输入:1+10/5+12+(2+3)*1+1;
输出:
(+ (+ (+ (+ 1 (/ 10 5)) 12) (* (+ 2 3) 1)) 1)
21