例5:计算器--添加乘除法运算
1.calculator2.jj
根据上一个例子,可知要添加乘法和除法运算是很简单的,我们只需在词法描述部分添加如下两个token:
TOKEN : { < TIMES : "*" > } TOKEN : { < DIVIDE : "/" > }
接下来我们修改Expression这个生产式,对它的修改跟上一步添加减号运算所做的修改很相似:
Expression --> Primary (PLUS Primary | MINUS Primary | TIMES Primary | DIVIDE Primary)*
从纯粹的句法角度来看,上面这种方法没有什么错,但是它与我们的计算方法不太吻合,因为它没有认识到乘法和除法应该比加法和减法具有更高的优先级。例如,如果我们计算下式:
2*3+4*5
那么根据我们的表达式,我们获得的结果就会是((2×3) + 4)×5,结果是50,而不是(2×3) + (4×5)。
因此,我们将生产式修改成如下:
Expression --> Term (PLUS Term | MINUS Term)* Term --> Primary (TIMES Primary | DIVIDE Primary)*
这样一来,我们就将每个表达式拆分成了一个或多个式子(terms)相加或相减。在我们的例子中,式子(terms)就是两个大括号中的内容:
[ 2*3 ] +[ 4*5 ]
对Expression来说,它的改变就是修改原先对Primary的引用,把它修改到对Term的引用,如下所示:
double Expression() throws NumberFormatException : { double i ; double value ; } { value = Term() ( <PLUS> i = Term() { value += i ; } | <MINUS> i = Term() { value -= i ; } )* { return value ; } }
而Term的生产式如下所示:
double Term() throws NumberFormatException : { double i ; double value ; } { value = Primary() ( <TIMES> i = Primary() { value *= i ; } | <DIVIDE> i = Primary() { value /= i ; } )* { return value ; } }
2.测试
根据上面的修改,最终得到的calculator2.jj文件内容如下:
/* calculator0.jj An interactive calculator. */ options { STATIC = false ; } PARSER_BEGIN(Calculator) import java.io.PrintStream ; class Calculator { public static void main( String[] args ) throws ParseException, TokenMgrError, NumberFormatException { Calculator parser = new Calculator( System.in ) ; parser.Start( System.out ) ; } double previousValue = 0.0 ; } PARSER_END(Calculator) SKIP : { " " } TOKEN : { < EOL : "\n" | "\r" | "\r\n" > } TOKEN : { < PLUS : "+" > } TOKEN : { < MINUS : "-" > } TOKEN : { < TIMES : "*" > } TOKEN : { < DIVIDE : "/" > } TOKEN : { < NUMBER : <DIGITS> | <DIGITS> "." <DIGITS> | <DIGITS> "." | "."<DIGITS> > } TOKEN : { < #DIGITS : (["0"-"9"])+ > } void Start(PrintStream printStream) throws NumberFormatException : {} { ( previousValue = Expression() <EOL> { printStream.println( previousValue ) ; } )* <EOF> } double Expression() throws NumberFormatException : { double i ; double value ; } { value = Term() ( <PLUS> i = Term() { value += i ; } | <MINUS> i = Term() { value -= i ; } )* { return value ; } } double Term() throws NumberFormatException : { double i ; double value ; } { value = Primary() ( <TIMES> i = Primary() { value *= i ; } | <DIVIDE> i = Primary() { value /= i ; } )* { return value ; } } double Primary() throws NumberFormatException : { Token t ; } { t = <NUMBER> { return Double.parseDouble( t.image ) ; } }
先来测试1+2:
计算 2 * 3.3:
计算 9. / 3 :
最后,计算23+45 :
可以看到,乘除的优先级确实高于加减。