上一個例子中,JavaCC爲BNF生產式所生成的方法,好比Start(),這些方法默認只簡單的檢查輸入是否匹配BNF生產式指定的規範。可是咱們也能夠用java代碼來擴充BNF生產式,使得由生產式生成的方法中也包含java代碼。
咱們加下來會對上面例一中的adder.jj代碼作一些修改。對於其中的Start這個BNF生產式,咱們加入一些聲明和java代碼,以下所示:java
int Start() throws NumberFormatException : { Token t ; int i ; int value ; } { t = <NUMBER> { i = Integer.parseInt( t.image ) ; } { value = i ; } ( <PLUS> t = <NUMBER> { i = Integer.parseInt( t.image ) ; } { value += i ; } )* <EOF> { return value ; } }
首先第一個改動是BNF生產式的返回類型,這就使得由該BNF生產式生成的方法的返回值類型由void變成了int。另外的改動是,咱們聲明瞭一個可能拋出的異常NumberFormatException。在方法內,聲明瞭3個變量,其中變量t是Token類型的,Token類是咱們編譯.jj文件文件以後生成的類,而Token類中的image屬性則表示匹配到的token的值。在聲明完變量以後,當一個token被BNF生產式匹配到,咱們就能夠經過t =
如今生成的Start方法將有一個返回值,所以咱們對main方法作以下修改:
Public static void main( String[] args ) throws ParseException, TokenMgrError, NumberFormatException { Adder parser = new Adder( System.in ); int val = parser.Start() ; System.out.println(val); }
除此以外,咱們還要作以下的一點小改進,咱們看到,下面的代碼出現了兩次:orm
{ i = Integer.parseInt( t.image ) ; } { value = i ; }
雖然在這個例子中影響並不大,可是像這種重複出現的代碼仍是可能會致使代碼維護的問題。所以咱們對這兩行代碼進行重構,將它重構成另一個BNF生產式,並把這個生產式命名爲Primary。blog
int Start() throws NumberFormatException : { int i ; int value ; } { value = Primary() ( <PLUS> i = Primary() { value += i ; } )* <EOF> { return value ; } } int Primary() throws NumberFormatException : { Token t ; } { t=<NUMBER> { return Integer.parseInt( t.image ) ; } }
下面是生成的代碼,從中咱們能夠看出javacc如何吧java的變量聲明和邏輯代碼跟生產式融合起來的。token
final public int Start() throws ParseException, NumberFormatException { int i ; int value ; value = Primary(); label 1: while (true) { switch ((jj ntk==-1)?jj ntk():jj ntk) { case PLUS: ; break; default: jj la1[0] = jj gen; break label 1; } jj consume token(PLUS); i = Primary(); value += i ; } jj consume token(0); {if (true) return value ;} throw new Error(」Missing return statement in function」); } final public int Primary() throws ParseException, NumberFormatException { Token t ; t = jj consume token(NUMBER); {if (true) return Integer.parseInt( t.image ) ;} throw new Error(」Missing return statement in function」); }
通過上面的修改,最終獲得.jj描述文件內容以下,咱們將其保存命名爲adder2.jj:input
/* adder.jj Adding up numbers */ options { STATIC = false ; } PARSER_BEGIN(Adder) class Adder { public static void main( String[] args ) throws ParseException, TokenMgrError, NumberFormatException { Adder parser = new Adder( System.in ); int val = parser.Start(); System.out.println(val); } } PARSER_END(Adder) SKIP : { " "} SKIP : { "\n" | "\r" | "\r\n" } TOKEN : { < PLUS : "+" > } TOKEN : { < NUMBER : (["0"-"9"])+ > } int Start() throws NumberFormatException : { int i ; int value ; } { value = Primary() ( <PLUS> i = Primary() { value += i ; } )* <EOF> { return value ; } } int Primary() throws NumberFormatException : { Token t ; } { t=<NUMBER> { return Integer.parseInt( t.image ) ; } }
能夠看到,input.txt輸入文件中的內容是1+2,運行完程序以後,便可計算出結果:3。
一樣的,若是input.txt文件中的內容是1-2,則會報 詞法異常 ,以下圖所示:
it
若是input.txt文件中的內容是1++2,則會報 語法異常 ,以下圖所示:
io