• 検索結果がありません。

Sapid によるソフトウエア解析技法 Ⅱ : ソフトウエア・メトリックスの作成

N/A
N/A
Protected

Academic year: 2021

シェア "Sapid によるソフトウエア解析技法 Ⅱ : ソフトウエア・メトリックスの作成"

Copied!
20
0
0

読み込み中.... (全文を見る)

全文

(1)

茅再

Sapidに よるソフ トウエア解析技法 工

― ソフ トウエア ・メ トリックスの作成 一

は じめに

Sapid(wwwe Sapid.org/)は 下流 レベルの ソフ トウェア解析 を効率 的 に実

現す るソフ トウエ アエ学 ツ

ール ・プラッ トフオームであ り,ソ フ トウエアの生

産性や品質の向上 を目的 としたプログラムを簡単 に作成す ることがで きる。本

論文では,ソ フ トウエア品質管理

・評価の手法のひとつであるソフ トウエア ・

メ トリックスを求めるプログラムを開発す る。

ソフ トウエア ・メ トリックスは,ソ フ トウエア品質管理,品 質評価の手法 と

して確立 され,開 発現場で も導入 されている。 しか し,実 際 にISOや」

IS等で

提案 されたメ トリックス に基づいたソフ トウエア評価 を行 うためには,構 文解

析等の手法 を用いて,メ トリックス評価 プログラムを作成す る必要がある。構

文解析系 も含 んだプログラムを作成することは容易ではな く,開 発 に多 くの時

間が必要 とされる。

本論文では,Sapidを 利用 して各種 のメ トリックス を求めるプログラムを作

成する。オープンソース として公 開されている,多 くのソフ トウエアのメ トリッ

クスを解析 し,結 果 を統計的に処理 して,メ トリックスに対する評価や比較の

指標 となるデー タを提供す る。オ

ープンソースの解析のために,オ ープンソー

ス ・ソフ トウエアの細粒度 リポジ トリ ・データベースを提供す るア

ーカイバ ・

サ イ トSappy(―

.aichi一

pu.ac.jp/sappy他

)の デー タを利用す る。

第 1章 で関数 とパ ラメー タの名前,型 を求めるプログラムを作成 し,第 2章

第 3章 で関数のメ トリックス情報 を求めるプログラムを作成する。第 4章 でそ

の他のメ トリックス情報 を求め,第 5章 でメ トリックスに関するデ

ー タの活用

(2)

彦根論叢 第 328号

I 関 数 とパ ラメータの名前,型 を求め る 一 オブジェク ト配列 の利用

Sapidに よる ソフ トウエ ア解析技 法 I」 体 は,関 数宣言 ,関 数 オプシ ョナ

ル宣言 と言 った ク ラス のID番 号 を求 め る方法 と して, ト ップ レベ ル (プログ

ラムID)か

ら関連 をた どる方法 (spdGetRe10明

関数群 ),オ ブ ジェク トの包含 関

係 を利用 す る方法 (spdCetlncludedOcc関

数群 )を 解説 した。

ここでは,オ ブジェク ト配列 (型 i SpdOttldArray)を

用 いて該 当す るオブジェ

ク トを求 め る方法 を用 い る。 関数 spdCetOttldArrayによ リオブ ジェ ク ト配列 を

求 め,繰 り返 し制御 (for文な ど)を 用 いて順番 にオブジェク トIDを 求 め る。i

番 目の オ ブ ジ ェ ク トIDは ,オ ブ ジ ェ ク ト配列 変数 の構 造体 メ ンバ変数id L]に

格納 され てい る (例 :血 nc_array.id□

)。

1口 例 題 1 関 数 宣言 オ ブジ ェク トー覧 をも とめ る

関数宣言 オブジェク トー覧 を,オ ブジェク ト配列 (クラス名 :dedaratOn,ソー

トDECL_FUNCDEF)と

して取得 す る。 関数 spdGetObildArrayに

求 め る ク ラス

名 (declaration)を

パ ラメー タ と して ォブ ジ ェ ク ト配列 を求め る。fOr文で順番

にオ ブ ジ ェ ク トIDを 取 り出 し, spdCetAttrV211nt関

数 でsortが関数宣言 (DECL

FUNCDEF)の

もの を取 り出す。

① オブジェク トIDを オブジェク ト配列から求める 一 spdGetObildArray

E C T ―A R R A Y n declaration ← DECL FUNCDEF

② 関数プロトタイプ

オブジェク ト配列←spdGetObildArray(ク

ラス名, 名

前1 条

件)

SpdObjldArray SpdStringi SpdStringi SpdCondObjldFunc

③ 関数プロトタイプ

func_array=spdGetOttldArray(‖ declaration‖

, NULL, NULL);

(3)

Sapldに よるソフ トウエ ア解析技法 コ

2.関

数の名前 と型 を求める

関数宣言 のオブジェク トIDか ら,順 番 に関数,パ ラメ

ー タの名前 と型 を求

める。関数の型の クラス typeは関数の宣言 declaration(属

性 :関数)か ら関連

deCI」

ype(declaration_type)を

た どって求める。 またクラス identiner(名

前)か ら

関連 問ent type(通

entiner_type)で

求めることもで きる (図I参 照)。

パ ラメー タは ク ラス optionaldecl(オ

プ シ ヨナ ル宣言 )か ら,関 連 func parm

(optionaldecl_declaration)を

た ど り,パ ラメー タの宣言 declaratio■

(属性 :変 数)

を順番 に求 め る。 そ こか ら名前 (クラス identiner,関

連 :decLident)と型 (ク

ラス :type,関 連 :deci」

ype)を 求 め る。

④ サ ンプルプログラムI 一 関数名と型を求める

↓オ ブ ジ ェク ト配 列 の 宣 言 S p d O b j l d A r r a y f u n c _ a r r a y ; i n t l ; ↓オ ブ ジ ェ ク ト配 列 の 取 得 func_array=spdGetObjldArray("declaration,,NULI,NULL); fOr(1=0;1く func_array.size;1++)

r(3pdGetAttrValnt料

島拐ざ

ぷ望督あ

ずゲ予

:め

│千

]事

督ぴ)

