メインコンテンツ

-regex-replace-rgx -regex-replace-fmt

プリプロセッサ命令での置換の実行

構文

-regex-replace-rgx matchFile -regex-replace-fmt replacementFile

説明

-regex-replace-rgx matchFile -regex-replace-fmt replacementFile は、Polyspace® 解析のためにプリプロセッサ命令のトークンを置き換えます。元のソース コードは変更されません。ファイル matchFile で正規表現を使用してトークンを照合し、ファイル replacementFile. で置換を使用してトークンを置き換えます。

このオプションは、"前処理の前" にプリプロセッサ命令のトークンを置換または削除する場合にのみ使用します。通常、ソース コードのトークンでコンパイル エラーが発生する場合は、より便利なオプション [前処理済みファイルに適用するコマンド/スクリプト] (-post-preprocessing-command) を使用して、前処理済みのコードのトークンを置き換えるか削除することができます。ただし、プリプロセッサ命令のトークンを置き換える場合は、このオプションを使用することはできません。その場合は -regex-replace-rgx -regex-replace-fmt を使用します。

このオプションで利用できる正規表現の完全なリストは、Perl のドキュメンテーションを参照してください。次の点に注意してください。

  • Perl では、構文 s/pattern/replacement/modifier を置換に使用できます。このオプションを使用するときには、この構文を部分的にのみエミュレートします。照合するパターン pattern を 1 つのファイルに指定し、その置換内容 replacement を別のファイルに指定します。検索修飾子 (Perl 構文の modifier の値) はサポートされていません。たとえばこのオプションでは、既定ではグローバル置換 (一致するトークンが検出されると常に置換) が実行され、一致では大文字と小文字が区別されます。検索修飾子を使用してこれらの既定の設定を変更することはできません。

  • このオプションでは、番号付きキャプチャ グループと名前付きキャプチャ グループの両方がサポートされています。キャプチャ グループは照合ファイルで定義できます。このためには、キャプチャ グループを小かっこで囲み、$1$2 などを使用して置換ファイルのキャプチャ グループを参照します。あるいは、キャプチャ グループに名前を付けて、グループを名前で参照することもできます。例は、キャプチャ グループを使用して複数のプリプロセッサ命令を異なる置換内容に置き換えるを参照してください。

ユーザー インターフェイス (Polyspace デスクトップ製品のみ) では、[構成] ペインの [その他] フィールドにこのオプションを入力します。Otherを参照してください。

ユーザー インターフェイスで、検索と置換のパターンを含むテキスト ファイルへの絶対パスを指定します。

プリプロセッサ命令の未定義シンボルをよりシンプルな代替シンボルに置換する

次の #define 命令を変更するとします。

#define ROM_BEG_ADDR (uint16_t)(&_rom_beg)
次に変更します。
#define ROM_BEG_ADDR (0x4000u)
置換の理由としては、Polyspace に提供されたコードで _rom_beg が未定義であり、コンパイルの問題が発生することなどがあります。トークン (uint16_t)(&_rom_beg) はアドレスを示しており、Polyspace 解析では正確なアドレスが追跡されないので、(uint16_t)(&_rom_beg) をシンプルなアドレス ((0x4000u) など) に置き換えることができます。もう少し複雑なケースを考えるため、#defineROM_BEG_ADDR の後に 1 つ以上の空白文字を使用できるようにするとします。

この置換を行うには、次のようにします。

  1. ファイル match.txt で正規表現を指定します。

    ^#define\s+ROM_BEG_ADDR\s+\(uint16_t\)\(\&_rom_beg\)
    正規表現では以下の要素が使用されます。

    • ^ は、行の先頭の位置をアサートします。

    • \s+ は、1 文字以上の空白文字を表します。

    文字 *&、(、および ) を \ でエスケープします。

  2. ファイル replace.txt で置換を指定します。

    #define ROM_BEG_ADDR \(0x4000u\)
    
  3. オプション -regex-replace-rgx および -regex-replace-fmt を使用して、解析時に 2 つのテキスト ファイルを指定します。

    • Polyspace Bug Finder™:

      polyspace-bug-finder -sources fileName -regex-replace-rgx match.txt -regex-replace-fmt replace.txt
    • Polyspace Code Prover™:

      polyspace-code-prover -sources fileName -regex-replace-rgx match.txt -regex-replace-fmt replace.txt
    • Polyspace Bug Finder Server™:

      polyspace-bug-finder-server -sources fileName -regex-replace-rgx match.txt -regex-replace-fmt replace.txt
    • Polyspace Code Prover Server:

      polyspace-code-prover-server -sources fileName -regex-replace-rgx match.txt -regex-replace-fmt replace.txt

キャプチャ グループを使用して複数のプリプロセッサ命令を異なる置換内容に置き換える

以下のコードは、2 つのマクロ bypass_UInt16_bypass_UInt32_ を定義しています。いずれのマクロにも、未定義のシンボル (UInt16_DO_NOT_EXIST) と (UInt32_DO_NOT_EXIST) が含まれています。

typedef unsigned short UInt16;
typedef signed short Int16;

typedef unsigned int UInt32;
typedef signed int Int32;

UInt16 x16;
Int16 y16, z16;

UInt32 x32;
Int32 y32, z32;

#define bypass_UInt16_(_var, _value, _add) _var = _value +/*CTO*/(UInt16_DOES_NOT_EXIST) _add
#define bypass_UInt32_(_var, _value, _add) _var = _value +/*CTO*/(UInt32_DOES_NOT_EXIST) _add

