天天看點

編譯原理學習筆記 9.4 錯誤處理技術一、錯誤處理方法二、錯誤改正三、錯誤局部化處理

前言

參考課上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)時,則分析發現錯誤。

錯誤恢複的基本思想是:跳過一些輸入符号,直到期望的同步符号之一出現為止。

同步符号(可重新開始繼續分析的輸入符号)集合通常可按以下方法确定:

  1. 把FOLLOW(A)的所有符号加入A的同步符号集。如果我們跳讀一些輸入符号直到出現FOLLOW(A)的符号,之後把 A 從棧中彈出,繼續往下分析即可。
  2. 隻用FOLLOW(A)作為非終結符A的同步符号集是不夠的(容易造成跳讀過多,如輸入串中缺少語句結束符分号時)。此時可将作為語句開頭的關鍵字加入它的同步符号集,進而避免這種情況的發生。
  3. 把FIRST(A)的符号加入非終結符A的同步符号集中。
  4. 如果非終結符A可以産生空串,那麼推導ε的産生式可以作為預設的情況。這樣做可以推遲某些錯誤檢查,但不會漏過錯誤。
  5. 如果終結符在棧頂而不能比對,則可彈出該終結符并發出一條資訊後繼續分析。這好比把所有其他符号均作為該符号的同步集合元素。
  1. 目标程式運作時錯誤檢測與處理

    對于這類錯誤,要正确地報告出錯誤位置很難,因為目标程式與源程式之間難以建立位置上的對應關系。

    在編譯時生成檢測該類錯誤的代碼。

    • 下标變量下标值越界

    • 計算結果溢出

    • 動态存儲配置設定資料區溢出

    一般處理辦法:

    當目标程式運作檢測到這類錯誤時,就調用異常處理,列印錯誤資訊和運作現場(寄存器和存儲器中的值)等,然後停止程式運作。

繼續閱讀