2013-06-05 36 views
1

我基本上需要用Python編寫一個C預處理器,我已經搜索過,因爲我需要完全自定義我的代碼,並且對發生的事情有完美的理解,所以我最好自己寫。使用Python製作預處理器

這裏是我的位置:我首先解析一些頭文件(.h)以找到#define關鍵字,並用所有建立的指令構建一個dictionnary(用它們的值指定它們)。然後我需要解析源文件(.c),這取決於我之前找到的指令。 我目前使用的機制來檢查代碼是否需要處理如下:我將所有定義的名稱和它們的值,並執行exec("define_name = define_value")(未指定時值爲'1')。然後,爲了解決諸如#if defined DEFINE_1 || defined DEFINE_2 && (DEFINE_3 == 10) ....的條件,我刪除了C預處理器關鍵字以使它們成爲Python風格,這將產生DEFINE_1 or defined DEFINE_2 and (DEFINE_3 == 10)

我終於在該字符串上使用eval(...)來找出結果。

問題是我想知道如果使用exec/eval是必要的,許多人都不願意使用它們,有沒有更好的解決方案?

+0

根據我對基於Python的預處理器的經驗,Python太慢而不適合這個。另外,用於例如MSVC不好預處理(儘管編譯更糟糕)。你想解決什麼問題? – imallett

回答

2

當然exec()是不需要的,不應該使用。我甚至不知道你期望它做什麼,因爲它會調用一個shell來設置一個只存在於子shell中的變量。

而且通常情況下,您應該避免使用eval()陳述以及很少做正確的事情。

那麼,你可以做什麼?

1)首先關閉,因爲程序可以寫入一個語句覆蓋先前語句的位置,所以無法預處理.h文件(或者甚至假設您正在查找的#define只是首先在.h文件中),然後讓它工作。考慮這個:

#define foo 1 
#if foo == 1 
this line is true! 
#endif 
#define foo 0 

如果你預先處理所有你將設置「foo」爲1,然後爲0,然後評估#if以後。你不能這樣做......

2)更常見的事情是編寫一行一行地解析每行一行內容的解析器。這樣你甚至可以編寫一個遞歸函數來處理#include語句,這樣你就可以從.c文件開始,讓它使用正確的頭文件,而不是以其他方式指定它們。

最後,你應該像結束(在一個名爲「READ_FILE」功能):

# ... file opening not shown ... 

for line in file: 
    includematch = re.match("#include\\s+\\"(.*)\\"", line) 
    if match: 
     # deal with an include statement by calling a function to process it 
     read_file(includematch.group(1), definedict) 

    definematch = re.match("#define\\s+(\\w+)\\s+(.*)") 
    if definematch: 
     # deal with define statements by saving it in a dict 
     definedict[match.group(1)] = definedict[match.group(2)] 

    #.... 

顯然,如果我給你的整體解決方案(及以上幾乎沒有漂亮的代碼,但它是簡潔的顯示目的)我會爲你解決你的問題(作業?)。但是,上述是建立整個事情的一種更好的方式,而不是你走下的路。

+0

謝謝你的回答,這不是作業的功課;)。爲了精確一些事情,我所處理的項目非常嚴格,人們不允許在他們想要的地方放置'#define'(我只有1或2個文件只是用'#define'填充,所以我只需要解析),所以不會像你說的那樣重新定義。我目前有一個工作代碼,但是加載了'eval/exec',主要問題是我如何處理複雜的'#if /#elif' ...條件,而不使用eval和exec ? – Jaay

+0

那麼,你必須最終做一個全面的解析器(這是更難但更安全)或評估。 Eval允許你跳過實現paren匹配,邏輯等,你可以專注於只是替換值,然後評估其餘的。您始終可以從eval開始,並從那裏開始工作,在未來取代理想。 –

+0

注意:僅僅因爲你現在有一個結構嚴格的環境,現在有一定的規則,並不意味着這些規則將來不會改變。你可能會考慮首先以正確的方式來反映cpp,只是爲了幫助未來的自己。 –