プリプロセッサを使用するには

3GL プログラムスクリプト用のコンパイラ bic6.2 には、次の機能を備えた組込みプリプロセッサが搭載されています。

  • インクルードファイル
  • マクロの定義
  • 可変マクロ引数
  • トークン貼付
  • オブジェクトへの ID の設定
  • プラグマコード
  • 条件付きコンパイル

すべてのプリプロセッサ指示語は # で始まります。プリプロセッサ指示語はソースラインの先頭でなければなりません。また、スペースまたはタブが先行する可能性があります。

インクルードファイル

ファイルをインクルードするには、#include ファイル名、または #include <ファイル名> のステートメントを使用します。

< と > で囲まれたファイルは、$BSE/include<rel.number> ディレクトリ内で検索します。このディレクトリはシステムヘッダ用に予約されており、アプリケーションは使用することができません。

通常、引用符で囲まれたファイル名は、標準ファイルリダイレクション方式を使用して検索されます。$BSE/lib/fd.6.2<package_comb> に次のように入力されたとします。

ippmmm:/usr/bse/standard6.2

次のようなインクルード文があるとします。

#include ippmmmheader

ファイル /usr/bse/standard6.2/ippmmm/immmheader0 はインクルードされます。

ファイル名に / が使用されている場合は、ファイルは特定パス名を使用して検索されます。

ファイルが 2 度インクルードされると、2 番目のインクルードは無視されます。

プリプロセッサは 3GL ソースのコンパイル時にのみ機能します。これは、標準ジェネレータ std_gen6.2 にはプリプロセッサパスがないためです。したがって、4GL イベントはインクルードファイルでは使用できません。

マクロ定義

マクロを定義するには、次のステートメントを使用することができます。

#define マクロ名[(引数)] マクロ定義

マクロ定義

マクロを未定義にするには、次のステートメントを使用することができます。

#undef macroname[(arguments)]

ソース中のマクロ名はマクロ定義に置換されます。マクロ定義が 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 コール 

詳細は、条件付きコンパイルを参照してください。

可変マクロ引数

マクロを定義するには、省略表記 ( , ... ) を使用してマクロに可変引数を追加することもできます。

#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() の各関数のように、省略表記を使用する関数にも使用できます。

トークン貼付

マクロに変数の一部をマクロ引数として入力することができます。マクロ引数と他のマクロとを区別するために ## 記号が使用されますが、マクロ呼出しでは削除されます。また、多くのマクロ引数を 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 "@(#)<source name>, YY/MM/DD, [HH/MM],                             
                          From ${logname}"

UNIX の what コマンドは、標準出力では、「@(#)」 で始まるすべてのオブジェクト行を書き出します。

プログラマはこのデフォルト ID の他に、同様にオブジェクトに置かれる独自の ID も使用することができます。

プラグマコード

プラグマコードは、コンパイラオプションの一種です。次のプラグマコードを使用することができます。

#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

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

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

#if <定数式>
    #if の後から #else/#elif/#endif will
			 までのソースは <定数式> が 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 <macro>
     マクロ定義を削除します。これは、このマクロが次の
			#ifdef 呼出しでは未知であることを意味します。 

#if、#elif 内の<定数式> は数値式です。この式では、ロングタイプのマクロおよび次のような演算子のみ使用できます。 +、-、*、/、=、<、>、<=、>=、<>、and、or、not、?:、()

入れ子 #if 構造を使用することができます。

D オプションを使用すると、コンパイラの起動時にマクロを定義することができます。

    bic6.2 -D<マクロ>     | 値がない場合はデフォルトの 1 
    bic6.2 -D<マクロ>=<値>
			 bic6.2 -D<マクロ>='任意のトークン文字列' 

これらのマクロは、次の例のように #if 条件の中でも使用できます。

 bic6.2 -DDEBUG -DMYTEST <ソース> 

|source 
#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__)