又一个语言识别工具(ANTLR)
刚刚看到《动态计算字串表达式值的类》,好像有许多人表示更喜欢解析器形式的求值类。其实我个人倒觉得用反射实现没什么不好,恰恰相反,我觉得这种实现方法很聪明!另外,装配中的脑袋的代码可以稍微修改一下来提高效率,那样再用的话就不会因为反复编译而影响效率了。
言规正传,不知道大家有没有注意我最近在Blog中添加了一个叫ANTLR的连接,它就是一个著名的“编译器的编译器”,不过它实际上是ANother Tool for Language Recognition(ANTLR),它的描述语言可以生成词法分析器、语法分析器与语义分析器,也就是说,我们可以用它来识别加工不同的语言(编译器的编译器)。它同时支持3大类语言的输出:C++, Java, C#(按照生日排序),也就是说,我们可以利用它来用C#生成编译器。ANTLR是免费开源的,而且历史也很久远了,目前的版本是2.7.5,有兴趣的朋友可以在我的Blog的连接中找到网址。
那么,除了用反射轻松的实现计算值之外我们也可以用ANTLR来描述这些数学表达式,下面我附上一个我在看到《动态计算字串表达式值的类》后写的一个语法文件,感兴趣的朋友可以去下载ANTLR来试一试下面的语法哦!
:
文件Calc.g
header
{
using CharBuffer = antlr.CharBuffer;
}options
{
language = "CSharp";
namespace = "Cavingdeep.Test.Calc";
}/******************************\
Calc Parser
\******************************/
class CalcParser extends Parser;
options
{
exportVocab = Calc;
buildAST = true;
}expr : sumExpr EOF ;
sumExpr : mulExpr ( ( SUM^ | NEG^ ) mulExpr )* ;
mulExpr : powExpr ( ( MUL^ | DIV^ ) powExpr )* ;
powExpr : negExpr ( POW^ negExpr )* ;
negExpr
: ( NEG^ )* a:atom!
{
if (#negExpr != null) {
AST lastNegNode = #negExpr;
while (lastNegNode.getNumberOfChildren() > 0) {
lastNegNode = lastNegNode.getFirstChild();
}
lastNegNode.setFirstChild(#a);
} else {
## = #a;
}
}
;atom : NUMBER | LCURLY! sumExpr RCURLY! ;
/***************************\
Calc Lexer
\***************************/
class CalcLexer extends Lexer;
options
{
caseSensitive = false;
exportVocab = Calc;
}WS
: ( ' '
| '\t'
| '\n'
| '\r' )+ { $setType(Token.SKIP); }
;NUMBER : ( ( '0'..'9' )+ '.' ( '0'..'9' )+ ) => ( '0'..'9' )+ '.' ( '0'..'9' )+ | '0'..'9' ;
SUM : '+' ;
NEG : '-' ;
MUL : '*' ;
DIV : '/' ;
POW : '^' ;
LCURLY : '(' ;RCURLY : ')' ;
/***************************\
Calc Tree Parser
\***************************/
class CalcTreeParser extends TreeParser;
options
{
exportVocab = Calc;
}{
public static void Main(string[] args) {
CalcLexer lexer = new CalcLexer(new CharBuffer(Console.In));
CalcParser parser = new CalcParser(lexer);
parser.expr();
AST ast = parser.getAST();
CalcTreeParser treeParser = new CalcTreeParser();
double r = treeParser.eval(ast);
Console.WriteLine("结果是:" + r);
}
}eval returns [double v = 0] : v=expr ;
protected
expr returns [double v = 0]
{
double izq = 0;
double der = 0;
}
: i:NUMBER { v = Convert.ToDouble(i.getText()); }
| #( SUM izq=expr der=expr ) { v = izq + der; }
| #( DIV izq=expr der=expr ) { v = izq / der; }
| ( #( NEG expr expr ) ) => #( NEG izq=expr der=expr ) { v = izq - der; }
| #( MUL izq=expr der=expr ) { v = izq * der; }
| #( POW izq=expr der=expr ) { v = Math.Pow(izq, der); }
| #( NEG izq=expr ) { v = -(izq);}
;


浙公网安备 33010602011771号