decr_id=8PaCetARe10bj(func_array.id【

11,"deCl_decl'',巾

anyⅢ

);

I一model

関数定義 main

↓有le_decl

↓func_body

パラメータ

パラメータ

argv

(4)

彦根論叢 第 328号

サ ンプル プログラム I(続 き) 一 関数名 と型 を求める

ident_id = spdGetARe10bj(decr_id,・ decl_ident",Wanyり , func_name= spdGetName(ide nt_id);

type_id= spdGetARe10bj(ident_id,"ident_type",nany"); printf("FUNC_NAME=%‐ 308 FUNC_TYPE=",func_name); getTypeName(type_id);

3口 型の求め方

型の宣言には,int(整 数型),char(文 字型)と いった属性のほかに,const,

volatileと

いった修飾子,longな どのサイズ指定子, signed,unsignedと いっ

たsign才

旨定子 などがある。 また,ポ インター型,配 列,構 造体,共 用体,enum

型 とい った複雑 な型,ユ ーザ定義の型 もある。Sapidはすべての型の宣言 に関

す る情報 を保持 している。本 プログラムでは整数,文 字型 とポインター型,配

列型のみ を扱 う。

ク ラ ス 型 t y p e の 属″性 s o r t が T Y P E _ D E C L A R A T 1 0 N の と き , 関 数 g e t T y p e N a m e B a s i c によ り, 型 の 名 前 を 標 準 出 力 に 出 力 す る 。 関 数 g e t T y p e N a m e は , ク ラ ス 型 t y p e の 属 性 s o r t を 調 べ , T Y P E _ P O I N T E R ( ポ イ ン タ ー 型 ) の 場 合 は そ の 情 報

を出力す る。関連 t y p e _ s t で

続 くt y p e オ

ブジェク トを求め, 関 数 g e t T y p e N a m e を

再 帰 的 に 呼 び 出 す 。

T Y P E t t R R A Y ( 配 列 型 ) の と き も同様 で あ る 。

T Y P E _ D E C L A R A T 1 0 N の

ときは関数 G e t T y p e N a m e B a s i c を

呼び出す。

関数 GetTypeNameBasic:型を求め る関数 (基本型)

char t getTypeNalneBasic(SpdObjld type

if(3pdGetAttrVallnt(type_id,"80rtり =TYPE_DECLARATION) switch(8PdGetAttrVallnt(type_id,巾 typeり)( cage TYPE_INT: return"INT";break; case TYPE_VOID: return"VOID巾 ;break, case TYPE_CHAR: return tCHAR";break; case TYPE_DOUBLE: return・ DOUBLE"ibreak; case TYPE_FLOAT: return"FLOAT";break; case TYPE_DOTSi return m.…Ⅲ;break; c a s e T Y P E _ U N K N O W N : r e t u r n ⅢU N K N O W N Ⅲ ; b r e a k ; return,1; default:

(5)

Sapldに よるソフ トウエ ア解析技法 Ⅱ

4 . パ ラメータ宣言の求 め方

パ ラメー タ部分 の宣 言 は optionaldecl(オ

プ シ ョナル宣言)か ら,関 連 func_

p a r m ( o p t i O n a l d e c l _ d e c i a r a t i o n ) を

た ど り,パ ラメー タの宣言 declaration(属

性 :

変 数 ) を s p d G e t R e 1 0 明

I n i t 関

数群 に よって順番 に求 め る。 そ こか ら名前 ( クラス

: i d e n t i n e r , 関

連 : d e c l _ i d e n t ) と

型 (クラス i type,関

連 : d e c l _ t y p e ) を求める。

関数 GetTypeNameBasic:型 を求める関数 (配列,ポ インタの場合)

v O i d g e t T y p e N a l l l e くS p d O b j i d t y p e _ S p d O b j l d t y p e _ i d l ;

if((type_idl=spdGetARe10bj(type_id,巾 type_st山,Ⅲ allyり)!=SAPID_NON_ID) awitch(8PdGetAttrVallnt(type_id,"80rtり ){ case TYPE_POINTER: printf(“POINTER OF“ ); getTypeName(type_idl)ibreak, case TYPE_ARRAY: printf(“ARRAY OF“ ); getTypeName(type_idl);break; case TYPE_DECLARAT10N: printf(“%s“ ,getTypeNaIIleBasic(type_id l)); break; default: break; }

サ ンプル プログラム I(パ ラメー タ情報取得 まで)

int main(int argC,char targv□) { char ttarget_prOgralII; SpdObjld Prog_id,decr_id,opt_id,param_id,blk_id,ident_id; SpdObjldArray func_array; S p d O c c o p t _ o c c ; S p d C u r s O r t o p t _ c 8 r i i n t l ; t a r g e t _ p r o g r a I E = S m u G e t A P r o g r a m N a m e o ; i f ( ( p r O g _ i d = s p a T a r g e t ( ・I ‐m O d e l Ⅲ, t a r g e t _ p r o g r a m ) ) = = S A P I D _ N O N _ I D ) ( spdErrOrExit("PrOgram¥"%s¥"not found.",target_progra11); } f u n c _ a r r a y = s p d G e t O b j l d A r r a y ( " d e c i a r a t i o n ■, N U L L , N U L L ) , fOr(1=0,1く func_array.oize,1++) i f ( s p d G e t A l t r V a l l n t ( f u n c _ a r r a y . i d 【1 ] , " 8 0 r t " ) = = D E C L _ F U N C D E F ) decr_id=sPdGetARe10bj(func_array.id[1],"deCl_decl","any"); ident_id = 8pdoetARe10bj(decr_id,"decl_ident","anyり ; func_name= 8PdCetName(ident_id);

type_id= 8pdGetARe10bj(ident_id,"ident_typeⅢ ,"anyり, / ★漱 名 前 と型 を 出 力 す る岩 ★/ printf("FUNC_NAME=%-30s FUNC_TYPE=",func_name); getTypeName(type_id); oPt_id=spdGetARe10bj(decr_id,"decl_opt",“ anyり ; if(Opt_id!=SAPID_NON_ID) 【param_id=8pdCetARe10bj(opt_id,・ func_parm","anyり ; blk_id =spdGetARe10bj(opt_id,い func_body",Ⅲany町);

(6)

パラメータ

パラメータ

funcparam

彦根論叢 第 328号

int main(int argc, char t argv[])

[解説]

オプシ ヨナル宣言 (optionaldecl)か

↓funcparam:optionaldecl…

declaration

↓decl_decl:declaratiぃ

declarator

↓decl_ident:declarator―

identifier

↓ident_type:identifler―

type

と型 (type)を た どる。ポインター型,

配列型 は関連 type_stで

順番 にた どる。

ポイ ンター,配 列 は属性sortで指示 され

る。

図 Ⅱ 関 数mainのパ ラメー タの卜model

サ ンプル プログラム I(パ ラメー タ情報取得 まで 続 き)

H 関 数呼び 出 しを求 め る 一 基本 メ トリックス

ソース コー ドの手続 き的 メ トリックス を,プ ログラム ・メ トリックス と関数

メ トリックス に分 ける。 プログラム ・メ トリックスは関数 メ トリックスのデー

タを集計 して求め る。関数 メ トリックスの基本項 目は,関 数の引数の数,行 数,

コメ ン ト行 数 ,コ ールす る関数の情報 な どの項 目か らなる。関数が所属す るプ

ログラム,フ ァイル,関 数 とパ ラメー タの名前 ,型 は,「Sapidによるソフ トウ

1 )

エア解析技法 I」 と第 1章の例題 Iか ら求めることができる。本章では関数呼

び出 しの回数,位 置 といつた情報を求めるプログラムを作成する。

param_id=spdGetARe10bj(opt_id,"func_parm・ ,"anyり, param_csr=spdGetRe10bjlnit(Param_id,"decI_decl","anyり ; w h i l e ( ( p a r a _ i d = s p d C e t R e 1 0 b j ( p a r a m _ C S r ) ) 1 = S A P I D _ N O N _ I D ) ( paraident_id=spdGetARe10bj(para_id,"decl_idellt",Ⅲany"); param_naIIle= 8paGetName(paraident_id), paratype_id=spdGetARe10bj(paraident_id,コ ident_type","any"); printf(・PARAM_NAME=%‐ 30s PARAM_TYPE=",param_name); getTypeNane(Paratype_id);

(7)

S a p i d に

よるソフトウエア解析技法Ⅱ 7 5

1.例 題 2 関 数呼び 出 しの情 報 を求 め る

あ る関数 の中の関数呼 び出 し情報 を求め る手順 を考 える。関数呼 び出 しは,

関数 中の オブ ジ ェ ク トidentiner(名

前 )の 出現 と して求め る。関数定義部 の名

前 に ア クセ ス しない ため に,I―modelの 中で 関数 定 義 名 (ident血

er)よ り下位

に あ る 関 数 の オ プ シ ヨナ ル 宣 言 を基 点 と して , identier(名 前 )の 出 現

(occurrence)をspdGetlndidedOcc関

数群 で求 め る。順 番 にsortが関数 で あ る も

の を選 び,配 列 に格納 す る。 同 じ関数が複 数 回出現 した ときは,重 複 して処理

を行 なわない。

アル ゴ リズ ム

0 関 数名 を格納 す る配列的nc_idを用意す る (準備 )

1.ク ラス 田entier(名前)の オブジェク ト出現 (occurrence)の取得

2.属 性 i sort(種類 )が 関数 (DECL FUNCDEF)で

あ る もの を選ぶ

3.関 名 を格納 す る配列 を調べ ,新 規 の名前 か どうか を判断す る

4.新 規 の関数 であ った場合 は配列 に格納 し,情 報 を出力す る

関数 getFuncCall(関数呼び出 しの情報 を求める)

ne MAX_FUNC_SIZE 100

void getFuncCall(SpdObjld funcDecl_id) ( SpdOcc func_occ; spacursor tfunc_c8r; SpdObjld func_idIMAX_FUNC_SIZEl,funC_id l; int i=0,j=0, V i s i b l e な関 数 の C a l l を求 め る 手 順 Func_cer=spdGetlncludedOcclnit(funCDecl_id,Widentitter",funcDecl_id); 名 前 の 出 現 を 求 め る w h i l e ( ( f u n C _ 。C C = 8 P d G e t l n c l u d e d O c c ( f u n c _ c s r ) ) . r e l a t i o n l d t = S A P I D _ N O N _ I D ) i f ( s p d G e t A t t r V a l l n t ( f u n c _ o c c . o b j e C t l d , " o o r t り= = I D _ F U N C T 1 0 N ) 【 関 数 の 名 前 の 出 現 だ け 抜 き 出 す w h i l e G く= i ) i f ( f u n c _ i d D + 十] = = f u n C _ O C c . o b j e c t l d ) g O t O E X I T 2 , 重 複 す る 関 数 名 の 出 現 が あ っ た 場 合 は 取 り除 く func_id[il=func_occ.ObjeCtldi

printf("Calling Function Name%d:%s¥n・ ,1,spdCetName(func_id ti〕)),

1 + 十 ;

EXIT2: j=0; 〕 }

(8)

76 彦 根論叢 第 328号

サ ンプル プログラム E (関

数 メ トリックス を求め る)

illt main(int argc,char targv口) ( char ttarget_prograal; SpdObjld prog_id,decr_id,opt_id,paran_id,blk_id,ident_id; SpdObjldArray func_array, S p d O c c o p t _ o c c ; S p d C u r 8 0 r t O p t _ c s r i i l l t l ; t a r g e t _ P r o g r a m = s m u G e t A P r o g r a m N a m e o , i f ( ( p r o g _ i d = s p d T a r g e t ( “I ‐m O d e l " , t a r g e t _ p r o g r a m ) ) = = S A P I D _ N O N _ I D ) ( 8pdErrorExit("PrOgram¥"%8¥"■ Ot found.",target…program)テ } f u n c _ a r r a y = 8 p d G e t O b j l d A r r a y ( ・d e c l a r a t i o n " , N U L L , N U L L ) ; for(1=0,1く futtc_array.size,1++) i f ( s p d G e t A t t r V a l I I I t ( f u n c _ a r r a y . i d [ 1 ] , " 8 0 r t り= = D E C L _ F U N C D E F ) decr_id=spdCetARe10bj(func_array,id[11,田deCl_declⅢ,Ⅲany“);

o p t _ i d = s p d C e t A R e 1 0 b j ( d e c r _ i d , " d e c l _ o p t " , 田a n y ・) , │ 関 数 呼 び 出 し情 報 を 出 力 g e t F u n c C a l l ( f u n C _ a r r a y . i d [ 1 1 ) ; 関 数 被 呼 び 出 し情 報 を 出 力 g e t F u n c C a l l e d ( f u n c _ a r r a y . i d t 1 1 ) ; 変 数 メ ト リ ッ ク ス 情 報 を 出 力 getVarNun(prog_id)i

関数 getFuncCall(改良版 )

void getFuncCall(SpdObjld funcDecl_ia)( SpdOcc func_occ; SpdCuraor tFunc_csr, i n t j ; 構 造 体 の 定 義 s t r u c t F U N C { int Func_size; SpdObjld tfunc_idi };

struct FUNC Func; 構 造 体 の 初 期 化 f u n c . f u n c _ 3 i Z e = 0 , f u n c . f u n c _ i d = N U L L i func_csr=spdCetlncludedOcclnit(funcDecl_id,"identiner",funcDecl_id); while((funC_。CC=8pdCetlncludedOcc(funC_CSr)).relationld!=SAPID_NON_ID) if(apdCetAttrVallnt(func_occ,objeCtld,"80rtり==ID_FUNCT10N)( 関 数 の 名 前 の 出 現 だ け 抜 き 出 す 。 f O r G = 0 ; j くf u n c . f u n c _ s i z e ; j + + ) i f ( f u n c . f u n c _ i d L i ] = = f u n c _ o c c . o b j e C t l d ) g o t o E X I T 2 , 構 造 体 を 配 列 の よ う に 使 う方 法 ( 注参 照 ) f u n c . f u n c _ i d = 8 P d R e a l l o c ( f u n C . f u I I c _ i d , s i z e o f ( S p d O b j l d ) " ( f u n c f u l l c _ s i Z e + 1 ) ) ; f u n c . f u n c _ i d 〔f u n C . f u n c _ s i z e l = f u n c _ O c c . o b j e c t l d i 結 果 の 出 力 p r i n t f ( " C a l l i n g F u n c t i o n N a m e % 。¥ n " , spdCetNaEIC(funC,func_id[func.func_size])); func.func_size++; E X I T 2 : ) } } 注 fu nc.func_id=(SpdObjld)malloc(sizeof(S,dObjld)t(func,func_size+1)): で も可

(9)

S a p l d に

よるソフトウエア解析技法Ⅱ 77

関数 getFuncCallは

,関 数の呼 び出 し数 を最大100として配列 を宣言 してお り,

対象 とするソフ トウエアの関数呼び出 し数が100を超 えると処理で きな くなる。

そのため,構 造体 を用いて,サ イズに対応するようプログラムを改良する。

2.関 数呼び出 しの複雑 さ

呼び出 される関数 も他の関数 を呼ぶ。その関数呼び出 し構造 をツリー として

表現 し,関 数呼び出 しの複雑 さの情報 を求める。関数の複雑 さは,関 数呼び出

しの総数,呼 び出 しの最大 ネス ト数 といった情報である。

各 関数 ご とに関数呼 び出 しの情報 を配列 (クラス optionalded)に

格納 し,再

帰的にgetFuncCallを

適用する。ただ し同 じ名前の関数が出現 した場合の無限ルー

プの可能性 もあ り,実 用的なソフ トウエアとするためには,こ れを考慮する必

要がある。

関数 getFuncCall(関

数の複雑さを求める)

func_idti]=func_occ.ObjeCtttd;

printf("Calling Functio■ NaIIle%di%s¥ュ ",i,spdGetName(func_idti])), オ☆キキヤ十 追 加 部 分 十☆十十☆キ オ プ シ ョ ナ ル 宣 言 オ ブ ジ ェ ク トー 覧 か ら 、 呼 び 出 した 関 数 と 同 じ も の を 選 ぶ f u n c _ a r r a y = 8 p d G e t O b j l d A r r a y ( " O p t i o I I a l d e c l " , N U L L , N U L L ) , f o r ( k = 0 ; k < f u n c _ a r r a y , s i z e ; k キ+ ) i f ( 8 P d G e t A t t r V a l l n t ( f u n c _ a r r a y . i d [ k ] , " 8 0 r t " ) = = D E C L _ F U N C D E F ) ( オ プ シ ョ ナ ル 宣 言 → 宣 言 子 → 名 前 と た ど る d e c r _ i d = s p d G e t A R e 1 0 b j ( f u n c _ a r r a y . i d 〔k l , " d e C l _ O p t " , " a I I y " ) ; i d e n t _ i d = 8 p d G e t A R e 1 0 b j ( d e c r _ i d , " d e c l _ i d e n t " , " a n y り, 関 数 と 同 じ 名 前 ( I D ) か ど う か を 判 断 i f ( f u n c . f u n c _ i d 【f u n c . f u n c _ s i z e ] = = i d e n t _ i d ) 再 帰 的 呼 び 出 し の 場 合 を 排 除 i f ( f u n c _ a r r a y o i d [ k 〕1 = f u n c D e c l _ i d ) ( 再 帰 的 に 関 数 呼 び 出 し情 報 を 出 力

plintf("The%S iS call the functioll¥n¥t",spdGetNane(ide nt_id)), getFuncCall(fu■lC_arrayid[k]);

printf(・%s func list end¥n″ ,spdGetName(ldent_id)); }

3.関 数の呼び出 し位置

関数の呼び出 し位置は,出 現 した関数名 mentinerか

ら,関 連 idenとref(名前一

式 :identiner一

expresslo■

)を求め, spdGetOttet関

数で,オ フセ ッ トを求める。

(10)

7 8 彦 根論叢 第 328号

終 的 にオ フセ ッ トを行 ,桁 数 に変換 して実際の位置 を求 め る必 要があ る。 これ

らの情報 はSapidのユ ーテ イリテ イSPIEに よ り取得 で きる。

関数 g e t F u n c C a l l ( 関

数の複雑 さを求める 続 き)

田 関 数の被呼び出 し

第 2章 では,あ る関数 における関数呼び出 し (call)に関す る様 々な情報 を

求めた。第 3章 では,関 数が他の関数で呼ばれる場合 (called)の情報 を求め

る。プログラム内における全 ての関数の中での出現 を調べ る必要があ り,関 数

(クラス optiondded)のオブジェク ト配列の中か ら当該関数の名前 (クラス :

週entiner属

性 i name)の occurrenceを

持 つ もの を選ぶ。同 じ関数が複数回出現

す る場合は重複 を取 り除 く。

アル ゴリズム

1.ク ラス optionaldedの

配列オブジェク トの取得

2.optionaldeclか

ら identinerの

名前が関数名 と等 しく属性 sortが関数であ

る ものを選ぶ

Sp dRel ide nt_rel;追 力田部 分 (宣 言 unc_idrI〕=func_。cc.ObjeCtld

/★者★★韓 追 加 普卜分 (手 順 nt_rel=spdGelARel(funC_id[I】 ,Wident_rer'

offset=spdGetOffset(ident_rel,relationld);

関 数 オ フ セ ッ ト値 ( グ ロ ー バ ル 変 数

ffse t=offset+func offee

p rintf("Calling Function Name%d:%g ofFset=¥ェ Ⅲ,i,spdGetName(func_idril),。 ffse

グローバル変数 を求める手順

e x t e m f u n c _ o f f s e t = 0 ; 追加 部 分 ( 宣言 ) int main(int argC,char targv[1)(

SpdRel ident_rel_func; 追力田部 分 (宣言 ) │ f u n c _ a r r a y = s p d G e t O b j l d A r r a y ( " d e c l a r a t i O n " , N U L L , N U L L ) , f O r ( 1 = 0 ; 1 く f u n c _ a r r a y . s i z e , 1 + + ) i f ( S p d C e t A t t r V a l l n t ( f u n c _ a r r a y . i d [ 1 1 , " 8 0 r t り= = D E C L _ F U N C D E F ) 減 ★キ去 追 加 部 分 十★球 ★/ ident_rel_func=spdGetARel(funC_array,id[1],"file_decl","anyⅢ); func_offset=spdGetOffset(ident_rel_func.relationld); │

(11)

S a p l d に

よるソフトウエア解析技法Ⅱ

3.当 該 関数 の identinerを

occurrenceとして持 つ もの を選 ぶ

4.新 規 の呼 び出 し元 関数 であ った場合 はエ ン トリ

ーす る

関数 getFuncCalled 関

数の被呼び出 し状況 を求める

IV 代 表的なソースコー ドメ トリックス

その他の ソースコ

ー ドのメ トリックス として,内 部変数 と変数の総数の比,

ループのネス ト数,Cyclomatic数といった情報 を求める。変数に関する情報は,

関数の ときと同 じく,ク ラス 組entinerを

用いて取得す る。プログラムの構造 に

関す る情報 はクラス b10Ckに

関す る情報 を利用す る。

1日 内部変数 に関するメ トリックス

変数の情報 は変数名,型 ,有 効範囲,出 現位置,含 まれる式 な どか らな

る。

変数名,型 は 1章 の関数のプログラムを改良 して求める。内部,外 部,静 的

いった変数の種類 はSapidの基本情報 (SDB)に は含 まれない。変数の宣言 を

予。

id print_Calling_FuncName(SpdObjld decl_id){

路嘉転岳

鑑驚

群盟

揺品掛

酷撤盤挽

it勁

}

void getFuncCalled(SpdObjld called_func_id)( SpdOcc func_occi SpdCursor tfunc_csr; 艶 : 8 群 緊 A r r t t e 柱 ] 品「景話3 孟」d , 血n c 」d t t A X _ F U N C _ S I Z E l ; d e c r _ i d = 8 p d G e t A R e 1 0 b j ( d e c l _ i d , W d e c l _ d e c l " , " a n y り, i d e n t _ i d = S p d G e t A R e 1 0 b j ( d e c r _ i d , Ⅲd e c l _ i d e n t Ⅲ, H a n y Ⅲ) ; f u n c _ a r r a y = S p d G e t O b j l d A r r a y ( Ⅲd e c l a r a t i o n " , N U L L , N U L L ) ;

fOr Kl毬

推部:部i絲路

艦総朝予

&鞘錯棋誉

縦認鮒)

w h i l e ( ( f u n C _ O C C = S p d G e t l n c l u d e d C

弧血nに

…的∝dd meぉωt」

if(func_array.id[1]1=Calle d_funl print_Calling_FuncName(func_array.id[1]); getFuncCalled(func_arrayid〔11), } } }

(12)

8 0 彦

根論叢 第 3 2 8 号

参照 して,宣 言 に関する情報 として調べ る。変数の有効範囲や変数 を含む式 を

取得するために, expression,blockを

といったクラスを参照する。

関数 getvarNum i変

数のメ トリックス情報を求める

2 , C y c i o m a t i c 数

プ ログ ラムの複雑 さを計 測す る指標 と して,ブ ロ ックの ネス トの数,ブ ロ ッ

クの数 な どを用 い る。Cyclomatic complexity数はThomas McCabeに

よ り

1 9 7 6 年に提案 された,プ ログラムの健全性 (soundness),信頼性 (confidence)

を計 測 す る指標 であ る。Cyclomatic complexity数

は,プ ログ ラム ・モ ジュー

ルの複雑 さを,有 向 グラフ と して表現 した ときの線形独 立 なパ スの合計 であ ら

わ され る。

① Cycbmadcの 複雑数

C C = E 一 N t t p

E = グ

ラ フのエ ッジ数

N = グ

ラフの ノー ド数

eine MAX VAR SIZE 100

void getVarNum(prOg_id){ SpdObjldArray id_array; SpdObjld file_id,decl_id,decr_id,gvar_idtMAX_VAR_SIZEli SpdCur80r ★ decl_c8r; int count=0,coun12=0,i,j,gvar_num=0; グ ロ ー バ ル 変 数 の リ ス ト ( 配列 ) を 求 め る 生le_id=spdGetARe10bj(prog→ id,"prog_■le","any巾); decl_car=spdGetRe10bjlnit(■ le_id,"nle_decl","any"); while((decl_id i spdCetRe10bj(decl_CSr))!=SAPID_NON_ID) 【deCr_id=8pdGetARe10bj(decl_id,Ⅲ decl_decl","any"); if(spdGetAttrVallnt(decl_id,Ⅲ 9ortⅢ)==DECL_VARIABLE) gvar_idigvar_num++]; } 変 数 の 出 現 を 求 め 、 ロ ー カ ル 、 グ ロ ー バ ル を 判 断 す る i d _ a r r a y = s p d G e t O b j l d A r r a y ( " i d e n t i f i e r " , N U L L , N U L L ) ; fOr(i=0;iく id_array,size;i++) if (spdGetAttrVallnt(id_array.id[i],・30rtⅢ)==ID_VARIABLE){ count++; forG=0;jく gvar_num;j++) if(id_arrayoid[i]==gVar_idB])【 count2++;goto EXIT, } EXIT: } p r i n ば( ⅢN u m b e r o f L o c a l V a r i a b l e s : % d L O c a l ′T o t a l : % ‐5 . 2 f % % ¥ n " , c o u n t , ( ■o a t ) ( C O u n t _ c o u n t 2 ) ±1 0 0 ′C O u n t ) ;

(13)

S a p i d に

よるソフ トウエア解析技法 Ⅱ 8 1

p = 要

素 数

② Cyclomadcの 複雑さの基準 (Thomas McCabeによる)

1-10

リス クの ない平坦 なプログラム

11-20

少 し複雑,危 険度小

21-50

複雑 ,危 険度大

50以上

非常 に危 険

3口 最大ネス トと各 ブロック

条件,繰 り返 しといつた制御文や,中 括弧 │,│で囲まれたブロックに関する

複雑 さの情報 を求め る。Sapidでは,ブ ロ ックの種類 を,内 部 にブロ ックを含

むhierachicalブ

ロックとbasicブロックに分ける。basicブロツクは内部にブロッ

クを含 まないブロックの最小単位である。

関数 geと

depthと

サンプルプログラム

│ ト ッ プ レ ベ ル の b 1 0 c k のI D を 求 め る

blk_id =spdGetARe10bj(opt_id,"func_body“,“any"); 関 数 の ネ ス ト の 深 さ を 求 め る

max_depth=get_depth(blk_id), │

get_depth(SpdObjld block,int depth) SpdObjld blk_id,block_id; SpdCursor オ blk_Csr;

extern int max;

if (spdGetAttrVallnt(bloCk,"eortり ==BLOCK_BASIC) return depth;

斌玉

8&試

!ぷ

1糾8灘

乱裕品

構&盟ふ

1巣ズ

3部

路。

NFD(

弧spdG:拾

:濫

::持

路諾だf∬礼孟母理鑑 8長

FORII

鍵襴難

鞘鞘垂

難撒且

cれ

) depth十 +; depth=get_depth(blk_id,depth); if(m aXく depth)

max=depth; }

(14)

8 2 彦 根論叢 第 328号

分岐 を含 むhierachicalブロックは,分 岐部分のbranchブ ロックと分岐以外

のブロ ックcOmpoundブ ロ ックに分け られる。branchブ ロックは分岐の種類

によってif文,while文 などに分 け られる。関数 geと

depthは,あ るブロックのネ

ス トの深 さを返す。再帰的に呼び出 され,呼 び出されたブロックIDと ,そ の

ブロ ックの トップ レベルか らのネス トの深 さをパ ラメータ (depth)に もつ。

関数 (クラス option』

ded)か ら,関 連 血nc―

paramをた ど リトップレベルのブ

ロ ックのIDを 求めて, get_depth関

数 にパ ラメー タとして渡す。各分岐ブロ ッ

クを調べ る ときの情報 を,適 当な構造体 を定義 し,格 納することで,ifゃ fOr

といったブロックごとの情報 を得 る。

V ソ ースコー ド ・メ トリックスの取得 と利用

メ トリックス情報 をCSVや XMLと いったデー タ形式で出力 し,情 報 を活用

す る方法 を考察す る。CSVデ ータ形式 はEXCELで 処理可能であ り,関 数 ごと

の各種のメ トリックスを集計 して,プ ログラム ・メ トリックスを取得 し,最 大,

最小,平 均,標 準偏差 といた統計的なデータ処理 を行い,メ トリックス関連の

資料 を作成する。

多 くのオープ ンソース ・ソフ トウエアに対 して同様の処理 を行い,デ ータを

集計 ・解析す ることも可能である。オープンソースをSapidアプリケーシ ョン

で利用す るため には,細 粒度 ソフ トウエ ア リポジ トリ ・データベースSDBが

必要であるが,本 論文では,オ ープンソースのSDBを アーカイブ し,イ ンター

ネ ッ ト上で提供 しているインターネ ッ トサイ トsappyを利用する。

1 . C S V デ ータの処理

4 章 までに求めたメ トリックスに,ソ ースコー ドの行数 (SLOC)と コメン

ト行数 (COM)と いった基本 メ トリックスを加 え集計 し,最 大,最 小,平 均,

標準偏差 を求める。図回は文末の参考資料 回のプログラムAladdiflこ

関す るメ

トリックスデータの解析結果である。

(15)

F I I I I I I I

S a p l d によるソフ トウエア解析技法 Ⅱ 8 3

①その他の指標

MVG i Cyclomatic数

Depth i関 数callッリーの最大パ ス

Fanin:関 数callの数 ,(v)関

数callの複雑 さ

Fanout i関 数calledの数,(v)関

数calledの複雑 さ

番 号 LOC MVG COMI LOC/COWI MVG/COM Depth FaninV Fanln FanoutV Fanout 途 中 省 略 0 9 0 0 1 1 2 1 0。069 5 1 1 422 0 9 0 0 0 0 合 計 28605 2937 6853 3290.2 492.591 10312 1874 4335 平 均 67.8 6.96 7.7967 1.16728 24.44 4.44 最 大 1170 最 小 3 0 0 0 0 0 0 0 偏 差 10.565 10.6954 24.2 82.87 28.9

図 田 EXCELに

よるデー タ処理結果

2 日 X M L デ ー タの処理

X M L は デー タ交換 の標 準 フ ォーマ ッ トで あ り,適 当 なス タイル シー トを用

いて,ブ ラウザ か ら参照す る こ ともで きる。サ ンプルプログラム 皿はCSVデ ー

タをX M L デ ー タに変換 す るプログラムであ る。

(16)

84 彦 根論叢 第 328号

サ ンプル プログラム 田 XMLデ

ー タ変換

キincludeくstdio.h> キdefine MaxTextSize 10000 m a i n O 【 F I L E t t f p , t f p l ; i n t l i n e = 0 , … 以 下 、 各 項 目 の 宣 言 c h a r f n a I I l e [ 1 0 0 】; char tmp[MaXTextSize],tmpl[2]; int c,ュ=0; 入 力 と 出 力 の フ ァ イ ル を 開 く f p = f o p e n ( " O u t p u t . d a t " , " r " ) ; fp l=fopen(・Outp ut.xlnl",Ⅲwり ;

X M L の バ ー ジ ョ ン や s ス タ イ ル シ ー トを指 定 す る

otrcpy(tmp,"<?Xml versiOn=¥"1.0¥"encOding=¥Ⅲ Shift_」IS¥"?> <?xmi‐stylesheet type=¥“text′x81¥Ⅲ href=¥"Outputl.xsl¥"?>

くIEletrics‐report>¥n"); fprintf(fp l,田%8",tmp), D T D の タ グ の 生 成 を 開 始 * while((c=fgetc(fp))!=EOF)【 strcpy(t】■P,"¥tくfunctiOn>¥nり ; fPrintf(fp l,"%8",tmp); etrcpy(tmp,"¥t¥tく name>り , sprintf(tmpl,"%c",(char)c)i s t r c a t ( t m p , t l n p l ) ; w h i l e ( ( c = f g e t c ( f p ) ) ! = ( i n t ) ' , り { S p r i n t f 〈t m p l , " % c Ⅲ, ( C h a r ) C ) ; 8trCat(tmp,tmpl); } fprintf(fp l,"%8く′name>¥n",tmp); 以 下 、 各 項 目 ご と に 、 タ グ を 生 成 す る 。 ・DTDの 定義は省略

出力結果 XMLデ

ー タ形式

〈?xmi verslon="1.0" encoding="Shift_JIS"?〉

く?xml―stylesheel lype="tex1/xsl" href=〕 Outpu↓1.xsl"?〉 く!DOCTYPE doc SYSTEM "filet//cl¥melrics.did"〉

くmetrics―report〉 くf ullc t i on〉 〈name〉1:Exiract_Eigenvector〈 /name〉 〈line〉28 く/1ine〉 〈MVG〉6 く/MVG〉 〈comment〉o〈 /comment〉 〈line_com〉0 く/1ine_c O lll〉 〈MVG_com〉0〈 /MVG_com〉 〈depth〉2〈/depth〉 〈FANIN〉5〈/FANIN〉 〈FANIN_visible〉5 く/FANIN_visible〉 くFANOUT〉1〈/FANOUT〉 くFANOUT_visible〉1 く/FANOUT_visible〉 〈/function〉

(17)

Sapidによるソフ トウエア解析技法 Ⅱ 85

お わ りに

Sapidのソフ トウエア解析技法の例題 として,ソ Tス コ

ー ド・メ トリックス

取得プログラムを詳細に解説 した。オ

ープンソースのソフトウエアに関するソー

スコー ド・メ トリックス情報を利用 して,ソ フ トウエアの品質解析の指標を開

発する手法を提案 し,オ ープンソ

ースの新たな利用方法を提起 した。

今後の課題 として, ドキュメントに関するメ トリックスを求める手法を考え

る。Sapidのドキュメント管理バージヨンDapidを利用 してコメン トや ドキュ

メント,仕 様書などを資源 として利用することが可能である。

[参考資料 I]SAPID関

数の名前 について

① SpdGetARe10晰 , SpdGetRelObilnit

SAPID関 数 取 得 関数 [一 つ取得]

参照 オブジエク ト

[カー ソル初期化]

Spd Get [A]

Re10tt ink

② spdGetlndudedOcclnit

SAPID関 数 取 得 関数 [一 つ取得 ]

Spd Get [A]

③ SpdGetObildArray:

SAPID関 数 取 得 関数

Spd Get

出現 を対象 [ カ

ー ソル初期化]

includedOcc init

オブジェク トI D 配列

O朗 ldArray

1 )

[参考資料 工]HTML形

式に出力 1 対 象プログラムmain l)

プログラムmttnは 「

Sapidによるソフ トウエア解析技法 I」 で用いた,30行

ほどの簡単なサ ンプルである。V章 までで求めた各種メ トリックスを,HTML

の表形式で出力する。

(18)

彦根論叢 第 328号

メ トリックス 1:(REB00TESPRITプ

ロジェク トよ り参照P

番 号 値 メ トリ ックス 要 素 基 準 Wi l Developing ドキュメントのベージ数/ソ ースコー ドの行数 理解性 ドキ ュ メ ンテ ー シ ョン M12 ドキュメントのアクセス可能性のチェックリスト理解性 ドキ ュメ ンテ ー シ ョン W13 コメン ト行/ソ ースコー ドの行数 理解性 自己記述性 M 4 モジュールの 自己記述性のチェックリス ト理解性 自己記述性 脱15 9.25 ソースコー ドの行数/モ ジュール数 可搬性 ・乗軟性モ ジュ ラ リテ イ lv1 6 Developing マシン依存コー ド行数/実 行部コー ドの行数 可搬性 環境独立性 lv1 7 Developing システム依存 コー ド行数/実 行部コー ド行数可搬 性 環境独立性

M 8 Fan―in,Fan―outの複雑さ (cyClomatic number)理解性 ・信頼性モジュラリテイー・要素複雑性

M 9 複雑 さ (cyclomadc number) 理解性 ・信頼性コー ド複雑性 M10 モジュールの 自己記述性のチェックリス ト柔軟性 汎用性 Mll 不良耐久性のチェックリス ト 信頼性 不良耐久性 M12 テス ト総数/検 出エラー数 M13 分離 された要求数/全 要求数 M14 データ無矛盾性チェックリス ト A/115 手続 き無矛盾性チェ ックリス ト い7116 0.135 複雑度/ソ ース コー ドの行数 理解性 ・信頼性要素複雑性 lv117 2 最大 ネス ト数 理解性 ・信頼性要素複雑性 巾118 5 内部変数の数/変 数の総数 卜7119 0.139 変数の総数/実 行部 コー ドの行数

[ 参考資料 田] H T M L 形

式 出力( 2 ) 対象 プログラムA l a d d i 辞

A l a d d i n は,linuxで利用 で きる行列処理 ソフ トウエ アであ る。Maryland大学

S y s t e m s R e s e a r c h ( U S A ) で

開発 され た オー プ ンソース で あ り,関 数 の数 が

4 2 2 個の 中規模 の プログラムであ る。 プログラム ・メ トリックス と関数 メ トリッ

クス につ い ての デー タをH T M L の 表形式 で出力す る。 メ トリックスの タグ記号

につ い て は,第 5章 を参照 の こ と。各 関数名 の リンク (参照)先 は,SPIEで 生

成 した情報 の ソース コー ド部分 (当該 関数 の先頭行 )で あ る。

(19)

S a p i d によるソフ トウエア解析技法 工 8 7

3 )

メ ト リ ックス 2 :Procedual Mに

trics

MIetric Tag Overall Per Function Line of Source Code SLOC 6149 14.6 M5 Cyclomatic number

l Number of if statement 2 Nuttber of for statement 3 Nuttber of while statement 4 Nuttber of switch statement 5 Nuttber of do statement 6 Nuttber of pain statement WIax Block Depth

MVG N if N―for N―while N―switch N―do N―plain W I B D 2.94e十 o3悦 19 1473 1240 23 200 1 0 18酌 117 6.96 3.49 2.94 0.0545 0.474 0.00237 0 N/A Fanin Fanout Fin Fout MIax Depth 5444 3921 13 M M 1 2 . 9 9 。2 9 N/A Lines of comment 30M 1 . 9 1 SLOC/COM L C 7.61958M13

N/A

MVG/COMI M C 3.63941 M116

N/A

Functions

Fuction Name MVG COM L C M C FUN IN FUN OUT ]IO(VI

1:Extract_Eigenvector matrix.i:6121 0 0 0 2 10(V=5) 1(V=1) 7.11 2:Extract_Eigenvalue matrix.i:6092 4 0 0 2 10(V=5) 1(V=1) 7.11 3:Solve_Eigen matrix.i:5994 1 1 4 2.75 2 460(V=30) 1(V=1) 21.2 4:帥latrixSolveEigen matrix.i:5845 1 1 0.73 3 403(V=29) 2(V=1) 20.5 5:A/1atrixPut matrix.1:5737 3 16(V=8) 1(V=1) 11.3 5,7 途 中省略 7∼417 416:dktq06 elIIlt_shell_4n_q.1:6812 1 0.032 1 0(V=0) 18(V=2) 12.7 417:dktb06 elmt_shell_4n_q.16710 0.032 1 56(V=28) 16(V=1) 41.2 418:elmt_shell_4nodes_q elrnt_shell_4n_q.15915 789 1.06 0.117 5 212(V=106) 15(V=15) 75.7 419:Lalnina_Sys ellnt_larnina_systi:5773 1.05 0.030 2 50(V=25) 0(V=0) 17.7 420:sld02 elIIlt fiber.i:5776 1 . 1 1 0 0 2(V=1) 15(V=15) 42■SetUpFiberRespondBuff ellnt fiber.15744 2 1.03 0.069 2 10(V=5) 1(V=1) 7.11 422:ellnt ttber ellnt fiber.15724 1 . 1 1 0 0 0(V=0) 15(V=15)

(20)

88 彦

根論叢 第 328号

[参照文献 ・ホームベ ージ]

1)斎 藤邦彦 (2000)「Sapidによるソフ トウエア解析技法 I」 (彦根論叢第325号)p126

2)日 科技連編 (1994)21世紀への ソフ トウエ ア品質管理技術 (日 科技追出版社)p306

3)http://w―

.isr.umd.edu/∼ austin/aladdin,html

[参考文献]

(1)山 本 晋一郎,阿 車 清滋 (1995)「

細粒度 リポジ トリに基づいたッール ・プラッ トフォー

ム とその応用」 情報処理学会 ソフ トウェアエ学研究会,Vol.102,No.7,pp.37-42

(2)大 橋 洋貴,山 本 晋一郎,阿 草 清滋 (1999)「ソフ トウェア空間を トラバースする柔軟

な検索」 日本 ソフ トウェア科学会第16回大会論文集,pp.149-152

(3)斎 藤 邦 彦 (1999)「ソフ トウエ アエ学 ツールプラッ トフォームSapid」彦根論叢第310号

pp.183-199

(4)カ ーニハ ン,リ ッチー (1983)「プログラム ング言語C」 共立出版株式会社

図 I 卜 mOdel定 義 関 数mttn.c

参照

関連したドキュメント

そのため本研究では,数理的解析手法の一つである サポートベクタマシン 2) (Support Vector

そこで本解説では,X線CT画像から患者別に骨の有限 要素モデルを作成することが可能な,画像処理と力学解析 の統合ソフトウェアである

名の下に、アプリオリとアポステリオリの対を分析性と綜合性の対に解消しようとする論理実証主義の  

ベクトル計算と解析幾何 移動,移動の加法 移動と実数との乗法 ベクトル空間の概念 平面における基底と座標系

振動流中および一様 流中に没水 した小口径の直立 円柱周辺の3次 元流体場 に関する数値解析 を行った.円 柱高 さの違いに よる流況および底面せん断力

解析の教科書にある Lagrange の未定乗数法の証明では,

はじめに ~作成の目的・経緯~

しかし , 特性関数 を使った証明には複素解析や Fourier 解析の知識が多少必要となってくるため , ここではより初等的な道 具のみで証明を実行できる Stein の方法