1. 程式人生 > 其它 >ANTLR3C--呼叫生成的語法檔案(How to build Generated C Code 原文翻譯)

ANTLR3C--呼叫生成的語法檔案(How to build Generated C Code 原文翻譯)

技術標籤:antlr

為了執行 lexer/解析器/樹解析器組合,您需要一個小函式(或 main)函式來控制事件序列,從讀取輸入檔案或字串,到呼叫樹解析器和檢索結果。有關更多詳細資訊,請參閱"使用 ANTLR3C C target",但如果您只想儘可能快地執行,請學習以下程式碼示例。

您可以採取所有措施,但是通常最好為您的專案建立一個include,其中將包含ANTLR3 C執行時標頭檔案和生成的標頭檔案(所有這些檔案都可以多次包含)和您自己的專案相關標頭檔案。在編譯行上使用<>包含和-I(vs2005現在可以處理,而vs2003現在不可以)。
 
 #include
<treeparser.h>
此示例的主要入口點 int ANTLR3_CDECL main(int argc,char * argv []{ 現在,我們宣告所需的與ANTLR相關的區域性變數。 請注意,除非確信您將永遠不需要專案的執行緒安全版本,否則應始終為每次呼叫建立諸如例項變數之類的東西。 ------------------- 輸入檔案的名稱。請注意,對於ASCII / 8位字串,我們始終使用抽象型別pANTLR3_UINT8-執行時庫保證在所有平臺上都可以使用。這是一條通用規則-始終將ANTLR3提供的typedef
用於指標/型別/等。 pANTLR3_UINT8 fName; ANTLR3字元輸入流,該輸入流對輸入源進行了抽象處理,從而很容易從不同的源(例如檔案或儲存字串)中獲取輸入。 對於8Bit / latin-1 / etc儲存字串,請使用: input = antlr3New8BitStringInPlaceStream (stringtouse, (ANTLR3_UINT32) length, NULL); 對於UTF16記憶體字串,請使用: input = antlr3NewUTF16StringInPlaceStream (
stringtouse, (ANTLR3_UINT32) length, NULL); 有關檔案的輸入,請參見下面的程式碼 請注意,這實質上是指向包含函式指標的結構的指標。 您可以建立自己的輸入流型別(複製現有型別之一),並在建立標準版本後通過安裝自己的指標來覆蓋任何單個函式。 pANTLR3_INPUT_STREAM input; 詞法分析器當然是由ANTLR生成的,因此詞法分析器型別不是大寫的。 向詞法分析器提供pANTLR3_INPUT_STREAM,從那裡開始消耗其輸入並生成令牌流作為輸出。這是詞法分析器的ctx(CTX巨集)指標。 pLangLexer lxr; 令牌流由ANTLR3生成的詞法分析器生成。同樣,它是基於結構的API/物件,您可以根據需要自定義和覆蓋方法。令牌流將提供給生成的解析器,您可以編寫自己的令牌流並將其傳遞給您。 pANTLR3_COMMON_TOKEN_STREAM tstream; Lang解析器也由ANTLR生成,並接受令牌流,如上所述。令牌流實際上可以是任何源,只要它實現ANTLR3_TOKEN_SOURCE介面即可。在這種情況下,解析器不返回任何內容,但是它當然可以從呼叫時呼叫的規則中指定任何型別的返回型別。這是解析器的ctx(CTX巨集)指標。 pLangParser psr; 解析器生成AST,該AST作為起始規則(當然,任何規則都可以首先起始)的返回型別的成員返回。這是根據我們開始的規則生成的型別。 LangParser_decl_return langAST; 樹節點由樹介面卡管理,後者根據請求分配節點。您可以建立自己的樹型別和介面卡,並覆蓋內建版本。有關詳細資訊,請參見執行時源,最後請參見C target的Wiki條目。 pANTLR3_COMMON_TREE_NODE_STREAM nodes; 最終,當解析器執行時,它將生成可以由樹解析器c.f. LangDumpDecl.g3t遍歷的AST。這是樹解析器的ctx(CTX巨集)指標。 在此示例中,根據命令列中提供給我們的引數建立輸入流,如果沒有顯式引數,則輸入將始終預設為./input。 if (argc < 2 || argv[1] == NULL) { fName =(pANTLR3_UINT8)"./input"; 注意在VS2005除錯中,必須配置工作目錄 } else { fName = (pANTLR3_UINT8)argv[1]; } 使用提供的檔名建立輸入流(對UTF16輸入使用antlr38BitFileStreamNew)。 input = antlr38BitFileStreamNew(fName); 只要有足夠的記憶體並且檔案存在,輸入將成功建立 if ( input == NULL ) { ANTLR3_FPRINTF(stderr, "Unable to open file %s due to malloc() failure1\n", (char *)fName); } 現在我們的輸入流已開啟,所有設定都可以使用,因此我們可以建立詞法分析器的新例項,並將詞法分析器輸入設定為輸入流: (file | memory | ?) --> inputstream -> lexer --> tokenstream --> parser ( --> treeparser )? lxr = LangLexerNew(input); CLexerNew由ANTLR生成 需要檢查錯誤 if(lxr == NULL{ ANTLR3_FPRINTF(stderr, "Unable to create the lexer due to malloc() failure1\n"); exit(ANTLR3_ERR_NOMEM); } 我們的詞法分析器就位,因此我們可以從中建立令牌流 注意:除了讀取檔案以外,什麼都沒發生。我們只是將所有這些東西連線在一起,當我們呼叫解析器規則時將呼叫它們。除非您有非常大的令牌流/輸入,否則通常可以將ANTLR3_SIZE_HINT保留為預設值。每個生成的詞法分析器都提供一個令牌源介面,這是令牌流建立者的第二個引數。 請注意,即使您實現自己的令牌結構,該令牌結構中也始終會包含一個標準的通用令牌,這是您傳遞給其他所有物件的指標。一個通用令牌,作為其中的一個指標,應指向您自己的外部令牌結構。 tstream = antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT,lxr-> pLexer-> tokSource); if (tstream == NULL) { ANTLR3_FPRINTF(stderr, "Out of memory trying to allocate token stream\n"); exit(ANTLR3_ERR_NOMEM); } 最後,既然我們已經構造了詞法分析器,就可以建立解析器了 psr = LangParserNew(tstream); CParserNew由ANTLR3生成 if (psr == NULL) { ANTLR3_FPRINTF(stderr, "Out of memory trying to allocate parser\n"); exit(ANTLR3_ERR_NOMEM); } 我們都準備好了。儘管乍一看看起來很複雜,但是我敢肯定,您會發現實際上上面的大多數程式碼都在處理錯誤,沒有那麼多事情要做(在C中不是總是這樣嗎?)。 因此,我們現在呼叫解析器。 ANTLR3生成的C元件的所有元素以及ANTLR C執行時庫本身都是偽物件。這意味著它們被表示為指向結構的指標,該結構包含所需的任何例項資料,以及一組指向其他介面或“方法”的指標。請注意,通常,我們在此處建立的這幾個指標是您將顯式使用free()的唯一方法,因為其他所有方法都是通過工廠建立的,它們可以高效分配記憶體,並在關閉解析器/詞法分析器時自動使用free()所使用的所有方法/等等。 請注意,這僅意味著方法總是通過物件指標來呼叫,而任何方法的第一個引數都是指向結構本身的指標。如果您使用的是VS2005之類的IDE,那麼在鍵入->時,您將看到物件支援的所有方法的列表,這也具有副作用。 langAST = psr-> decl(psr); 如果解析器正確執行,我們將有一棵樹要解析。通常,我建議保留自己的標誌作為錯誤陷阱的一部分,但是如果您使用通用錯誤訊息,則可以通過以下方法確定是否有錯誤 if (psr->pParser->rec->errorCount > 0) { ANTLR3_FPRINTF(stderr, "The parser returned %d errors, tree walking aborted.\n", psr->pParser->rec->errorCount); } else { nodes = antlr3CommonTreeNodeStreamNewTree(langAST.tree, ANTLR3_SIZE_HINT); // sIZE HINT WILL SOON BE DEPRECATED!! 給樹解析器一個公共的樹節點流(或您的覆蓋) treePsr = LangDumpDeclNew(nodes); treePsr->decl(treePsr); nodes ->free (nodes); nodes = NULL; treePsr ->free (treePsr); treePsr = NULL; } 我們沒有從此解析器規則返回任何內容,因此可以完成。剩下的只是關閉開啟的物件,以相反的順序建立它們 psr ->free (psr); psr = NULL; tstream ->free (tstream); tstream = NULL; lxr ->free (lxr); lxr = NULL; input ->close (input); input = NULL; 返回0; }