2011-09-12 51 views
4

我需要一個外語編程語言的解析器。我爲它寫了一個語法,並使用解析器生成器(PEGjs)來生成解析器。這完美地工作......除了一件事:宏(用預定義文本替換佔位符)。我不知道如何將它融入語法。讓我來說明這個問題:如何用基於語法的解析器替換宏?

一個例子程序解析通常是這樣的:

instructionA parameter1, parameter2 
instructionB parameter1 
instructionC parameter1, parameter2, parameter3 

沒有問題爲止。但該語言也支持宏:

Define MacroX { foo, bar } 
instructionD parameter1, MacroX, parameter4 

Define MacroY(macroParameter1, macroParameter2) { 
    instructionE parameter1, macroParameter1 
    instructionF macroParameter2, MacroX 
} 

instructionG parameter1, MacroX 
MacroY 

當然,我可以定義一個語法來標識宏和對宏的引用。但在這種情況下,我不知道我將如何解析宏的內容,因爲它不清楚宏包含的內容。它可能只是一個參數(這是最簡單的),但它也可以是一個宏中的幾個參數(如我的示例中的MacroX,代表兩個參數)或一整塊指令(如MacroY)。而宏甚至可以包含其他宏。如果不清楚宏的語義是什麼,我怎樣才能把它寫成語法?

最簡單的方法似乎是先運行預處理器來替換所有的宏,然後才運行解析器。但在這種情況下,行號會變得混亂。如果存在解析錯誤,我希望解析器生成包含行號的錯誤消息。如果我預處理輸入,行號不再對應。

非常感謝。

+2

回覆:線條越來越亂了:在讀入宏定義之後,可以輸出相當數量的空行,或者可以輸出類似'#line N'的東西,並向您的解析器添加一條規則:#line N'將當前行號改爲'N'。 (這是GCC和大多數C預處理程序處理'#include'指令的方式。) –

回答

3

宏處理器往往不尊重語言元素的邊界;實質上,它們(通常)可以對顯式輸入字符串進行任意更改。

如果是這種情況,您幾乎沒有選擇:您需要構建一個宏處理器,可以保留行號。

如果宏總是包含結構良好的語言元素,並且它們總是出現在代碼中的結構化位置,那麼您可以添加宏定義的概念並調用語法。這可能會使你的解析模糊不清; C代碼中的foo(x)可能是宏調用,也可能是函數調用。你必須以某種方式解決這種模糊性。 C解析器用於通過在解析時收集符號表信息來解決這種歧義問題;如果您在解析時收集is-foo-a-macro,則可以確定foo(x)是否是宏調用。

0

有了PEG,它比其他任何東西都容易得多。首先,基於Packrat的解析器等都是可擴展的。您的宏定義可以修改語法,所以下次使用它時,它將自然被解析。見herehere這種方法的一些極端例子。

另一種可能性是鏈式解析器,這對於基於PEG的方法來說也是微不足道的。

1

使用PEG,您必須手動定義可以檢查宏擴展的位置。您可以將您的宏添加到哈希中,並在PEG規則中檢查它,這允許使用宏(中綴expr,後綴expr,unop,binop,函數調用...)。它不像lisp那麼容易,但比YACC和它的運算符優先級攻擊更容易:)

其他已知的PEG框架允許像parrot,perl6,katahdin或PFront這樣的宏使用技巧在運行時執行解析時間,因此交易與表現。 或者你可以同時做這兩個,並允許預編譯和解釋的PEG分析。有幾個項目考慮過這個問題,但你需要一個快速虛擬機,比如luajit,java,clr或者朋友。

我使用特殊的語法塊關鍵字來加載外部共享庫與外部預編譯的PEG分析器。例如。將SQL或FFI聲明分析到您的AST中。 但是,您也可以要求使用C編譯器,並在運行時爲所有宏編譯解析。