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

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

1.修改

  上一個例子中,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 = 的方式,將token賦值給t從而記錄下來。在BNF生產式中,咱們能夠加上任何的合法的Java代碼,這些Java代碼在javacc編譯生成語法分析器類時,將會被原封不動的複製到語法分析器類的相應方法中。
  如今生成的Start方法將有一個返回值,所以咱們對main方法作以下修改:
code

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

2.運行

2.1 adder2.jj

  通過上面的修改,最終獲得.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 ) ; }
}

2.2 運行javacc命令

2.3 編譯生成的java文件

2.4 運行程序

  能夠看到,input.txt輸入文件中的內容是1+2,運行完程序以後,便可計算出結果:3。
  一樣的,若是input.txt文件中的內容是1-2,則會報 詞法異常 ,以下圖所示:
it

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

相關文章
相關標籤/搜索