例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 :
可以看到,乘除的優先級確實高於加減。