gxh973121

博客园 首页 新随笔 联系 订阅 管理

刚刚看到《动态计算字串表达式值的类》,好像有许多人表示更喜欢解析器形式的求值类。其实我个人倒觉得用反射实现没什么不好,恰恰相反,我觉得这种实现方法很聪明!另外,装配中的脑袋的代码可以稍微修改一下来提高效率,那样再用的话就不会因为反复编译而影响效率了。

言规正传,不知道大家有没有注意我最近在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);}
 ;
posted on 2005-04-08 09:19  gxh973121  阅读(710)  评论(1编辑  收藏  举报