void main(void){
    bypass_UInt16_(x16, y16, z16); 
    bypass_UInt32_(x32, y32, z32);   
}

これらの未定義シンボルはいずれもコメント /*CTO*/ の後に配置されています。シンボルが未定義であるため、コンパイル エラーが発生します。マクロ定義を変更して、未定義のシンボルがコメントの後ではなく、コメント内に配置されるようにするとします。両方の定義に対して類似する変更を行うものの、両方の未定義のシンボルを同じ内容に置き換えることはしない場合は、キャプチャ グループを使用してシンボル名を変更せずに維持することができます。

この置換を行うには、次のようにします。

  1. match.txt という名前のファイルで、次の正規表現を指定します。

    \/\* CTO \*\/([^\)]*\))
    正規表現では以下の要素が使用されます。

    • シーケンス \/\*CTO\*\/ はコメント /*CTO*/" に一致します。一致シーケンスに含まれる文字 */ は、バックスラッシュ文字 \ でエスケープされています。

    • 小かっこで囲まれたシーケンス ([^\)]*\)) は、キャプチャ グループに対応します。各要素の意味は次のとおりです。

      • [^\)]* は、閉じ小かっこを除く任意の文字に一致します。

      • 2 番目のエスケープされた小かっこ \) は、一致させる正規表現の閉じかっこに一致します。

      まとめると、このキャプチャ グループは、/*CTO*/ コメントの後にある、閉じ小かっこ以外の任意の文字と一致し、閉じかっこで停止します。

      このキャプチャ グループは、未定義のシンボル (UInt16_DO_NOT_EXIST)(UInt32_DO_NOT_EXIST) の両方をキャプチャできます。

  2. replace.txt という名前のファイルで、この置換テキストを指定します。

    /*CTO $1*/

    $1 は、以前にキャプチャされたグループを表します。この置換により、コメントを閉じる */ の前にキャプチャ グループが配置されます。

    あるいは、名前付きキャプチャ グループを作成して、置換ファイルでこのグループの名前で参照することもできます。たとえば、次の正規表現では名前付きキャプチャ グループ cto_group が作成されます。

    \/\* CTO \*\/(?<cto_group>[^/)]*\))
    置換ファイルで名前付きキャプチャ グループを指定するには、次のように入力します。
    /* CTO $+{cto_group} */
    キャプチャ グループの名前が $+{ } に含まれています。

  3. 前の例に示されているオプション -regex-replace-rgx および -regex-replace-fmt を使用して、解析時に 2 つのテキスト ファイルを指定します。

解析結果に次のコードが表示され、未定義シンボルがコメントの中に配置されていることがわかります。

typedef unsigned short UInt16;
typedef signed short Int16;

typedef unsigned int UInt32;
typedef signed int Int32;

UInt16 x16;
Int16 y16, z16;

UInt32 x32;
Int32 y32, z32;

#define bypass_UInt16_(_var, _value, _add) _var = _value + /* CTO  (UInt16_DO_NOT_EXIST) */ _add
#define bypass_UInt32_(_var, _value, _add) _var = _value + /* CTO  (UInt32_DO_NOT_EXIST) */ _add

void main(void){
    bypass_UInt16_(x16, y16, z16);
    bypass_UInt32_(x32, y32, z32);
}

ヒント

  • IDE で Polyspace as You Code の拡張機能を使用する場合は、このオプションを解析オプション ファイルに入力します。Polyspace 解析のオプション ファイルを参照してください。

  • Polyspace の正規表現エンジンでは、ドット . 文字はラインフィード文字を含むすべての文字に一致すると解釈します。正規表現でラインフィード文字をキャプチャしない場合は、正規表現でドット文字以外のトークンを指定してください。たとえば、ラインフィード文字以外のすべての文字に一致させるには、正規表現 [^\n] を使用します。

  • 複数の種類のプリプロセッサ命令で置換を行うには、照合ファイルで 1 行ごとに 1 つの正規表現を入力し、置換ファイルの対応する行にその置換内容を入力します。照合ファイル内の正規表現と一致するプリプロセッサ行のそれぞれが、置換ファイル内の対応する置換内容で置き換えられます。すべての照合内容と置換内容を | で区切って 1 行に入力することもできます。ただし、1 行ごとに 1 つのエントリを入力したほうがファイルが読みやすくなります。

    たとえば、照合ファイルには次のように 2 つの正規表現を含めることができます。

    ^#define\s+ROM_BEG_ADDR\s+\(uint16_t\)\(\&_rom_beg\)
    ^#define\s+ROM_END_ADDR\s+\(uint16_t\)\(\&_rom_end\)
    置換ファイルには、次の 2 つの置換内容を含めることができます。
    #define ROM_BEG_ADDR \(0x4000u\)
    #define ROM_END_ADDR \(0x8000u\)
    これらの照合と置換を以下のソース コードに適用するとします。
    #include <stdint.h>
    
    #define ROM_BEG_ADDR (uint16_t)(&_rom_beg)
    #define ROM_END_ADDR (uint16_t)(&_rom_end)
    
    
    void main() {
        uint16_t beg_addr = ROM_BEG_ADDR;
        uint16_t end_addr = ROM_END_ADDR;
    }
    上記のコードは解析前に次の前処理済みコードに変換されます。
    #include <stdint.h>
    
    #define ROM_BEG_ADDR (0x4000u)
    #define ROM_END_ADDR (0x8000u)
    
    
    void main() {
        uint16_t beg_addr = ROM_BEG_ADDR;
        uint16_t end_addr = ROM_END_ADDR;
    }