| # プリプロセッサを使用するには 3GL プログラムスクリプト用のコンパイラ bic6.2 には、次の機能を備えた組込みプリプロセッサが搭載されています。 インクルードファイル マクロの定義 1 可変マクロ引数 2 トークン貼付 オブジェクトへの ID の設定 プラグマコード 条件付きコンパイル すべてのプリプロセッサ指示語は # で始まります。プリプロセッサ指示語はソースラインの先頭でなければなりません。また、スペースまたはタブが先行する可能性があります。 1. インクルードファイル インクルードファイルには次の文を使用します: #include ファイル名、または #include <ファイル名> < > で囲まれたファイルは、$BSE/include<rel.number> ディレクトリで検索されます。このディレクトリはシステムヘッダ用に予約されており、アプリケーションは使用することができません。 通常、引用符で囲まれたファイル名は、標準ファイルリダイレクション方式を使用して検索されます。$BSE/lib/fd.6.2.<パッケージコンビネーション> で次のような入力がされたとします。 `ippmmm:/usr/bse/standard6.2` 次のようなインクルード文があるとします。 #include ippmmmheader ファイル /usr/bse/standard6.2/ippmmm/immmheader0 はインクルードされます。 ファイル名に / が使用されている場合は、ファイルは特定パス名を使用して検索されます。 ファイルが 2 度インクルードされると、2 番目のインクルードは無視されます。 プリプロセッサは 3GL ソースのコンパイル時にのみ機能します。これは、標準ジェネレータ std_gen6.2 にはプリプロセッサパスがないためです。したがって、4GL イベントはインクルードファイルでは使用できません。 2. マクロ定義 マクロを定義するには、次のステートメントを使用することができます。 #define マクロ名[(引数)] マクロ定義 マクロ定義 マクロを未定義にするには、次のステートメントを使用することができます。 `#undef macroname[(引数)]` ソース中のマクロ名はマクロ定義に置換されます。マクロ定義が 1 つのラインに収まらない場合、次のラインの先頭にカレット記号 (^) を付けて定義を次のラインに続けることができます。マクロで引数を使用することができます。 例:
    #define a(x, y, z) for i = x to y
    ^ z()
    ^ and for | 定義
    a(1, 100, func) | 呼出
名前が同じで引数の数が異なるマクロ定義は、次の例のように、別のマクロ定義です。
    #define  x             引数なしの定義
    #define  x()           引数が 0 の定義
    #define  x(arg1)       引数 arg1 が 1 つある定義
    #define  x(arg1,arg2)  引数が 2 つある定義
    #define  x(...)        反復記号がある定義 (次を参照)
引数のない x のマクロと 0 引数を持つ x() のマクロとでは差異があります。マクロを呼び出すプログラムスクリプトで、前者の場合は x を使用し、後者の場合は x() を使用しなければなりません。 #undef ステートメントを使用するとマクロ定義は無視されます。#undef 呼出し内の引数の数と定義内の引数の数は一致しなければなりません。
     #define MAXLENGTH 1000
    #define INCR 1
    #define INCR(i) i=i+INCR
    .....
    #undef MAXLENGTH
    #define INCR 2 | INCR の再定義
    .....
    #undef INCR(i)
#undef を未知マクロに適用すると、エラーが発生します。次の構文を使用して、マクロが再定義されたことを確認します。
    #ifdef INCR | 引数なし
    #undef INCR(i)
    #endif | of #ifdef / #endif コール
詳細は、5. 条件付きコンパイルを参照してください。 2.1. 可変マクロ引数 マクロを定義するには、省略表記 ( , ... ) を使用してマクロに可変引数を追加することもできます。 例:
    #define fillbuf(buf1, format, ...) buf1 = sprintf$(format,...)
    | macro call string buffer(100) long l_val double d_val fillbuf(buffer,
    %d. %s = %d %5.2f, 1, Value, l_val, d_val)
