<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    迷途書(shū)童

    敏感、勤學(xué)、多思
    隨筆 - 77, 文章 - 4, 評(píng)論 - 86, 引用 - 0
    數(shù)據(jù)加載中……

    JavaCC、解析樹(shù)和 XQuery 語(yǔ)法,第 2 部分

    本文的第 1 部分簡(jiǎn)要討論了語(yǔ)法、解析器和 BNF。然后它介紹了 JavaCC,一個(gè)流行的解析器生成器。第 2 部分演示了如何修改第 1 部分中的樣本代碼,這樣就可以使用附加工具 JJTree 來(lái)構(gòu)建相同解析的解析樹(shù)表示。您將探索這種方法的優(yōu)點(diǎn),并研究如何編寫(xiě) Java 代碼在運(yùn)行時(shí)遍歷該解析樹(shù)以便恢復(fù)其狀態(tài)信息,并對(duì)正在解析的表達(dá)式求值。本文結(jié)尾將演示如何開(kāi)發(fā)通用例程,用于遍歷從一小部分 XQuery 語(yǔ)法生成的解析樹(shù),并對(duì)其求值。

    使用 JavaCC 解析器生成器有一個(gè)嚴(yán)重缺點(diǎn):許多或大多數(shù)客戶機(jī)端 Java 代碼需要嵌入到 .jj 語(yǔ)法腳本中,該腳本編碼了您的 BNF(巴科斯-諾爾范式,Backus-Naur Form)。這意味著您失去了在開(kāi)發(fā)周期中合適的 Java IDE 可以向您提供的許多優(yōu)點(diǎn)。

    開(kāi)始使用 JJTree 吧,它是 JavaCC 的伙伴工具。JJTree 被設(shè)置成提供一個(gè)解析器,該解析器在運(yùn)行時(shí)的主要工作不是執(zhí)行嵌入的 Java 操作,而是構(gòu)建正在解析的表達(dá)式的獨(dú)立解析樹(shù)表示。這樣,您就可以獨(dú)立于生成該解析樹(shù)的解析代碼,捕捉在運(yùn)行時(shí)易于遍歷和查詢的單個(gè)樹(shù)中的解析會(huì)話的狀態(tài)。使用解析樹(shù)表示還會(huì)使調(diào)試變得更容易,并縮短開(kāi)發(fā)時(shí)間。JJTree 是作為 JavaCC 分發(fā)版(distribution)的一部分發(fā)布的(請(qǐng)參閱 參考資料)。

    在我們繼續(xù)之前,我要特別提一下,術(shù)語(yǔ) 解析樹(shù)抽象語(yǔ)法樹(shù)(或 AST)描述了非常相似的語(yǔ)法結(jié)構(gòu)。嚴(yán)格地講,對(duì)于我在下面提到的解析樹(shù),語(yǔ)言理論家更精確地把它稱作 AST。

    要使用 JJTree,您需要能夠:

    1. 創(chuàng)建 JJTree 作為輸入獲取的 .jjt 腳本
    2. 編寫(xiě)客戶機(jī)端代碼以遍歷在運(yùn)行時(shí)生成的解析樹(shù)并對(duì)其求值

    本文演示了如何執(zhí)行這兩種操作。它并沒(méi)有涵蓋所有內(nèi)容,但肯定能帶您入門(mén)。

    JJTree 基礎(chǔ)知識(shí)

    JJTree 是一個(gè)預(yù)處理器,為特定 BNF 生成解析器只需要簡(jiǎn)單的兩步:

    1. 對(duì)所謂的 .jjt 文件運(yùn)行 JJTree;它會(huì)產(chǎn)生一個(gè)中間的 .jj 文件
    2. 用 JavaCC 編譯該文件( 第 1 部分中討論了這個(gè)過(guò)程)

    幸運(yùn)的是,.jjt 文件的結(jié)構(gòu)只是我在第 1 部分中向您顯示的 .jj 格式的較小擴(kuò)展。主要區(qū)別是 JJTree 添加了一個(gè)新的語(yǔ)法 node-constructor構(gòu)造,該構(gòu)造可以讓您指定在解析期間在哪里以及在什么條件下生成解析樹(shù)節(jié)點(diǎn)。換句話說(shuō),該構(gòu)造管理由解析器構(gòu)造的解析樹(shù)的形狀和內(nèi)容。

    清單 1 顯示了一個(gè)簡(jiǎn)單的 JavaCC .jj 腳本,它類似于您在第 1 部分中看到的腳本。為簡(jiǎn)便起見(jiàn),我只顯示了結(jié)果。


    清單 1. simpleLang 的 JavaCC 語(yǔ)法
    												
    														void simpleLang()   : {}    { addExpr() <EOF> }
    
    void addExpr()      : {}    { integerLiteral() ( "+" integerLiteral() )? }
    
    void integerLiteral()   : {}    { <INT> }
    
    SKIP  : { " " | "\t" | "\n" | "\r" }
    
    TOKEN : { < INT : ( ["0" - "9"] )+ > }
    
    
    												
    										

    該語(yǔ)法說(shuō)明了該語(yǔ)言中的合法表達(dá)式包含:

    1. 單個(gè)整數(shù)文字,或
    2. 一個(gè)整數(shù)文字,后面跟一個(gè)加號(hào),再跟另一個(gè)整數(shù)文字。

    對(duì)應(yīng)的 JJTree .jjt 腳本(再次聲明,略有簡(jiǎn)化)看上去可能如下:


    清單 2. 等價(jià)于清單 1 中的 JavaCC 語(yǔ)法的 JJTree
    												
    														SimpleNode simpleLang() : #Root       {}  { addExpr() <EOF> { return jjtThis; }}
    
    void addExpr()          :             {}  { integerLiteral()
    
                                              ( "+" integerLiteral() #Add(2) )? }
    
    void integerLiteral()   : #IntLiteral {}  { <INT> }
    
    SKIP  : { " " | "\t" | "\n" | "\r" }
    
    TOKEN : { < INT : ( ["0" - "9"] )+ > }
    
    
    												
    										

    該腳本對(duì)您已經(jīng)看到的腳本添加了一些新的語(yǔ)法特性。現(xiàn)在,我們只討論突出顯示的部分。以后,我會(huì)詳細(xì)說(shuō)明。



    回頁(yè)首


    逐句說(shuō)明 JJTree 語(yǔ)法

    首先請(qǐng)注意,最頂層的 simpleLang() 結(jié)果的 JavaCC 的過(guò)程性語(yǔ)法現(xiàn)在指定了一個(gè)返回類型: SimpleNode 。它與嵌入的 Java 操作 return jjtThis (有一點(diǎn)為 JJTree 虛張聲勢(shì))一起指定了從應(yīng)用程序代碼調(diào)用解析器的 simpleLang() 方法將返回解析樹(shù)的根,然后這個(gè)根將用于樹(shù)遍歷。

    在 JavaCC 中,解析器調(diào)用看上去如下:

    												
    														   SimpleParser parser = new SimpleParser(new StringReader( expression ));
    
        parser.simpleLang();
    
    
    												
    										

    而現(xiàn)在看上去象下面這樣:

    												
    														   SimpleParser parser = new SimpleParser(new StringReader( expression ));
    
        SimpleNode rootNode = parser.simpleLang();
    
    
    												
    										

    注:所抓取的根節(jié)點(diǎn)并不僅僅是 SimpleNode 類型。它其實(shí)是 Root 類型,正如 清單 2 中的 #Root 偽指令所指定的(雖然您不會(huì)在上述調(diào)用代碼中那樣使用)。 RootSimpleNode 子代,就象 JJTree 生成的解析器構(gòu)造的每個(gè)節(jié)點(diǎn)一樣。我將在下面向您顯示 SimpleNode 的一些內(nèi)置方法。

    addExpr() 結(jié)果中的 #Add(2) 構(gòu)造與上述的 #Root 偽指令不同,體現(xiàn)在以下幾方面;

    • 它是參數(shù)化的。樹(shù)構(gòu)建器在構(gòu)造樹(shù)期間使用節(jié)點(diǎn)堆棧;沒(méi)有參數(shù)的節(jié)點(diǎn)構(gòu)建器的缺省行為是將自己放在正在構(gòu)造的解析樹(shù)的頂部,將所有節(jié)點(diǎn)彈出在同一個(gè) 節(jié)點(diǎn)作用域 中創(chuàng)建的節(jié)點(diǎn)堆棧,并把自己提升到那些節(jié)點(diǎn)父代的位置。參數(shù) 2 告訴新的父節(jié)點(diǎn)(在此示例中是一個(gè) Add 節(jié)點(diǎn))要恰好采用 兩個(gè)子節(jié)點(diǎn),它們是 下一段文字 中描述的兩個(gè) IntLiteral 子節(jié)點(diǎn)。JJTree 文檔更詳細(xì)地描述了這個(gè)過(guò)程。使用好的調(diào)試器在運(yùn)行時(shí)遍歷解析樹(shù)是另一個(gè)寶貴的輔助方法,它有助于理解樹(shù)構(gòu)建在 JJTree 中是如何工作的。
    • #Root 偽指令放在其結(jié)果的主體之外表示 每次 遍歷該結(jié)果時(shí)都會(huì)生成一個(gè) Root 節(jié)點(diǎn)(而在此特定示例中,只允許發(fā)生一次),這一點(diǎn)具有同等的重要性 。但是,將 #Add(2) 偽指令放在可選的“零或一”項(xiàng)中表示僅當(dāng)在解析期間遍歷包含它的選擇子句時(shí) ― 換句話說(shuō),當(dāng)該結(jié)果表示一個(gè)真的加法操作時(shí) ― 才 有條件地 生成一個(gè) Add 節(jié)點(diǎn)。當(dāng)發(fā)生這種情況時(shí),會(huì)遍歷 integerLiteral() 兩次,每次調(diào)用時(shí)都將一個(gè) IntLiteral 節(jié)點(diǎn)添加到樹(shù)上。這兩個(gè) IntLiteral 節(jié)點(diǎn)都成為調(diào)用它們的 Add 節(jié)點(diǎn)的子節(jié)點(diǎn)。但是,如果正在解析的表達(dá)式是單個(gè)整數(shù),那么作為結(jié)果的 IntLiteral 節(jié)點(diǎn)將直接成為 Root 的一個(gè)子節(jié)點(diǎn)。

    一圖勝千言(引用一句古老的諺語(yǔ))。以下是由上述語(yǔ)法生成的兩種類型的解析樹(shù)的圖形表示:


    圖 1:?jiǎn)蝹€(gè)整數(shù)表達(dá)式的解析樹(shù)


    圖 2:加法操作的解析樹(shù)

    讓我們更詳細(xì)地研究 SimpleNode 的類層次結(jié)構(gòu)。



    回頁(yè)首


    使用解析樹(shù)

    在 .jjt 腳本中聲明的每個(gè)節(jié)點(diǎn)都指示解析器生成 JJTree SimpleNode 的一個(gè)子類。接下來(lái), SimpleNode 又實(shí)現(xiàn)名為 Node 的 Java 接口。這兩個(gè)類的源文件都是由 JJTree 腳本和定制 .jj 文件一起自動(dòng)生成的。 清單 1 顯示了定制 .jj 文件的當(dāng)前示例。在當(dāng)前示例中,JJTree 還提供了您自己的 RootAddIntLiteral 類以及沒(méi)有在這里看到的一些附加的助手類的源文件。

    所有 SimpleNode 子類都繼承了有用的行為。 SimpleNode 方法 dump() 就是這樣一個(gè)例子。它還充當(dāng)了我以前的論點(diǎn)(使用解析樹(shù)使調(diào)試更容易,從而縮短開(kāi)發(fā)時(shí)間)的示例。以下三行客戶機(jī)端代碼的代碼片段實(shí)例化了解析器、調(diào)用解析器、抓取所返回的解析樹(shù),并且將一個(gè)簡(jiǎn)單的解析樹(shù)的文本表示轉(zhuǎn)儲(chǔ)到控制臺(tái):

    												
    														   SimpleParser parser = new SimpleParser(new StringReader( expression ));
    
        SimpleNode rootNode = parser.simpleLang();
    
        rootNode.dump();
    
    
    												
    										

    圖 2 中的樹(shù)的調(diào)試輸出是:

    												
    														   Root
    
            Add
    
                IntLiteral
    
                IntLiteral
    
    
    												
    										



    回頁(yè)首


    輔助導(dǎo)航

    另一個(gè)有用的內(nèi)置 SimpleNode 方法是 jjtGetChild(int) 。當(dāng)您在客戶機(jī)端向下瀏覽解析樹(shù),并且遇到 Add 節(jié)點(diǎn)時(shí),您會(huì)要抓取它的 IntLiteral 子節(jié)點(diǎn)、抽取它們表示的整數(shù)值,并將這些數(shù)字加到一起 ― 畢竟,那是用來(lái)練習(xí)的。假設(shè)下一段代碼中顯示的 addNode 是表示我們感興趣的 Add 類型節(jié)點(diǎn)的變量,那我們就可以訪問(wèn) addNode 的兩個(gè)子節(jié)點(diǎn)。( lhsrhs 分別是 左邊(left-hand side)右邊(right-hand side)的常用縮寫(xiě)。)

    												
    														    SimpleNode lhs = addNode.jjtGetChild( 0 );
    
         SimpleNode rhs = addNode.jjtGetChild( 1 );
    
    
    												
    										

    即使到目前為止您已經(jīng)執(zhí)行了所有操作,但您仍然沒(méi)有足夠的信息來(lái)計(jì)算該解析樹(shù)表示的算術(shù)運(yùn)算的結(jié)果。您的當(dāng)前腳本已經(jīng)省略了一個(gè)重要的細(xì)節(jié):樹(shù)中的兩個(gè) IntLiteral 節(jié)點(diǎn)實(shí)際上不包含它們聲稱要表示的整數(shù)。那是因?yàn)楫?dāng)記號(hào)賦予器(tokenizer)在輸入流中遇到它們時(shí),您沒(méi)有將它們的值保存到樹(shù)中;您需要修改 integerLiteral() 結(jié)果來(lái)執(zhí)行該操作。您還需要將一些簡(jiǎn)單的存取器方法添加到 SimpleNode



    回頁(yè)首


    保存和恢復(fù)狀態(tài)

    要將所掃描的記號(hào)的值存儲(chǔ)到適當(dāng)?shù)墓?jié)點(diǎn)中,將以下修改添加到 SimpleNode

    												
    														   public class SimpleNode extends Node
    
        {
    
            String m_text;
    
            public void   setText( String text ) { m_text = text; }
    
            public String getText()              { return m_text; }
    
            ...
    
        }
    
    
    												
    										

    將 JJTree 腳本中的以下結(jié)果:

    												
    														   void integerLiteral() : #IntLiteral {} <INT> }
    
    
    												
    										

    更改成:

    												
    														   void integerLiteral() : #IntLiteral { Token t; }
    
                                            { t=<INT> { jjtThis.setText( t.image );} }
    
    
    												
    										

    該結(jié)果抓取它剛在 t.image 中遇到的整數(shù)的原始文本值,并使用您的 setText() setter 方法將該字符串存儲(chǔ)到當(dāng)前節(jié)點(diǎn)中。 清單 5 中的客戶機(jī)端 eval() 代碼顯示了如何使用相應(yīng)的 getText() getter 方法。

    可以很容易地修改 SimpleNode.dump() ,以提供任何節(jié)點(diǎn)的 m_text 值供其在解析期間存儲(chǔ) ― 我把這作為一個(gè)眾所周知的練習(xí)留給您來(lái)完成。這將讓您更形象地理解在進(jìn)行調(diào)試時(shí)解析樹(shù)看起來(lái)是什么樣子。例如,如果您解析了“42 + 1”,略經(jīng)修改的 dump() 例程可以生成以下有用的輸出:

    												
    														   Root
    
            Add
    
                IntLiteral[42]
    
                IntLiteral[1]
    
    
    												
    										



    回頁(yè)首


    組合:XQuery 的 BNF 代碼片段

    讓我們通過(guò)研究實(shí)際語(yǔ)法的一個(gè)代碼片段來(lái)進(jìn)行組合和總結(jié)。我將向您演示一段非常小的 XQuery 的 BNF 子集,這是 XML 的查詢語(yǔ)言的 W3C 規(guī)范(請(qǐng)參閱 參考資料)。我在這里所說(shuō)的大多數(shù)內(nèi)容也適用于 XPath,因?yàn)檫@兩者共享了許多相同的語(yǔ)法。我還將簡(jiǎn)要地研究運(yùn)算符優(yōu)先級(jí)的問(wèn)題,并將樹(shù)遍歷代碼推廣到成熟的遞歸例程中,該例程可以處理任意復(fù)雜的解析樹(shù)。

    清單 3 顯示了您要使用的 XQuery 語(yǔ)法片段。這段 BNF 摘自 2002 年 11 月 15 日的工作草案:


    清單 3:一部分 XQuery 語(yǔ)法
    												
    														[21]  Query              ::= QueryProlog QueryBody
    
        ...
    
    [23]  QueryBody          ::= ExprSequence?
    
    [24]  ExprSequence       ::= Expr ( "," Expr )*
    
    [25]  Expr               ::= OrExpr
    
        ...
    
    [35]  RangeExpr          ::= AdditiveExpr ( "to"  AdditiveExpr )*
    
    [36]  AdditiveExpr       ::= MultiplicativeExpr (("+" | "-") MultiplicativeExpr )*
    
    [37]  MultiplicativeExpr ::= UnionExpr (("*" | "div" | "idiv" | "mod") UnaryExpr )*
    
          ...
    
    
    												
    										

    您將要構(gòu)建一個(gè)剛好適合的 JJTree 語(yǔ)法腳本來(lái)處理結(jié)果 [36] 和 [37] 中的 +-*div 運(yùn)算符,而且簡(jiǎn)單地假設(shè)該語(yǔ)法所知道的唯一數(shù)據(jù)類型是整數(shù)。該樣本語(yǔ)法 非常小,并不能妥善處理 XQuery 支持的豐富的表達(dá)式和數(shù)據(jù)類型。但是,如果您要為更大、更復(fù)雜的語(yǔ)法構(gòu)建解析器,它應(yīng)該能給您使用 JavaCC 和 JJTree 的入門(mén)知識(shí)。

    清單 4 顯示了 .jjt 腳本。請(qǐng)注意該文件頂部的 options{} 塊。這些選項(xiàng)(還有許多其它可用選項(xiàng)開(kāi)關(guān))指定了其中樹(shù)構(gòu)建在本例中是以 多重 方式運(yùn)行的,即節(jié)點(diǎn)構(gòu)造器用于顯式地命名所生成節(jié)點(diǎn)的類型。備用方法(不在這里研究)是結(jié)果只將 SimpleNode 節(jié)點(diǎn)提供給解析樹(shù),而不是它的子類。如果您想要避免擴(kuò)散節(jié)點(diǎn)類,那么該選項(xiàng)很有用。

    還請(qǐng)注意原始的 XQuery BNF 經(jīng)常將多個(gè)運(yùn)算符組合到同一個(gè)結(jié)果中。在 清單 4中,我已經(jīng)將這些運(yùn)算符分離到 JJTree 腳本中的單獨(dú)結(jié)果中,因?yàn)檫@讓客戶機(jī)端的代碼更簡(jiǎn)單。要進(jìn)行組合,只需存儲(chǔ)已掃描的運(yùn)算符的值,就象對(duì)整數(shù)所進(jìn)行的操作一樣。


    清單 4:清單 3 中的 XQuery 語(yǔ)法的 JJTree 腳本
    												
    														options {
    
       MULTI=true;
    
       NODE_DEFAULT_VOID=true;
    
       NODE_PREFIX="";
    
    }
    
    PARSER_BEGIN( XQueryParser )
    
    package examples.example_2;
    
    public class XQueryParser{}
    
    PARSER_END( XQueryParser )
    
    SimpleNode query()     #Root      : {} { additiveExpr() <EOF> { return jjtThis; }}
    
    void additiveExpr()               : {} { subtractiveExpr()
    
                                           ( "+" subtractiveExpr() #Add(2) )* }
    
    void subtractiveExpr()            : {} { multiplicativeExpr()
    
                                           ( "-" multiplicativeExpr() #Subtract(2) )* }
    
    void multiplicativeExpr()         : {} { divExpr() ( "*" divExpr() #Mult(2) )* }
    
    void divExpr()                    : {} { integerLiteral()
    
                                           ( "div" integerLiteral() #Div(2) )* }
    
    void integerLiteral() #IntLiteral :    { Token t; }
    
                                           { t=<INT> { jjtThis.setText(t.image); }}
    
    SKIP  : { " " | "\t" | "\n" | "\r" }
    
    TOKEN : { < INT : ( ["0" - "9"] )+ > }
    
    
    												
    										

    該 .jjt 文件引入了幾個(gè)新的特性。例如,該語(yǔ)法中的運(yùn)算結(jié)果現(xiàn)在是 迭代的 :通過(guò)使用 * (零次或多次)發(fā)生指示符來(lái)表示它們的可選的第二項(xiàng),這與 清單 2 中的 ? (零次或一次)表示法相反。該腳本所提供的解析器可以解析任意長(zhǎng)的表達(dá)式,如“1 + 2 * 3 div 4 + 5”。

    實(shí)現(xiàn)優(yōu)先級(jí)

    該語(yǔ)法還知道 運(yùn)算符優(yōu)先級(jí)。例如,您期望乘法的優(yōu)先級(jí)比加法高。在實(shí)際例子中,這表示諸如“1 + 2 * 3”這樣的表達(dá)式將作為“1 + ( 2 * 3 )”進(jìn)行求值,而不是“( 1 + 2 ) * 3”。

    優(yōu)先級(jí)是通過(guò)使用級(jí)聯(lián)樣式實(shí)現(xiàn)的,其中每個(gè)結(jié)果會(huì)調(diào)用緊隨其后的較高優(yōu)先級(jí)的結(jié)果。級(jí)聯(lián)樣式和節(jié)點(diǎn)構(gòu)造的位置和格式保證了以正確的結(jié)構(gòu)生成解析樹(shù),這樣樹(shù)遍歷可以正確執(zhí)行。用一些直觀圖形也許更易于理解這一點(diǎn)。

    圖 3 顯示了由此語(yǔ)法生成的解析樹(shù),它可以讓您正確地將“1 + 2 * 3”當(dāng)作“1 + ( 2 * 3 )”進(jìn)行求值。請(qǐng)注意, Mult 運(yùn)算符與它的項(xiàng)之間的聯(lián)系比 Plus 更緊密,而這正是您希望的:


    圖 3. 結(jié)構(gòu)正確的樹(shù)

    圖 4顯示的樹(shù)(該語(yǔ)法 不會(huì)生成這樣的樹(shù))表示您(錯(cuò)誤地)想要將該表達(dá)式當(dāng)作“(1 + 2) * 3”求值。


    圖 4. 結(jié)構(gòu)不正確的樹(shù)



    回頁(yè)首


    遍歷解析樹(shù)客戶機(jī)端

    就象我曾答應(yīng)的,我將用客戶機(jī)端代碼的清單作為總結(jié),該清單將調(diào)用該解析器并遍歷它生成的解析樹(shù),它使用簡(jiǎn)單而功能強(qiáng)大的遞歸 eval() 函數(shù)對(duì)樹(shù)遍歷時(shí)遇到的每個(gè)節(jié)點(diǎn)執(zhí)行正確操作。 清單 5中的注釋提供了關(guān)于內(nèi)部 JJTree 工作的附加詳細(xì)信息。


    清單 5. 可容易泛化的 eval() 例程
    												
    														   // return the arithmetic result of evaluating 'query'
    
        public int parse( String query )
    
        //------------------------------
    
        {
    
            SimpleNode root = null;
    
         // instantiate the parser
    
            XQueryParser parser = new XQueryParser( new StringReader( query ));
    
                try {
                // invoke it via its topmost production
    
                // and get a parse tree back
    
                root = parser.query();
    
                root.dump("");
    
            }
    
            catch( ParseException pe ) {
    
                System.out.println( "parse(): an invalid expression!" );
    
            }
    
            catch( TokenMgrError e )  {
    
                System.out.println( "a Token Manager error!" );
    
            }
    
            // the topmost root node is just a placeholder; ignore it.
    
            return eval( (SimpleNode) root.jjtGetChild(0) );
    
        }
    
        int eval( SimpleNode node )
    
        //-------------------------
    
        {
    
            // each node contains an id field identifying its type.
    
            // we switch on these. we could use instanceof, but that's less efficient
    
            // enum values such as JJTINTLITERAL come from the interface file
    
            // SimpleParserTreeConstants, which SimpleParser implements.
    
            // This interface file is one of several auxilliary Java sources
    
            // generated by JJTree. JavaCC contributes several others.
    
            int id = node.id;
    
            // eventually the buck stops here and we unwind the stack
    
            if ( node.id == JJTINTLITERAL )
    
                return Integer.parseInt( node.getText() );
    
            SimpleNode lhs =  (SimpleNode) node.jjtGetChild(0);
    
            SimpleNode rhs =  (SimpleNode) node.jjtGetChild(1);
    
            switch( id )
    
            {
    
                case JJTADD :       return eval( lhs ) + eval( rhs );
    
                case JJTSUBTRACT :  return eval( lhs ) - eval( rhs );
    
                case JJTMULT :      return eval( lhs ) * eval( rhs );
    
                case JJTDIV :       return eval( lhs ) / eval( rhs );
    
                default :
    
                    throw new java.lang.IllegalArgumentException(
    
                                      "eval(): invalid operator!" );
    
            }
    
        }
    
    
    												
    										



    回頁(yè)首


    結(jié)束語(yǔ)

    如果您想要查看可以處理許多實(shí)際 XQuery 語(yǔ)法的功能更豐富的 eval() 函數(shù)版本,歡迎下載我的開(kāi)放源碼 XQuery 實(shí)現(xiàn)(XQEngine)的副本(請(qǐng)參閱 參考資料 )。它的 TreeWalker.eval() 例程 例舉了 30 多種 XQuery 節(jié)點(diǎn)類型。還提供了一個(gè) .jjt 腳本。



    回頁(yè)首


    參考資料

    • 您可以參閱本文在 developerWorks 全球站點(diǎn)上的 英文原文.

    • 請(qǐng)加入本文的 論壇。(您也可以單擊本文頂部或底部的 討論來(lái)訪問(wèn)論壇。)

    • 有關(guān)語(yǔ)法、解析器和 BNF 的簡(jiǎn)要討論和 JavaCC 的介紹,請(qǐng)回顧本文的 第 1 部分。您還會(huì)找到使用 JavaCC 構(gòu)建定制解析器的樣本代碼,它從語(yǔ)法的 BNF 描述開(kāi)始。

    • 請(qǐng)?jiān)L問(wèn)免費(fèi)(但不是開(kāi)放源碼) JavaCC 和 JJTree 的分發(fā)版

    • 請(qǐng)?jiān)?XML Query 主頁(yè)上尋找關(guān)于 W3C 的 XQuery 和 XPath 規(guī)范的更多信息。

    • XQEngine 是作者編寫(xiě)的 XQuery 引擎的基于 Java 的開(kāi)放源碼實(shí)現(xiàn)。

    • 想要了解 BNF 的更多知識(shí)嗎?請(qǐng)?jiān)L問(wèn) Wikipedia.org

    • 請(qǐng)?jiān)?developerWorks XMLJava 技術(shù)專區(qū)中尋找本文中所涵蓋技術(shù)的更多信息。

    • IBM WebSphere Studio 提供了以 Java 和其它語(yǔ)言自動(dòng)進(jìn)行 XML 開(kāi)發(fā)的一組工具。它與 WebSphere Application Server緊密集成,而且還可以用于其它 J2EE 服務(wù)器。

    • 了解您怎樣可以成為一名 IBM 認(rèn)證的 XML 及相關(guān)技術(shù)開(kāi)發(fā)人員


    回頁(yè)首


    關(guān)于作者

    Howard Katz 居住在加拿大溫哥華,他是 Fatdog Software 的唯一業(yè)主,該公司專門(mén)致力于開(kāi)發(fā)搜索 XML 文檔的軟件。在過(guò)去的大約 35 年里,他一直是活躍的程序員(一直業(yè)績(jī)良好),并且長(zhǎng)期為計(jì)算機(jī)貿(mào)易出版機(jī)構(gòu)撰寫(xiě)技術(shù)文章。Howard 是 Vancouver XML Developer's Association 的共同主持人,還是 Addison Wesley 即將出版的書(shū)籍 The Experts on XQuery的編輯,該書(shū)由 W3C 的 Query 工作組成員合著,概述了有關(guān) XQuery 的技術(shù)前景。他和他的妻子夏天去劃船,冬天去邊遠(yuǎn)地區(qū)滑雪。可以通過(guò) howardk@fatdog.com與 Howard 聯(lián)系。

    posted on 2006-05-06 16:23 迷途書(shū)童 閱讀(642) 評(píng)論(0)  編輯  收藏 所屬分類: 編譯原理

    主站蜘蛛池模板: 一级毛片免费一级直接观看| 久久精品亚洲综合专区| 又大又硬又爽免费视频| 成年18网站免费视频网站| 在线观看免费人成视频色9| 大地资源在线观看免费高清| 日韩精品福利片午夜免费观着 | 亚洲美女人黄网成人女| 久久综合亚洲色HEZYO社区| 亚洲福利视频网址| 亚洲一级免费毛片| 亚洲乱亚洲乱妇24p| 精品久久亚洲一级α| 免费看美女午夜大片| 国产精品美女久久久免费 | 精品人妻系列无码人妻免费视频| 国产精品青草视频免费播放| 97无码人妻福利免费公开在线视频| 一个人免费视频观看在线www| 97公开免费视频| 亚洲美女中文字幕| 亚洲中字慕日产2021| 亚洲AV无码专区在线电影成人 | 亚洲日产2021三区| 一本色道久久88亚洲精品综合| 无码天堂亚洲国产AV| a级成人毛片免费图片| 国产成人精品免费视频网页大全| 成年人免费网站在线观看| 亚洲男女内射在线播放| 亚洲av无码精品网站| 亚洲va在线va天堂成人| 极品美女一级毛片免费| 免费人成网站在线观看不卡| 日韩版码免费福利视频| 又粗又硬又大又爽免费视频播放| 国产V亚洲V天堂A无码| 国外亚洲成AV人片在线观看| 亚洲欧洲第一a在线观看| 亚洲成A∨人片在线观看不卡 | 伊伊人成亚洲综合人网7777|