
概要
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を使えば本格的なプログラム解析まで簡単に可能です。 システムエンジニアの手作業に依存せず、エンジニアよりも安く、早く、正確に作業が可能です。ぜひお試しください。