マクロ定義にはいくつもの引数を含めることができますが、省略表記は最後の引数でなくてはなりません。この表記は、`sprintf()`、`message()`、および `mess()` 関数のように、省略表記を使用する関数にも使用できます。 2.2. トークン貼付 マクロに変数の一部をマクロ引数として入力することができます。マクロ引数と他のマクロとを区別するために ## 記号が使用されますが、マクロ呼出しでは削除されます。また、多くのマクロ引数を 1 つの識別子として一緒に貼り付けることができます。この方式をトークン貼付と呼びます。 例
    #define p(x) message("%d", var##x)
    #define q(x,y) message("%d", x##y)
    #define r(x,y,z) message("%d", x##y##z)

    long var1a, var1b

    p(1a) | message("%d", var1a) になります
    p(1b) | message("%d", var1b) になります
    q(var, 1a) | message("%d", var1a) になります
    q(var, 1b) | message("%d", var1b) になります
    r(var, 1, a) | message("%d", var1a) になります
    r(var, 1, b) | message("%d", var1b) になります
この方法は、関数の使用が不可能または困難な場合に、ソースコードの一部を再使用するために使用します。次の例も参照してください。 例
    #define VRC(table,v,r,c)
    ^ tt##table##.vers = v
    ^ tt##table##.rele = r
    ^ tt##table##.cust = c

    VRC(adv100, "6.2", "a", "")
    VRC(adv200, "6.2", "a", "")
    VRC(adv300, "6.2", "a", "")
オブジェクト ID オブジェクトに ID を設定するには、次のステートメントを使用します。 `#ident "@(#)Identification of object"` 例 `#ident "@(#)<progname>, YY/MM/DD [HH/MM], version, author"` デフォルトの ID は、次の内容でコンパイラによって常にオブジェクト内に置かれます。
     #ident "@(#)<ソース名>, YY/MM/DD, [HH/MM],
    From ${logname}"
