2012-09-30 63 views
0

我正在使用Linux平臺上的C++元編程語言的解析器。現在,我需要爲解析器實現選項/長選項來提供一些附加功能。基本上,如果用戶傳入一些額外的選項,解析器需要在解析文本文件時存儲統計信息。C++選項/長選項實現

我可以想出兩種實現方法。一種方法是用戶全局存儲由用戶輸入的選項。另一種方法是創建一個單例類來存儲選項。所以我想知道是否有其他方法來實施它。什麼是最好/最推薦的實施方式?提前致謝。

問候,

K.Hein

+1

由於配置元素無論如何都必須是解析器環境的全局配置元素,所以兩者都可以工作。我建議,除非你有可配置選項的功能集,否則維護一個簡單的id值容器。一旦你知道了某些選項會暴露出來,你可以用更快的方式替換它)保持簡單和開放式。直到那麼 – WhozCraig

+0

你可以在boost :: program_options中看到實現。 – Torsten

回答

2

兩個全局和單身會使你的解析器痛苦的單元測試。要單元測試解析器的行爲與不同的選項,你的測試將需要修改全局。這種方法至少有兩個問題:全局和你的類沒有明確的關聯。除了檢查實現之外,讀者不能判斷在類中使用了哪些全局變量,以及它們如何影響行爲。這樣的全局變量不能是const的(因爲它們是在main中設置的)。所以你放棄了溝通和強制執行的能力,一旦創建解析器,選項的值就不能改變。

經典單例甚至比全局變差,因爲它使您無法替換實現並通常完全阻止測試。

一個不錯的方法是注入一個將選項存儲到解析器構造函數的const對象。但是不要在這個對象中放置命令行解析邏輯,否則你將無法在測試中方便地使用該對象。

+0

嗨,簡,你能詳細介紹一下const對象的注入嗎?或者,如果你能指出一些參考教程/例子,那將會很棒。謝謝:) –

1

爲了擴大在揚的回答,你將有一個功能,如:

bool my_parser(const parser_options &options); 

parser_options類型可以是一個簡單的結構,例如:

struct parser_options 
{ 
    FILE *source_file; 
    bool warnings_as_errors; 
    std::shared_ptr<error_handler> eh; 
    ... 
}; 

error_handler可以這樣定義:

struct error_handler 
{ 
    virtual void error(int code, const char *message) = 0; 
    virtual void warning(int code, const char *message) = 0; 
    virtual ~error_handler() {} 
}; 

該程序然後會做一些喜歡的東西E:

int main(int argc, const char *argv) 
{ 
    parser_options options; 
    // process argc/argv options here, adding them to options, e.g.: 
    //  case WARN_AS_ERROR: options.warnings_as_errors = true; break; 
    return my_parser(options, &error) ? ERROR_SUCCESS : ERROR_FAILURE; 
} 

這允許你編寫直接調用my_parser測試,命令行的處理獨立地設置parser_options,並允許不同的error_handler被指定爲(例如一種將信息格式化爲機器可讀的形式)。

注意:這並不意味着是一個解析器的完美設計,它只是一個如何設計類似的例子。如果應用程序可以配置爲控制流水線(例如,不進行優化,打印內部AST,內部表示,彙編代碼,預處理器輸出),則此設計不是嚴格測試所必需的。但是,設計更靈活,因爲它允許不同的程序直接調用命令行程序(GUI應用程序/ IDE,靜態分析工具等)來使用它。

+0

在解析器應用程序中涉及到相當多的類。那麼採用這種方法,我必須將選項明確地傳遞給應用程序中的每個類?這將需要一些努力來重構類。 –

+0

您可以將選項傳遞給應用程序中的每個類,或者只能傳遞所需的內容(例如,代碼生成類不需要解析選項)。你可以用很多bool選項來使用bitflags。設計一個好的架構非常複雜。你可能會經歷幾次迭代才能正確。從葉類開始,爲它們添加測試並向上構建。這將需要時間,但將是值得的。你應該反覆地改進設計,專注於特定領域,利用你所寫的內容的經驗,不完善的工作或難以更新的內容。 – reece