1. 程式人生 > >SASL編譯器Diagnostic資訊的管理、格式化與輸出

SASL編譯器Diagnostic資訊的管理、格式化與輸出

1. Diagnostic需要提供哪些資料

出錯處理和錯誤提示,是編譯器開發過程中重要而繁瑣的部分。

診斷資訊的格式因編譯器和IDE而不同。

SALVIA將採用Visual Studio的格式,即 檔案 + 行列 + 類別(等級) + 編號 + 出錯資訊。例如:

d:\programming\salvia\sasl\test\cgllvm_test\function_test_basic.cpp(16): error C2061: syntax error : identifier 'te'

因此在出錯分析的時候,也需要提供如上的一些資訊。


2. 診斷資訊Diagnostic Item

在以上資訊中,檔名和行列號可以在詞法分析的時候獲得,我們將它作為屬性附加在Token中。

類別和編號,對於同一個編譯器而言是相對固定的,儘管我們可以用ID來表示,但是它並不直觀,編譯器檢查也較少。與引數匹配時,也比較容易出錯。

SASL中的診斷資訊將每個錯誤都使用一個型別來表達:

classdiagnostic_item
{
};
classunrecognized_identifier:publicdiagnostic_item
{
public:
unrecognized_identifier&token(token_ttok);
private:
staticintlevel;
staticintid;staticstd::stringdescription_template
; private: std::stringident; size_trow,col; // Other properties };

這樣的好處在於可以用Combinator的風格來撰寫錯誤資訊。例如這樣:

diagnostic_chat.report<unrecognized_identifier>().token( err_tok );

並且由於編譯器的保證也比較不容易寫錯。

但是這種寫法也有一個很關鍵的問題,需要為每個錯誤都定義一個類,工作量很大。SASL對這一問題的處理,自然是傳統的大殺器:運用指令碼進行生成。

Clang使用了它內建的程式碼生成工具td來完成生成的工作。

3. 診斷資訊管理器Diagnostic Chat

Chat是診斷資訊的管理工具。它主要要完成以下需求:新增和清理診斷資訊,以及在診斷資訊的新增清理時提供回撥操作。

後者是很有用的,尤其是在除錯編譯器的時候。你得分清楚究竟是真正的程式錯誤呢,還是編譯器出了錯。

Diagnostic Chat的原型如下:

classdiagnostic_chat
{
public:
template<typenameT>T&report();
voidadd_report_diagnostic_handler(DiagnosticHandlerThandler);
};

同時,我們也將Treat Warning As Error,Error Count,Disable Warning,Stop compiling when error occurs等狀態和功能所需要的支援新增到Chat中。

所以,Chat除了提供管理之外,也要具有相應的診斷資訊的統計功能。

4. 過濾器Diagnostic Filter

Filter主要配合IDE使用,從Chat中取出符合條件的診斷資訊。Error Count和Disable Warnings等功能也可以通過它來完成。

5. Formatter

Formatter用於將DiagnosticItems中的資訊轉換成人可讀的字串。目前SASL只打算支援Visual Studio的格式,但是相信支援GCC的格式以更好的和Eclipse等第三方IDE整合並不困難。

在C#裡面,我們可以用“We need ‘{0}’ not ‘{1}’.”這樣的方式來分離description template並延期的產生格式化的字串。但是在C++中,這種做法並不容易。C的sprintf很難具有延期、漸增的繫結模板的特定,對自定義型別的字串化的支援也不足,型別安全也比較差;而stream的話,也會面臨著將好端端的格式化字串割裂的問題。SASL使用了boost.format,從一定程度上搞定了這兩個問題,從而像C#一樣,使用格式化字串的功能。