概要
C#プログラムの可視化
§4
ビジネステクノロジー活用講座
■C#のソースコードを可視化/一覧化する
COBOLやPL/Iなどのレガシーコードの可視化はよく目にしますが、時代の先端を行くJavaやC#、実はこれらのオブジェクト指向言語で
書かれたシステム/プログラムもソースの可読性という点からみると、レガシーコードより読みにくいのが現実です。
実はこれらのプログラムはリバース、解析するにしても、レガシーコードやVBAなどより厄介です。
"function"や"sub"のような単純キーワードだけでは解析できません。プログラミングの文法に従って、ソースコードを解析していく必要があります。
とはいえ、C#の全ソースコードをExcelシート上に集めて解析したい場合が往々にあります。
ここではそのC#のプログラム解析を行うプログラムの一部を紹介します。
☆解析用の全ソースが必要な方は別途お問い合わせください☆
解析し、Excelシート上に取り込んだC#ソース一覧
Excelに取り込んで文法に従って解析し、クラス一覧を作成
詳細解析を行い、メソッド一覧を作成
ソースステートメントを解析し、メソッド呼び出し部分を抽出したメソッド呼出し一覧
メソッド呼出し一覧から呼び出しネスト図を作成
【C#プログラムの可視化プログラム・ソース(抜粋)】
'基本解析
Private Sub prog0()
Dim FN As String
Dim FNP As String
Dim FNL As String
Dim FNLV As Variant
Dim buff, buffx As String
Dim eofflg, comflg As Integer
Dim outcode, outcom As Long
Dim lmax As Long
Dim x, x1 As String
Dim stmtno, stmtno0 As Long
Dim linepos As Long
Dim colpos As Long
Dim org As Long
Dim idx1 As Long
Dim Seq_No As Long '全体通し番号
Dim LT1, LT2, KA1 As Long 'リテラルや()の出現回数
org = 1
'クリアー
Worksheets("ORG").Cells.ClearContents
Worksheets("コード").Cells.ClearContents
Worksheets("コメント").Cells.ClearContents
Seq_No = 0
'ファイルを読み込むための配列
Dim Arr()
'ReDim Preserve Arr(0)
Dim ftxtobj As Object
'ファイル共通初期化
outcode = 1
outcom = 1
'GET FOLDER NAME
'FNP = GetFoldername("C:")
FNP = GetFoldername("")
'Get File Name List
FNL = getFileList(FNP)
'List分解
FNLV = Split(FNL, ",")
'DO FOR ALL FILES
idx1 = 0
Do While idx1 <= UBound(FNLV)
'select source file
FN = FNLV(idx1)
GoSub fileproc
idx1 = idx1 + 1
Loop
'Make Namespace ID
GoSub namespacecnt
MsgBox ("基本解析終了")
Exit Sub
'ファイル単位の処理
fileproc:
'入力ファイルのOpen
GoSub fn00
buff = ""
eofflg = 0
linepos = 0
comflg = 0
stmtno = 0
stmtno0 = 0
'出現回数カウンタ=0
LT1 = 0
LT2 = 0
KA1 = 0
l00:
'Buffが空ならば次を読む
If buff = "" Then
If eofflg = 1 Then
'EOFFLGならば終了
GoTo l99
Else
'1行読み取り(Buff,LinePos)、有効文字までスキップ(ColPos)
If ftxtobj.EOS Then
eofflg = 1
buff = ""
linepos = linepos + 1
Else
'read
buff = ftxtobj.ReadText(-2) 'adReadLine
stmtno = stmtno + 1 '現在行
stmtno0 = stmtno '開始行
Worksheets("ORG").Cells(org, 1) = buff
org = org + 1
buff = LTrim(buff)
buff = Replace(buff, Chr(9), " ")
DoEvents
colpos = 1
End If
End If
End If
'if コメントの開始(/*)ならばコメント開始
If Left(buff, 2) = "/*" Then
comflg = 1
End If
If comflg = 1 Then
'if コメント中ならば
'コメントの終了*/または改行までを1ステートメントとして出力
lmax = Len(buff)
Do Until colpos > lmax
If Mid(buff, colpos, 2) = "*/" Then
comflg = 0
outcom = outcom + 1
Worksheets("コメント").Cells(outcom, 1) = stmtno0
Worksheets("コメント").Cells(outcom, 4) = Left(buff, colpos + 1)
Worksheets("コメント").Cells(outcom, 5) = FN
Worksheets("コメント").Cells(outcom, 6) = Seq_No
buff = Mid(buff, colpos + 2, 10000)
GoTo l00
End If
colpos = colpos + 1
Loop
'行終わりまで
outcom = outcom + 1
Worksheets("コメント").Cells(outcom, 1) = stmtno0
Worksheets("コメント").Cells(outcom, 4) = Left(buff, 10000)
Worksheets("コメント").Cells(outcom, 5) = FN
Worksheets("コメント").Cells(outcom, 6) = Seq_No
buff = ""
GoTo l00
End If
'if コメント行開始(//)
If Left(buff, 2) = "//" Then
outcom = outcom + 1
Worksheets("コメント").Cells(outcom, 1) = stmtno0
Worksheets("コメント").Cells(outcom, 4) = Left(buff, 10000)
Worksheets("コメント").Cells(outcom, 5) = FN
Worksheets("コメント").Cells(outcom, 6) = Seq_No
buff = ""
GoTo l00
End If
'STMT文字の処理
'終了位置デリミターを見つける({,},;,EOF,//,/*)(LineDel,ColDel)
'ただし、"'のリテラルや()の中は除く
lmax = Len(buff)
Do Until colpos > lmax
x = Mid(buff, colpos, 1)
x1 = Mid(buff, colpos, 2)
If LT1 > 0 Or LT2 > 0 Then
If LT1 > 0 And x1 <> "''" And x = "'" Then
LT1 = LT1 - 1
End If
If LT2 > 0 And x1 <> """""" And x = """" Then
LT2 = LT2 - 1
End If
Else
If x = "'" Then
LT1 = LT1 + 1
GoTo skp01
Else
If x = """" Then
LT2 = LT2 + 1
GoTo skp01
End If
End If
If x = ")" Then
KA1 = KA1 - 1
If KA1 < 0 Then
KA1 = 0
MsgBox ("()の数不正 " & CStr(Seq_No))
End If
Else
If x = "(" Then
KA1 = KA1 + 1
End If
End If
If (x = "{" And KA1 = 0) Or (x = "}" And KA1 = 0) Or (x = ";" And KA1 = 0) Or x1 = "//" Or x = "/*" Or eofflg = 1 Then
'コード出力
If Trim(Left(buff, colpos - 1)) <> "" Then
outcode = outcode + 1
Seq_No = Seq_No + 1
Worksheets("コード").Cells(outcode, 1) = stmtno0
Worksheets("コード").Cells(outcode, 3) = "C"
Worksheets("コード").Cells(outcode, 4) = TrimAll(Left(buff, colpos - 1))
Worksheets("コード").Cells(outcode, 7) = FN
Worksheets("コード").Cells(outcode, 20) = Seq_No
End If
'デリミタ出力
If x1 = "//" Or x = "/*" Or eofflg = 1 Then
'出力しない
Else
outcode = outcode + 1
Seq_No = Seq_No + 1
Worksheets("コード").Cells(outcode, 1) = stmtno
Worksheets("コード").Cells(outcode, 3) = "D"
Worksheets("コード").Cells(outcode, 4) = TrimAll(x)
Worksheets("コード").Cells(outcode, 7) = FN
Worksheets("コード").Cells(outcode, 20) = Seq_No
End If
'残りをセット
If x1 = "//" Or x = "/*" Then
buff = LTrim(Mid(buff, colpos, 10000))
Else
buff = LTrim(Mid(buff, colpos + 1, 10000))
End If
colpos = 1
'出現回数カウンタ=0
LT1 = 0
LT2 = 0
KA1 = 0
GoTo l00
End If
End If
skp01:
colpos = colpos + 1
Loop
'行終わりまでなし、継続
If eofflg = 1 Then GoTo l99 'すでになら終了
If ftxtobj.EOS Then
eofflg = 1
Else
'read
buffx = ftxtobj.ReadText(-2) 'adReadLine
Worksheets("ORG").Cells(org, 1) = buffx
org = org + 1
If buff = "" Then
stmtno = stmtno + 1
stmtno0 = stmtno
Else
stmtno = stmtno + 1
End If
buff = buff & " " & buffx
buff = Replace(buff, Chr(9), " ")
DoEvents
End If
GoTo l00
l99:
outcode = outcode + 1
Seq_No = Seq_No + 1
Worksheets("コード").Cells(outcode, 1) = "99999999"
Worksheets("コード").Cells(outcode, 3) = "D"
Worksheets("コード").Cells(outcode, 4) = "[EOF]"
Worksheets("コード").Cells(outcode, 7) = FN
Worksheets("コード").Cells(outcode, 20) = Seq_No
GoSub fn99 'ファイルのクローズ
Return
'ファイルのオープン
fn00:
'ファイルオープンと取得
'オブジェクトを作成
Set ftxtobj = CreateObject("ADODB.Stream")
'オブジェクトに保存するデータの種類を文字列型に指定する
ftxtobj.Type = 2 'adTypeText
'文字コードを取得し、設定する
ftxtobj.Charset = GetEncodeType(FNP & "\" & FN)
'オブジェクトのインスタンスを作成
ftxtobj.Open
'ファイルからデータを読み込む
ftxtobj.LoadFromFile (FNP & "\" & FN)
Return
'ファイルのクローズ
fn99:
'オブジェクトを閉じる
ftxtobj.Close
'メモリからオブジェクトを削除する
Set ftxtobj = Nothing
Return
'名前空間、変数領域IDの設定
namespacecnt:
Dim sid As String
Dim scope1, scope2(100) As Integer
Dim i, idx As Long
scope1 = 0
For i = 1 To 100
scope2(i) = 0
Next i
idx = 2
sid = "コード"
Do Until Worksheets(sid).Cells(idx, 1) = ""
If Worksheets(sid).Cells(idx, 3) = "D" Then
If Worksheets(sid).Cells(idx, 4) = "{" Then
scope1 = scope1 + 1
If scope1 > 98 Then
MsgBox ("Scope level exceeds 98 ")
Exit Sub
End If
scope2(scope1) = scope2(scope1) + 1
GoSub setlvl
Else
If Worksheets(sid).Cells(idx, 4) = "}" Then
GoSub setlvl
scope1 = scope1 - 1
'強制アジャスト
If scope1 < 0 Then
scope1 = 0
End If
'
For i = scope1 + 2 To 100
scope2(i) = 0
Next i
Else
GoSub setlvl
End If
End If
Else
GoSub setlvl
End If
idx = idx + 1
Loop
Return
setlvl:
If Worksheets(sid).Cells(idx, 4) = "[EOF]" Then
'強制リセット
scope1 = 0
For i = 1 To 100
scope2(i) = 0
Next i
End If
Return
End Sub
Excelシートに取り込めば、あとはExcelの検索やフィルタ機能、さらにはVBAを使えば本格的なプログラム解析まで簡単に可能です。 システムエンジニアの手作業に依存せず、エンジニアよりも安く、早く、正確に作業が可能です。ぜひお試しください。