7.JavaCC官方入門指南-例2


例2:整數加法運算--改良版(增強語法分析器)

1.修改

  上一個例子中,JavaCC為BNF生產式所生成的方法,比如Start(),這些方法默認只簡單的檢查輸入是否匹配BNF生產式指定的規范。但是我們也可以用java代碼來擴充BNF生產式,使得由生產式生成的方法中也包含java代碼。
  我們加下來會對上面例一中的adder.jj代碼做一些修改。對於其中的Start這個BNF生產式,我們加入一些聲明和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 = 的方式,將token賦值給t從而記錄下來。在BNF生產式中,我們可以加上任何的合法的Java代碼,這些Java代碼在javacc編譯生成語法分析器類時,將會被原封不動的復制到語法分析器類的相應方法中。
  現在生成的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);
}

  除此之外,我們還要做如下的一點小改進,我們看到,下面的代碼出現了兩次:

{ i = Integer.parseInt( t.image ) ; }
{ value = i ; }

  雖然在這個例子中影響並不大,但是像這種重復出現的代碼還是可能會導致代碼維護的問題。因此我們對這兩行代碼進行重構,將它重構成另外一個BNF生產式,並把這個生產式命名為Primary。

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的變量聲明和邏輯代碼跟生產式融合起來的。

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”);
}

2.運行

2.1 adder2.jj

  經過上面的修改,最終得到.jj描述文件內容如下,我們將其保存命名為adder2.jj:

/* 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 ) ; }
}

2.2 運行javacc命令

2.3 編譯生成的java文件

2.4 運行程序

  可以看到,input.txt輸入文件中的內容是1+2,運行完程序之后,即可計算出結果:3。
  同樣的,如果input.txt文件中的內容是1-2,則會報 詞法異常 ,如下圖所示:

如果input.txt文件中的內容是1++2,則會報 語法異常 ,如下圖所示:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM