2011-12-08 76 views
2

我想構建一個解析並列出頭文件內容的程序。到目前爲止,這麼好,我發現它很容易解析和列出我編寫的頭文件,但是當我開始解析跨平臺API頭時,事情變得混亂。解析不規則的C++原型

我目前的做法是相當簡單的,這裏是解析以下功能的僞代碼示例:

void foo(int a); 

void is a type, so we are dealing with instancing a type 
foo is the name of that type 
foo is followed by brackets, meaning it is a function of type void named foo 
    int is a type... 
    a is the name of that type instance 
foo is a function of type void that takes one parameter of type int named a 

然而,當我進入更大和更復雜的頭,我偶然發現有些不規則的原型,包括宏和上帝知道什麼。舉例:

GLAPI void APIENTRY glEvalCoord1d(GLdouble u); 

GLAPI和APIENTRY是平臺相關的宏。我的簡單解析方案會破壞哪種類型,因爲它期望對象的名稱遵循其類型。這兩個宏恰好轉換爲__stdcall,__declspec(dllimport)或extern,但理論上它們可能意味着什麼,在編譯之前它們的含義不清楚。

如何編寫我的解析器,以便它可以處理這種情況,而不會感到困惑?宏本身是在早期階段定義的,所以解析器可以意識到GLAPI和APIENTRY是宏,因此它們可以簡單地被忽略,這是要走的路嗎?自然地,這只是衆多不規則之處的變體之一,解析器可能偶然發現通過不同的頭文件進行解析,所以任何有關如何處理任何「合法」頭文件內容解析的通用技術都是受歡迎的。

+0

不,我不需要任何建議。乾杯,但。 –

+0

我很抱歉,有一個感嘆號「需要建議!」但由於某種原因,該網站將其更改爲?甚至在我編輯我的帖子後,它仍然把一個問號...奇怪,但我假設,因爲我發佈了一個問題,問號是默認的...讓我猜,你試圖編輯它,並失敗了? ? :) – dtech

+0

哈,你是對的..它確實似乎重寫了尾隨感嘆號。 –

回答

1

在解析之前沒有任何真正的選擇來擴展宏,至少如果你想處理與微軟相同複雜度的頭文件,或者任何其他與編譯器系統相關的頭文件已經存在10次年或以上。

未經處理的源代碼不是C;它只是沒有經過處理的源代碼。這些宏(以及令人驚訝的預處理器條件並未提及)可以以任意而又非常複雜的方式編輯這個API。除非您也處理#includes,否則您通常無法知道所使用的宏或擴展的條件。

你可以讓GCC爲你做預處理器擴展,然後解析它。這將是最接近 的最簡單方法。

這仍然留下解析真正的C代碼的問題,具有所有的聲明的複雜性,以及片段中的含糊不清等問題T X;其中語句的含義取決於T的聲明。要準確解析標題,您需要一個完整的C語法分析器。

我們的C Front End可以做完整的預處理,或者你可以調用它的模式,其中一些宏展開,有些不是。通過調整這個集合,你經常分析這樣的頭文件,而不會泄露每個宏。預處理器條件要困難得多,因爲它們可能發生在不方便(非結構化)的地方。

0

如果你想要的只是函數的名字和簽名,那麼簡單的搜索和替換宏就足夠了。

但是,您需要檢查宏是否包含關鍵字(如返回值)。這可能是通過剝離每個關鍵字的宏定義來實現的,因爲它們是被定義的,但是跟蹤它們並使用簡單的預處理器將是必要的。

與平臺相關的關鍵字(如__declspec__attribute__)的語法非常有限,並且只有少數幾個,因此可以特別刪除這些關鍵字。

您可能想要看看doxygen如何處理這個問題,因爲它幾乎完全符合您的需求並處理宏。它允許根據定義擴展宏列表,以及應擴展爲自定義值的宏列表。您可以調整它以將__declspec(x)擴展爲空,並且默認情況下將所有其他擴展爲其定義的值。

這當然不是萬無一失的,但搜索和替換是關於您將獲得的最簡單的功能解決方案。您需要遵循標準的C++預處理器規則,這些規則不是非常複雜,需要額外的宏(const,declspec等)去除額外的屬性,並解析最終的結果。