摘要 程序定義域的確定有利于指導測試用例的選取。雖然程序規范規定了輸入變量的定義域,但程序實現本身也定義了其定義域,如果二者不能完全重合,那么某些軟件錯誤就可診斷出來。為此,本文提出了一種基于數據流分析的程序定義域自動確定方法。通過對源程序進行數據流分析和相關性分析,求取輸入變量的定義域。采用程序抽取技術,將與輸入變量無關的語句和函數剔除,簡化了源程序,提高了分析效率。采用動態模擬技術,實現了特殊情形下輸入變量的定義域確定。實驗證明該方法是行之有效的。
關鍵詞 數據流分析、程序抽取、動態模擬、非數值變量、程序定義域
中圖法分類號 TP311.5
A Method of Program Domain Automated Determination
Based on Data Flow Analysis
Ruilian Zhao and Yinghua Min
Abstract The determination of program's input domain is helpful to select test data. The implementation of a program defines the domain of input variables, though the specification of the program also specifies the domain. However, if they are not coincided with each other exactly, some software errors can be detected. This paper presents a novel approach of program domain automated determination based on data flow analysis. Using the techniques of data flow analysis and relevance analysis on given program the domain can automatically be identified. The program slicing method is employed to delete those statements and functions that are not related to input variables, so that the given program is simplified and analyzing efficiency is improved. The domain of input variables can be obtained under some particular circumstances by using dynamic stimulation strategy. A lot of experimental results show that the proposed approach is efficient.
Keyword data flow analysis, program slicing, dynamic stimulation, nonnumeric variable, program domain.
1 引言
盡管軟件質量保證貫穿于軟件生存期的各個階段,但軟件測試仍然是保證軟件質量的重要措施,是對軟件功能、設計和實現的最終審定。要檢驗開發的軟件是否符合規格說明書的要求,可以采取各種不同的測試策略。例如:基于程序的白盒測試或基于規范的黑盒測試,隨機測試或窮舉測試,自頂向下測試或自底向上測試等等 [1] 。但是,不論采取哪一種測試策略,設計測試方案 (testing case) 都是測試階段最關鍵的技術問題 [1,2,3] ,測試以前都需要從程序定義域 (domain) 中選取有代表性的測試數據。因此,程序定義域對于測試數據的選取,尤其對邊界值分析有著直接的指導作用。程序定義域如何確定?就目前而言,大多是以程序規范 (specification) 說明的輸入變量的取值范圍為其定義域,其正確性依賴于規范的正確性。事實上,我們不能保證規范說明完全正確。雖然程序規范規定了輸入變量的定義域,但程序實現本身也定義了其定義域。軟件規范給定的功能是定義在輸入空間的一個所謂功能域 D f 上,而被測程序本身定義了輸入空間的一個所謂運行域 D p 。正如 [4] 指出的,在需求階段,系統由功能 (function) 來給定,而在開發和運作中,系統將由運行 (operation) 來描述。功能域 D f 和運行域 D p 是否相等,如果兩者不能完全重合,那么某些軟件錯誤就可診斷出來。但是,兩者完全重合,并不說明軟件沒有錯誤。對于那些不能從定義域中反映出來的錯誤,可采用等價劃分、邏輯覆蓋、錯誤推斷等測試方法進行檢測。
一般而言,輸入空間可表示為: E = E 1
E 2
E 3
E 4 , 其中 E 1 =D f
D p , E 2 =
f
D p , E 3 =D f
p , E 4 =
f
p 。 E 1 表明規范和程序有相同的輸入子域,但實現與說明是否一致,還需進一步研究。 E 2 表明程序產生了一個結果,但規范并沒有要求。對于這種情況,要么補充規范,要么縮小其程序的運行域。 E 3 表明規范的某些要求,程序沒有處理。這顯然是不允許的,應該修改程序。 E 4 關于例外處理,即規范既未要求,程序也無從處理。在高可靠的軟件中,例外處理必不可少。如果我們能夠得到被測程序的定義域,那么不僅可以進行程序定義域的重合驗證,而且還可以得到輸入子域 E 1 、 E 2 、 E 3 、 E 4 。根據其規范說明與程序實現之間的差異,選取測試用例,可以克服測試的盲目性,有效地提高測試效率。因此,從程序本身探討其定義域非常必要,然而對于這一重要問題,很少有文獻提及。
為此,本文提出了一種基于數據流分析的程序定義域自動確定方法,從程序結構本身出發,通過對源程序進行數據流分析和相關性分析,實現其定義域的自動確定;采用動態模擬( dynamic stimulation )技術確定一些特殊情形下輸入變量的定義域。該方法的實現為邊界值分析、測試數據的自動生成提供了一種新的、有效的途徑,為程序定義域的重合驗證奠定了基礎。
2 基本概念
數據流分析 (data flow analysis) 在軟件開發、測試和維護中起著十分重要的作用。它將程序中變量的出現分為變量的定義 (definition) 和引用 (use) ,若語句 I 實現對變量 v 存儲單元的賦值,則稱 I 定義變量 v ;若語句 I 引用變量 v 存儲單元的值,則稱 I 引用變量 v [5,6,7] 。
由于應用的領域不同,分析數據的屬性也有所不同。我們的方法將每條程序語句看作一個結點,方法中涉及的有關概念定義如下:
定義 1 程序定義域 D:
程序各輸入變量取值范圍的笛卡爾乘積,構成其定義域 D [8] 。
即 D =Dx 1 ′ Dx 2 ′ … ′ Dx n ={ ( x 1 , x 2 , ... x n ) ? " x 1 ? Dx 1 , " x 2 ? Dx 2 , … , " x n ? Dx n } 。
其中 x i ( i=1 , 2 , n )是程序的輸入變量, Dx i 是 x i 所有可能的取值。
定義 2 變量 v 的定義集 def (v) :
def (v) 由定義變量 v 的所有結點組成。
即 def (v)={i ? 結點 i 定義了變量 v} 。
本方法中,定義不僅指對變量的賦值,變量的類型說明,函數入口結點對參數的說明都看作是對變量的定義。
定義 3 變量 v 的引用集 use (v) :
use (v) 由引用變量 v 的所有結點組成。
即 use (v)={i ? 結點 i 引用了變量 v} 。
定義 4 定義變量 v 的引用變量集 indef (v) :
indef (v) 由定義變量 v 時所引用的變量組成。
即 indef ( v)={x ? 變量 v 的定義中引用了變量 x} 。
例如: v = x + y - z ;
則 : indef ( v) = { x , y , z }
定義 5 引用變量 v 的涉及變量集 inuse (v) :
inuse (v) 由引用變量 v 時所涉及的變量組成。
即 inuse (v)={x ? 引用變量 v 時涉及了變量 x} 。
例如: if ( v > x + y ) ;
則 : inuse (v) = { x , y }
定義 6 程序表示等價:
定義函數 exec 是從程序集及其定義域到輸出的影射,即
program_set ′ input_set ? output_set
或 exec(program,input)=output,
如果對任意的 input , exec(program_p , input)=exec(program_p' , input), 則稱程序 P 和 P' 表示等價。
3 程序定義域自動確定的實現
我們以結構良好的 C 語言程序為例進行研究。同時要求源程序能通過編譯并運行。
3 .1 主要算法思想
基于數據流分析的程序定義域自動確定方法,采用程序抽取技術,通過對源程序進行數據流分析及相關性分析,從中抽取出與自變量(輸入變量)相關的部分,剔除與自變量無關的語句及函數。只分析與自變量相關的部分,可以簡化程序定義域的求取,提高分析效率。
程序抽取 (program slicing) 是一種廣泛應用于程序調試、軟件測試及維護的技術。它從被測程序中抽取出與故障代碼相關聯的語句,忽略了許多與此無關的語句,減少了故障因素的分析范圍,有利于故障原因的定位 [9,10,11,12] 。
本文方法采用兩種程序抽取算法,基于自變量的程序抽取和基于標準 C = (I , q , V) [11,12] 的程序抽取 (q 為有特殊取值要求的表達式, I 為 q 對應的結點, V 為 q 中變量的集合 ) ,其主體結構如下:
while ( input file name)
{
create_table (filename_p);
program_slicing (filename_p,newfile_ p' );
create_table (newfile_ p' );
domain_determine (newfile_ p' , slicefile);
}
源程序 P 以文件形式讀入,由 create_table (P) 生成關于 P 的各種表格;依據其信息, program_slicing ( ) 從 P 中抽取出與自變量有關的部分 P' ; domain_determine ( ) 根據 create_table (P') 生成的新表格,完成自變量的定義域確定。對一些特殊情形,進行基于標準 C = (I , q , V) 的程序抽取,動態模擬求其定義域。
3 .1 .1 建立源程序 P 的各種表格 create_table ( p )
逐行掃描源程序 P ,對其每一函數 i ,建立函數參數表、函數調用表、變量表、自變量表及復合語句表等。其中函數參數表記錄與該函數有關的各種信息;如函數名、形參名、形參個數、函數中定義的變量數、涉及的自變量數、被調用函數的數目等。函數調用表記錄被調用函數的名稱、實參等信息;變量表是數據流分析中最關鍵的數據結構,記錄函數所定義變量的名稱、類型及其 def( ) 、 use( ) 、 indef( ) 、 inuse( ) 等信息;自變量表記錄函數中出現的自變量,同時在變量表中有關于自變量定義、引用的詳細信息。
對于數組變量,數組元素 a[e] 的定義看作是對數組 a 的定義,其 indef (a) 由表達式 e 中所引用的變量和賦值號右邊所引用的變量組成;數組元素 a[e] 的引用看作是對數組 a 的引用,其 inuse (a) 由表達式 e 中所引用的變量及引用 a[e] 時所涉及的變量組成。
例如: a[ i + j ] = a [ k - 3 ] + v ;
則: indef ( a ) ={ i , j , a , k , v } 。
對于指針變量,其變量的定義、引用類似于簡單變量的定義、引用,只是它的變量類型帶有 * ,以表明是指針變量。
3 .1 .2 基于自變量的程序抽取 program_slicing( )
基于自變量的程序抽取,根據 create_table (P) 生成的表格信息,分析變量的定義引用關系、相關性以及函數調用關系等,從源程序 P 中抽取出與自變量相關的部分 P' ,剔出與自變量無關的函數和語句 (include , break 等除外 ) ,并且保證 P' 結構完整;同時就自變量而言,抽取出的程序部分 P' 和源程序 P 二者表示等價,即 exec (P , input ) = exec (P' ,input ) 。
program_slicing( ) 實現基于自變量的程序抽取,其算法如下:
program_slicing( P , P' )
{
從 P main( ) 函數的各種表格開始。
1 掃描變量表 variable_scan( )
對變量表中的每一個變量 v ;
if ( v為自變量 )
則 def(v), use(v) 中的結點, def(x) ? 變量 x ? inuse(v) 中的結點是 P' 中的結點。
else if (x 為自變量 ? x ? indef(v) ú x ? (indef...(indef(v)) ú x ? inuse(v) )
則 def(v), use(v) 中的結點是 P' 中的結點 .
2. 復合語句處理 component_process( ) // 保證程序結構完整 //
對每一個復合語句K
if ( 結點 i ? K ? i ? P' )
則K的源結點、開始點、結束點、 K 中的 break , continue 等結點是 P' 中的結點。
// 源結點對應于條件或循環控制語句 //
else if ( K的源結點 ? P' ù K 中有 break 等結點時 ) 其 break 結點是 P' 中的結點。
else 將K的源結點從 P' 中去掉。 // 復合語句 K 與自變量無關 //
3 . if ( 結點 i ? P' ? i ? 函數 ) 則將函數的源結點、開始點、結束點放入 P' 中。
4 .被調用函數處理 called_func_ process( )
對函數調用表中未處理的被調用函數,根據其函數名,找到函數參數表,重復1、2、3、4步,將與自變量相關的結點放入 P' 中。
5 . P' 結點從小到大排序。
6 .根據 P' 的結點,從源程序中抽取出相應的語句,組成新程序 P' 。
}
例 1 給出源程序 P ,它由函數 main( ) 、 xpoint( ) 、 f( ) 及 power( ) 組成,其自變量為 x 。
例 2 給出新程序 P' ,去掉了與自變量 x 無關的變量 k 及其相關語句和函數 power( ) , P' 變量和函數都與自變量 x 有關。
例 1 :源程序 P :
1 int power(int x, int i)
2 {
3 int p;
4 for(p=1;i>0;--i)
5 p=p*x;
6 return(p);
7 }
8 float f(float x)
9 {
10 float y;
11 y=((x-0.5)*x+16.0)*x-80.0;
12 return(y);
13 }
14
15 float xpoint(float x1)
16 {
17 float y;
18 y=x1*f(x1)/(f(x1)-f(3.453));
19 return(y);
例 2 : 新程序 P' :
1 float f(float x)
2 {
3 float y;
4 y=((x-0.5)*x+16.0)*x-80.0;
5 return(y);
6 }
7 float xpoint(float x1)
8 {
9 float y;
10 y=x1*f(x1)/(f(x1)-f(3.453));
11 return(y);
12 }
13 void main()
14 {
15 float x,y;
16 scanf("%f",&x);
17 y=xpoint(x);
18 printf("%f",y);
19 }
20 }
21 void main()
22 {
23 int k;
24 float x,y;
25 k=0;
26 scanf("%f",&x);
27 k++;
28 printf("%d%d%d\n",k,power(2,k),power(-3,k));
29 y=xpoint(x);
30 printf("%f",y);
31 }
3 .1 .3 建立程序 P' 的各種表格 create_table ( P' )
生成新程序 P' 的函數參數表、函數調用表、變量表、自變量表等。
3 .1 .4 程序 P' 的定義域確定 domain_determine ( )
按語法制導方法對程序 P' 進行詞法和語法分析,根據自變量的類型說明及 create_table (P') 提供的信息,確定其自變量的定義域。但對一些特殊情形,應分別加以考慮。
1 字符串自變量
若程序中含有某些字符函數,比如 atoi( ) , atol( ) , atof( ) , strtol( ) 等,將字符串轉化為數值量,轉化后的結果應在一定的取值范圍內,這時字符串變量的取值應滿足轉化后數據的定義域要求。如例 3 。
例 3 :程序 P' : 例 4 :程序部分 P" :
1 void main()
2 {
3 char name[20];
4 char numstr[20] ;
5 unsigned short num;
6 float score;
7 gets(name);
8 gets(numstr);
9 num=atoi(numstr);
10 score=atof(numstr);
11 }
例 4 :程序部分 P" :
1 float f(float x)
2 {
3 float y;
4 y=((x-0.5)*x+16.0)*x-80.0;
5 return(y);
6 }
7 float func1(float x1)
8 {
9 float y;
10 y=f(x1)-f(3.453);
11 return(y);
12 }
例 3 中自變量 name, numstr 最多允許輸入 19 個字符(緩沖存儲器的最后一個字符為結束符), numstr 轉換后結果應在轉化函數 atoi( ),atof( ) 限制的范圍內,還應滿足賦給變量的取值要求。如語句 9 ,不僅要求輸入字符串轉化后的結果在整數的范圍內,而且還應是無符號的短整數。 domain_determine ( ) 給出其定義域見實驗結果部分。
2 整型、實型自變量
若 P' 中自變量或與自變量相關 的式子,出現在一些有特殊取值要求的表達式中。例如表達式做除數或做一些標準函數的實參(如
、log (x)、acos (x)、asin (x)等),要求變量x在一定范圍內取值。
如果 P' 考慮了表達式的特殊取值要求,假設例 2 的語句 10 為:
if ( ( f(x1) - f(3.453) ) != 0 ) y = x1*f(x1)/(f(x1)-f(3.453) );
則自變量 x 的取值不受表達式 q: f(x1)-f(3.453) 的約束。由于程序設計非常靈活,條件判斷 if ( f(x1) - f(3.453) ) , if ( f(x1) != f(3.453) ) , if ( f(x1)f(3.453) ) 與上述條件判斷等價。識別等價表達式又涉及語義分析,語言理解,其自動實現相當困難。但若不考慮 q 的取值限制,可能又會造成系統失效。因此,不論 P' 是否考慮了表達式 q 的特殊取值要求,我們都對其自變量進行取值分析。
已知表達式 q : X ? Y 及值域 ran q ,由 q -1 可求其自變量的取值范圍。即若存在逆函數 q -1 : Y ? X ,則對于 " y y ? ran q 有 x = q -1 ( y ) ù x ? dom q ,自變量 x 的定義域 dom q = {x ? " y y ? ran q ù x = q -1 ( y ) } 。但對于 y ? ran q , q -1 ( y )是否存在,即使存在,能否從 q 求出 q -1 。如例 2 中表達式 q = f(x1) - f(3.453) ,而 f = ( (x - 0.5)*x +16.0)*x - 80.0 , q -1 計算十分復雜。通過函數求逆,分析自變量的取值范圍,實現困難。為此,我們采用動態模擬, 確定 q中自變量的取值要求。
首先,進行 基于標準 C = (I , q , V) 的程序抽取(其中 I 為表達式 q 對應的結點, V 為 q 中變量的集合)。通過分析變量 v (v ? V) 的定義引用關系及其相關性,從 P' 中抽取出影響或間接影響 I 處表達式 q 及變量 v 的所有結點和函數,對其進行加工處理, 形成 可執行部分 P" 。 使得在結點 I ,對于任意的輸入, P' 相對于表達式 q 的執行結果和 P" 相對于 q 的執行結果相同。 然后,根據表達式 q的值域要求,將 P" 與事先編制好的相應處理函數連接成一個完整的可執行程序。執行該程序,得到 q中自變量的取值范圍。
為描述抽取算法,先定義幾個關系和符號:( K , J 均為結點)
DU 關系: 定義 (definition) ——引用 (use) 關系
K DU J :結點 K 定義了變量 v ,結點 J 引用 v 。即 K ? def(v), J ? use(v) 。
PC 關系: 謂詞 (predicate) ——控制 (control) 關系
K PC J :結點 J 在謂詞 K 的直接影響范圍內,即 K 對 J 有最直接的控制行為。 主要針對: If K then B1 else B2
While K do B ( J ? B1 ú J ? B2 ú J ? B )
FC 關系: 函數 (function) ——控制 (control) 關系
K FC J :結點 J 屬于某一函數或調用了某一函數, K 為函數說明結點。
A 0 : 對 V 中變量有直接影響的結點集。
A 0 = LD ( I , V )
LT ( I )
其中: LD ( I , V ) = 結點 I 之前,對 V 中變量最后一次賦值的結點;
即: LD ( I , V ) = { K ? K = max { K ? def (v) ù ( K < I ) , v ? V} }
LT ( I ) = 對 I 有直接影響的控制行為。
即: LT(I) = { K ? K 滿足( K PC I ) ú ( K FC I ) }
算法實現:
?、?求A 0
?、?令 S 0 = A 0
?、?S i+1 = S i è A i+1
A i+1 ={K ? ( K < I ù K ? S i ù $ J J ? S i )滿足 K R J , R = DU
PC
FC }
重復第 3 步,直到 A i+1 為空。因程序語句有限, A i+1 最終變為空,算法終止。
定義在 P' 結點集上的并運算
具有封閉性,所以 S i+1 中的結點屬于 P' 。 令 P" = S i+1
I,根據 P" 中結點, 從 P' 中抽取出相應的語句,并將q所在函數更名為 funci (第 i 個表達式 q ) , 以保證原函數的完整性;修改函數值為q,加上函數返回語句,形成完整的函數 funci 及 P" 。
如例 2 中,自變量 x 為函數 xpoint( ) 的實參,函數 xpoint( ) 中結點 10 對應的表達式 q : f ( x1 ) - f ( 3.453 )作除數。 X 應如何取值才能保證 f ( x1 ) - f ( 3.453 )不為零?基于標準 C = ( 10 , q , {x1} )的程序抽取,從 P' 中抽取出影響表達式 q 及變量 x1 的所有結點和函數,對其進行加工處理,形成函數 func1 及 P" ,見例 4 。
3 .2 用動態模擬求取定義域
因表達式 q 只有幾種可能情形,如作除數,開方,求導等。根據表達式 q 可能的出現情形,事先編制好相應的處理程序,放在相應的頭文件中, 然后分析程序中表達式 q的具體出現情形及值域要求,將 P" 與相應處理函數連接成一個完整程序。運行該程序,即可得其輸入變量的取值要求。
例如,例 2 結點 10 對應的表達式 q 作除數,其類型為 float ,將用模擬求解方法編制的實現浮點通用函數 divi_float( ) 求根及取值分析的處理函數 fdivi( ) ,放在頭文件 float_divi.h 中,將頭文件 float_divi.h 加入 P" ,定義函數 divi_float( ) 為 func1( ) ,在 main( ) 函數中調用浮點處理函數 fdivi ( ) ,實現對自變量 x 的取值分析。 完整程序 見例 5 。
例 5 :完整的程序:
1 float f(float x)
2 {
3 float y;
4 y=((x-0.5)*x+16.0)*x-80.0;
5 return(y);
6 }
7 float func1(float x1)
8 {
9 float y;
10 y=f(x1)-f(3.453);
11 return(y);
12 }
13 #define divi_float func1
14 #include"float_divi.h"
15 void main()
16 {
17 fdivi();
18 }
運行 P" 與相應處理函數連接成的完整程序,即可得自變量 x 的取值范圍。結果見第 4 部分。
所有自變量的取值范圍構成了程序定義域。
4 實驗結果
為驗證本文所提方法的有效性,我們研制了 C 程序定義域自動確定系統,對多個 C 語言程序,進行了定義域模擬求取實驗。雖然每個程序僅由幾十行語句組成,但卻涉及了復雜的控制關系以及單輸入變量、多輸入變量、自變量表達式、字符串自變量有特殊取值要求等情形,實驗結果與預期結果相同,表明該方法有廣泛的適用性,是確實可行的。
對例 1 ,定義域自動確定系統運行結果為:
3.452942 cannot be assigned to the input variable x.
對例 3 ,其運行結果如下:
The domain of string 'numstr' corresponding 'num' is between 0 and 65535.
The domain of string 'numstr' corresponding 'score' is between -1E308 and 1E308.
The length of string variable 'name' is between 0 and 20-1.
The length of string variable 'numstr' is between 0 and 20-1.
即:程序自變量 name, numstr 最多允許輸入 19 個字符,相應于整數 num 的輸入串 numstr 轉化后的結果應在 0 和 65535 之間,相應于浮點數 score 的輸入串 numstr 轉化后的結果應在 -1E308 和 1E308 之間。
分析結果和實際定義域相符。
5 結論
本文介紹了一種基于數據流分析的程序定義域自動確定方法,該方法從程序結構本身出發,實現了輸入變量定義域的自動確定。通過采用程序抽取技術,剔除與自變量無關的語句及函數,大大簡化了程序定義域的求取,降低了分析成本,提高了分析效率;而且對被測源程序的結構、功能、性能均不產生任何影響。應用前景十分廣泛,對軟件測試過程的自動化有著積極的作用。為后續程序定義域的重合驗證奠定了基礎。當然,要想開發出一個高效、實用的程序定義域自動確定工具,還需做大量的工作和進一步擴充與完善。
參考文獻
• Zheng Ren-jie, "The Technology of Computer Software Testing ", TsingHua University Press. Beijing ,1992.
( 鄭人杰,計算機軟件測試技術,北京:清華大學出版社, 1992 )
• Sandra Rapps and Elaine J.Weyuker, "Selecting Software Teat Data Using Data Flow Information", IEEE Trans. on Software Eng., vol. SE-11, No. 4, April 1985, pp. 367-374.
• B. Marick, "The Craft of Software Testing", PTR Prentice Hall, NJ, 1995.
• M.R.Lyu, Editor, "Handbook of software reliability engineering", IEEE Computer Society Press, CA, 1996, pp.850.
• M. S. Hecht, "Flow Analysis of Computer Program", Amsterdam, The Netherlands: North-Holland, 1977.
• P. G. Frankl and E. J. Weyuker, "A Data Flow Testing Tool", in Proc. IEEE Softfair II , San Francisco, CA, Dec.1985.
• Phyllis G. Frankl and Elaine J.Weyuker, "An Applicable Family of Data Flow Testing Criteria", IEEE Trans. on Software Eng., vol.14, No.10, Oct.1988, pp. 1483-1497.
• Bogdan Korel, "Automated Software Test Data Generation", IEEE Trans. on Software Eng., vol.16, No.8, Auguest.1990, pp. 870-879.
• Bogdan Korel and Janusz Laski, "Dynamic Slicing of Computer Program", J. Systems Software 13, 1990, pp. 187-195.
• Tip,F., "A Survey of Program Slicing Techniques", Journal of Programming Languages, Sept.1995, 3(3), pp. 121-189.
• Tibor Gyimothy, Arpad Beszedes and Istvan Forgacs, "An Efficient Relevant Slicing Method for Debugging", Software Engineering Notes, vol.24, No.6, 1999, pp.304-312
• Gerardo Canfora, Aniello Cimitile and Andrea De Lucia, "Conditioned Program Slicing", Information and Software Technology, 1998,40,pp.595-607.
原文轉自:http://www.anti-gravitydesign.com