快適なC++生活のためにスクリプト言語を使おう


 開発ターゲットの言語がC++だからといって、それ以外の言語を使わない手はない。いまC++で書いているソースコードの健全性をチェックするために、スクリプト言語を使ってチェックすることができる。

 既存のコードを試行錯誤で改造していると、いつの間にか変なコードになっていることがある。ある一式のプログラムに、別のプログラムを切り貼りして機能を強化したようなときに、妙な状況に陥っている可能性がある。

・ヘッダファイルに定義されているのだが、目的のプログラムの範囲では使われていないマクロ定数、マクロ関数が放置されている。
・使われていないextern宣言
・同一名のマクロ定義の存在

 「まずは動かすことが先だ」で書いたコードを十分に見直さないままになっていると、このような変なコードになってしまっている。コードの行数が少なければ
grep '#define' *.h *.cpp
とかでも何とかなるだろうけれども、
プログラムの全体の行数が増えて、しかもマクロが不幸にも多く含まれているという状況では、grep以上のツールがほしくなる。

マクロは
#define DATA_SIZE  (1000)
#define square(x) ((x) * (x))

などのようにスペースやタブで区切られて記述されており、
最初のフィールドは"#define"であるという規則がある。
このことを利用して、次のようなツールを作ると上記の健全性のチェックツールを作ることができる。

・#defineが含まれている行で、スペース・タブ区切りテキストとしてフィールドに分割する。
・最初のフィールドが"#define"に一致しているときに、次のフィールドをキーワードとして辞書を作る。辞書の値としては、出現箇所のソースコードのファイル名のリストとする。
・そうして一連のソースコードを処理したあとに、辞書の値に複数のソースコードのファイル名が含まれていたら、それを表示する。

そんなツールが、スクリプト言語では簡単に書ける。
スクリプト言語を使って快適なC++生活をしよう。

おまけ:ヘッダファイルでのマクロの重複を見つけるスクリプト

参考のスクリプトを書いてみました。

doubledMacro.py
# -*- coding: utf-8 -*-
#pylint: disable=C0103
import os

u"""
ヘッダファイルでのマクロの重複を見つけるスクリプト
"""

def findDoubledMacro(wdir):
    d = {}
    for root, dirs, files in os.walk(wdir):
        files = [p for p in files if os.path.splitext(p)[1] in ('.h', '.hpp')]
        for p in files:
            fullname = os.path.join(root, p)
            for line in open(fullname, "rt"):
                oline=line.replace("(", " ")
                oline=oline.replace(")", " ")
                oline=oline.replace(",", " ")

                f = oline.strip().split()
                if len(f) >= 2 and f[0] == "#define":
                    if not d.has_key(f[1]):
                        d[f[1]] = []
                    d[f[1]].append(p)

    for k in d.keys():
        if len(d[k]) > 1:
            print k, d[k]

if __name__ == "__main__":
    wdir = "."
    findDoubledMacro(wdir)

実行結果の例

max ['sourceA.h', 'sourceB.h']
_UNICODE ['sourceB.h', 'sourceC.h']
DATA_SIZE ['sourceA.h', 'sourceB.h']

実行結果に使用した入力データ

sourceA.h
#ifndef SOURCEB_H
#define SOURCEB_H

#define DATA_SIZE (100)
#define _UNICODE
#define DEBUG_VIEW
#define max(x,y)  ((x) > (y) ? (x) : (y))
#endif
sourceB.h
#ifndef SOURCEB_H
#define SOURCEB_H

#define DATA_SIZE (100)
#define _UNICODE
#define DEBUG_VIEW
#define max(x,y)  ((x) > (y) ? (x) : (y))
#endif
subDir/sourceC.h
#ifndef SOURCEC_H
#define SOURCEC_H

#define DATA_SIZEC (100)
#define _UNICODE
#define DEBUG_VIEW2
#endif

追記:

快適なC++生活のためにスクリプト言語を使おう2 C++のソースを自動生成させる

快適なC++生活のためにスクリプト言語を使おう3 ーグラフ作成はmatplotlibにまかせようー

快適なC++生活のためにスクリプト言語を使おう4 - C++の自作ライブラリをスクリプト言語から使おう -

快適なC++生活のためにスクリプト言語を使おう5 - 数値データの確認にはSpyder統合環境を使おう -