前言
參考課上PPT内容。 該學習筆記目前僅打算個人使用。
後續會進一步整理,包括添加筆記内容,标明參考資料。
更新中。。。
跳過目錄
目錄
- 一、錯誤處理方法
- 二、錯誤改正
- 三、錯誤局部化處理
-
- 一般原則
- 錯誤局部化處理的實作(遞歸下降分析法)
- 提高錯誤局部化程度的方法
- LL分析的錯誤恢複——補充(第四章内容!)
一、錯誤處理方法
發現錯誤後,在報告錯誤的同時還要對錯誤進行處理,以便編譯能繼續進行下去。
目前有兩種處理辦法:
- 錯誤改正
- 錯誤局部化處理
二、錯誤改正
指編譯診察出錯誤以後,根據語言的文法和對程式意圖作某種猜測,進行錯誤改正。
例:
A[i, j := B + * C
- 編譯可根據 A 的定義(聲明),查符号表知道 A 是二維資料,是以應加上“ ] ”;
- 根據表達式定義去掉
(但也有可能去掉*
)+
但不是總能做到改正錯誤
例:
- 多一個右括号還是少一個左括号?
- 若是少了左括号,少在何處?
是以,要正确地改寫錯誤是很困難的。
三、錯誤局部化處理
指當編譯程式發現錯誤後,盡可能将把錯誤的影響限制在一個局部的範圍,避免錯誤擴散和影響程式其它部分的分析。
一般原則
當診斷到錯誤以後,就暫停對後面符号的分析,跳過錯誤所在的文法成分(一旦跳過就認為該文法成分是正确的)然後繼續往下分析。
詞法分析:
- 發現不合法字元,顯示錯誤,并跳過該辨別符(單詞)繼續往下分析。
文法語義分析:
- 跳過所在的文法成分(短語或語句),一般是跳到語句右界符,然後從新語句繼續往下分析。
錯誤局部化處理的實作(遞歸下降分析法)
CX:全局變量,存放錯誤資訊。
- 用遞歸下降分析時,如果發現錯誤,便将有關錯誤資訊(字元串或者編号)送CX,然後轉出錯誤處理程式;
- 出錯程式先列印或顯示出錯位置以及出錯資訊,然後跳出一段源程式,直到跳到語句的右界符(如
、end
),或正在分析的文法成分的合法後繼符号為止,然後再往下分析。;
例:條件語句分析
有如下分析程式:
void if_statement()
{
nextsym(); // 讀下個單詞符号
B(); // 調用布爾表達式處理程式
if (class ! = thensy)
{
cx = 錯誤'缺then'的編号; // 錯誤性質送cx
error(); // 調用出錯處理程式
}
else
{
nextsym();
statement(); // 調用語句分析程式
}
if (class == elsesy)
{
nextsym();
statement();
}
} // end of if_statement()
局部化處理的出錯程式為:
void error()
{
printf("%d, %d, %d\n", cx, 源程式行号, 序号);
do
{
nextsym();
}
until(class == semicolon || class == endsy || class == elsesy)
} //end of error()
可以看出,如發現錯誤就立即跳到語句結尾處(語句右界符 end , ; 等)。這樣的處理比較粗糙,将跳過太多。上例中缺then,就将跳過整個條件語句,使得then後面的語句都被跳過而不分析,其中若有錯誤就發現不了。
例:ALGOL說明
real x, 1a, a, bed, 2fg;
文法分析時,可發現第二個辨別符有錯,按上述處理辦法則跳到該語句的右界符
;
,這導緻最後一個辨別符的錯誤未檢查出來,且因為正确說明的辨別符 a 、 bed 未進
行分析,則後面對這兩個辨別符 的引用都将被判定為未 聲 明 。
提高錯誤局部化程度的方法
設:
- S1:合法後繼符号集 (某文法成分的後繼符号)
- S2:停止符号(跳讀必須停止的符号集)
當發現錯誤時:error( S1, S2 )
procedure error( S1, S2 )
begin
write( line-no, char-no, cx);
repeat
nextsym
until( class in S1 or class in S2 );
end error;
上面例題中的 if 語句中,若<B>有錯,則可跳到then;
若statement有錯,則可跳到 else。
LL分析的錯誤恢複——補充(第四章内容!)
當符号棧頂的終結符和下一個輸入符号不比對,或棧頂是非終結符A,輸入符号a,而M [A , a]為空白(即error)時,則分析發現錯誤。
錯誤恢複的基本思想是:跳過一些輸入符号,直到期望的同步符号之一出現為止。
同步符号(可重新開始繼續分析的輸入符号)集合通常可按以下方法确定:
- 把FOLLOW(A)的所有符号加入A的同步符号集。如果我們跳讀一些輸入符号直到出現FOLLOW(A)的符号,之後把 A 從棧中彈出,繼續往下分析即可。
- 隻用FOLLOW(A)作為非終結符A的同步符号集是不夠的(容易造成跳讀過多,如輸入串中缺少語句結束符分号時)。此時可将作為語句開頭的關鍵字加入它的同步符号集,進而避免這種情況的發生。
- 把FIRST(A)的符号加入非終結符A的同步符号集中。
- 如果非終結符A可以産生空串,那麼推導ε的産生式可以作為預設的情況。這樣做可以推遲某些錯誤檢查,但不會漏過錯誤。
- 如果終結符在棧頂而不能比對,則可彈出該終結符并發出一條資訊後繼續分析。這好比把所有其他符号均作為該符号的同步集合元素。
-
目标程式運作時錯誤檢測與處理
對于這類錯誤,要正确地報告出錯誤位置很難,因為目标程式與源程式之間難以建立位置上的對應關系。
在編譯時生成檢測該類錯誤的代碼。
• 下标變量下标值越界
• 計算結果溢出
• 動态存儲配置設定資料區溢出
一般處理辦法:
當目标程式運作檢測到這類錯誤時,就調用異常處理,列印錯誤資訊和運作現場(寄存器和存儲器中的值)等,然後停止程式運作。