UNIX の what コマンドは、標準出力では、「@(#)｣ で始まるすべてのオブジェクト行を書き出します。 プログラマはこのデフォルト ID の他に、同様にオブジェクトに置かれる独自の ID も使用することができます。 4. プラグマコード プラグマコードは、コンパイラオプションの一種です。次のプラグマコードを使用することができます。
#pragma nodebug | デバッグ時にソースを表示しません
#pragma debug | デバッグ時にソースを表示します
#pragma nowarnings | ソースについて警告を表示しません
#pragma warnings | ソースについて警告を表示します
#pragma notransactions | ソースに含まれるのは読取処理のみです。ソース内にはトランザクションはありません。したがって、1 つのデータベースサーバを開始するだけで十分です
#pragma warning <テキスト> | プログラマは自分の警告を生成します。(警告レベル15)。例を参照してください
#pragma fatal <テキスト> | プログラマは自分のエラーを生成します
#pragma sticky | プロセス終了時にオブジェクトをメモリから削除しません
#pragma used <構成要素> <コード> | 以下を参照してください
例:
    #pragma warning This is not a fine solution !

    | コンパイル後に次のメッセージが表示されます:
    | <ソース (ライン)>: 警告 (15): This is not a fine solution !
場合によっては、使用先リストが自動的に更新されません。たとえば、予期しないセッションコードが入力されたときです。 たとえば、 `message("ttadv2130s000") or bms.send("command", event, "ttaad3100s000", pr.id)` このセッションコードを使用先リストに入れるには、次のようなコマンドラインを入力します。 `#pragma used session ttadv2130s000` 次に示すのは使用先リストを更新するためのプラグマコードの一覧です。
#pragma used include | <ファイル>
#pragma used table | <テーブルコード>
#pragma used field | <フィールドコード>
#pragma used domain | <ドメインコード>
#pragma used message | <メッセージコード>
#pragma used question | <質問コード>
#pragma used session | <セッションコード>
#pragma used menu | <メニューコード>
#pragma used dll | <dll オブジェクト名>
#pragma used chart | <チャートコード>
通常は、使用先リストが更新されます。関数の場合、関数呼出しに文字列値が含まれるときに使用先リストが更新されます (例を参照)。 例
    mess("ttadvs0000", 1) | 使用先リストが更新されます

    str = "ttadvs0000"
    mess(str, 1) | 使用先リストは更新されません

    #pragma used message ttadvs0000
プラグマコードは、ソースのどこにでも配置できます。 たとえば、次のプラグマをソースの先頭に置いたとします。 `#pragma nowarnings` いくつかの警告の後で次のプラグマを入力することができます。 `#pragma warnings` 5. 条件付きコンパイル
    #ifdef <マクロ>
            #ifdef の後から #else/#elif/#endif までのソースは、<マクロ> が定義されている場合にコンパイルされます。そうでない場合、このソースは無視されます。

    #ifndef <マクロ>
            #ifndef の後から #else/#elif/#endif までのソースは、<マクロ> が定義されていない場合にコンパイルされます。そうでない場合、このソースは無視されます。

    #if <定数式>
            #if の後から #else/#elif/#endif までのソースは <定数式> が TRUE の場合にコンパイルされます。そうでない場合、このソースは無視されます。

    #else
            #if/#ifdef/#ifndef/#elif に属する条件が FALSE の場合、#else の後から #endif までのソースはコンパイルされます。#if/#ifdef/#ifndef/#elif に属する条件が TRUE の場合、#else の後から #endif までのソースは無視されます。

    #elif <定数式>
            #elif は #else および #if を組み合わせたものです。

    例
    #if <定数式>
    ...
    #else
    #if <定数式>
    ...
    #else
    ...
    #endif
    #endif

    上の例は、以下と同じです:
    #if <定数式>
    ...
    #elif <定数式>
    ...
    #else
    ...
    #endif

    #endif
    #ifdef/#ifndef/#if で始まるソースの部分を終了するには
    #undef <マクロ>
    マクロ定義を削除するということは、このマクロが次の #ifdef 呼出しでは未知であることを意味します。
#if、#elif 内の <定数式> は数値式です。この式では、ロングタイプのマクロおよび次のような演算子のみ使用できます。 +、-、*、/、=、<、>、<=、>=、<>、and、or、not、?:、() 入れ子 #if 構造を使用することができます。 D オプションを使用すると、コンパイラの起動時にマクロを定義することができます。
    bic6.2 -D<マクロ> | 値がない場合はデフォルトの 1
    bic6.2 -D<マクロ>=<値>
    bic6.2 -D<マクロ>='任意のトークン文字列'
これらのマクロは、次の例のように #if 条件の中でも使用できます。
    bic6.2 -DDEBUG -DMYTEST <ソース>

    |ソース
    #if DEBUG and MYTEST
    メッセージ (デバッグ情報)
    ...
    #endif
    bic6.2 -DCUSTOMER_X -DCUSTOMER_Y <ソース>
    bic6.2 -DSTANDARD <ソース>

    #if STANDARD
    ....
    #elif ( CUSTOMER_X and (not CUSTOMER_Y) )
    ....
    #endif
#ifdef を使用すると、ファイルを無効にすることができます。 例:
    #ifdef OLD
    ....
    ....
    ....
    #endif
プリプロセッサは 3GL ソースのコンパイル時にのみ機能します。これは、標準ジェネレータ std_gen6.2 にはプリプロセッサパスがないためです。このため、#if、#ifdef、または #ifndef に 4GL イベントを使用することはできません。 #ifdef ステートメントは埋込み SQL 問合せでは使用できません。したがって、
    select *
    #ifdef STANDARD
    ...
    from x
    #else
    ...
    from y
    #endif
    where ...
    selectdo
    ...
    endselect
は使用できませんが、次のような構文は使用することができます。
    #ifdef STANDARD
    select * from x where ...
    selectdo
    ...
    endselect
    #else select * from y where ...
    selectdo
    ...
    endselect
    #endif
3GL ソース内のデバッグ情報を提供するために 2 つのキーワードが導入されました。
    __FILE__     : 現行ソースの名前が含まれます。
    __LINE__     : 現行ソースのライン番号が含まれます。
例
    message(This is at line %d in the source %s, __LINE__, __FILE__)