今天咱们来一句一句的解释一下这个expression.g文件。还是从最简单的几行开始:
class ExpressionLexer extends Lexer; //这是用来声明一个词法分析器,名字叫
//ExpressionLexer
PLUS : '+' ; //加号
MINUS : '-' ; //减号
MUL : '*' ; //乘号
DIV : '/' ; //除号
MOD : '%' ; //求余
POW : '^' ; //开方
SEMI : ';' ; //结束号
PLUS : '+' ; //加号
MINUS : '-' ; //减号
MUL : '*' ; //乘号
DIV : '/' ; //除号
MOD : '%' ; //求余
POW : '^' ; //开方
SEMI : ';' ; //结束号
//上面这些都太简单了,简直就不需要说明
protected DIGIT : '0'..'9' ; //数字,这是一个受保护的单词,只能被
//词法分析器内部使用
INT : (DIGIT)+ ; //出现了一次以上的数字的词,就是整数,
INT : (DIGIT)+ ; //出现了一次以上的数字的词,就是整数,
//它通过受保护的单词:“数字”来定义自己。
//如果DIGIT不是被保护的单词,则词法分析器就会
//无法分辨究竟是数字还是整数了
接下来看语法分析器的代码:
class ExpressionParser extends Parser; //定义一个语法分析器,名字叫ExpressionParser
options { buildAST=true; } //告诉ANTLR,要帮我生成一个抽象语法树,
//留着以后有用
options { buildAST=true; } //告诉ANTLR,要帮我生成一个抽象语法树,
//留着以后有用
//接下来的部分就非常复杂了,主要是多出来了两个特殊的符号“!”、“^”
//这两个符号,不是EBNF原有的,而是ANTLR为了生成AST而增加的符号
//“!”,是告诉AST生成程序,不要把自己算进去
//“^”,是告诉AST生成程序,把这个符号,放在一颗树的根部,或者一颗子树的根部
//另外,“*”表示出现0次以上,“+”表示出现一次以上,“?”表示出现0或1次
expr : sumExpr SEMI!; //“;”作为结束符,不放入AST
sumExpr : prodExpr ((PLUS^|MINUS^) prodExpr)* ; //“+”“-”作为计算符号
//放在树的顶部
prodExpr : powExpr ((MUL^|DIV^|MOD^) powExpr)* ; //剩下的就不解释了,都能明白的
powExpr : atom (POW^ atom)? ;
atom : INT ;
powExpr : atom (POW^ atom)? ;
atom : INT ;
再来看AST计算器的代码。这“AST计算器”是我起的名字,也就是通过对一个生成的抽象语法树,递归求值,得到最后的结果。
{import java.lang.Math;} //ExpressionTreeWalker要用到的
class ExpressionTreeWalker extends TreeParser; //声明一个树计算器
expr returns [double r] //有一个方法叫expr
class ExpressionTreeWalker extends TreeParser; //声明一个树计算器
expr returns [double r] //有一个方法叫expr
//它的返回值是double类型
{double a,b; r=0; } //嵌入的代码,后面要用到
: #(PLUS a=expr b=expr) { r=a+b; } //以下就是计算各种算符,不用多说了
| #(MINUS a=expr b=expr) { r=a-b; }
| #(MUL a=expr b=expr) { r=a*b; }
| #(DIV a=expr b=expr) { r=a/b; }
| #(MOD a=expr b=expr) { r=a%b; }
| #(POW a=expr b=expr) { r=Math.pow(a,b); }
| i:INT { r=(double)Integer.parseInt(i.getText()); }
;
{double a,b; r=0; } //嵌入的代码,后面要用到
: #(PLUS a=expr b=expr) { r=a+b; } //以下就是计算各种算符,不用多说了
| #(MINUS a=expr b=expr) { r=a-b; }
| #(MUL a=expr b=expr) { r=a*b; }
| #(DIV a=expr b=expr) { r=a/b; }
| #(MOD a=expr b=expr) { r=a%b; }
| #(POW a=expr b=expr) { r=Math.pow(a,b); }
| i:INT { r=(double)Integer.parseInt(i.getText()); }
;
(未完待续)