
はじめに
InterSystemsCachéでのマクロの使用について説明します。 マクロは、ソースコードを一連のプログラム命令でコンパイルするときに置き換えられる記号名です。 マクロは、マクロ内のトリガーされたブランチとそれに渡される引数に応じて、呼び出しごとに異なる命令シーケンスで「展開」できます。 これは、静的コードまたはCOS実行の結果のいずれかです。 アプリケーションでどのように使用できるかを検討してください。
編集
はじめに、マクロが使用されている場所を理解するために、ObjectScriptコードがどのようにコンパイルされるかについていくつか説明します。
- クラスコンパイラは、クラス定義を使用してMACコードを生成します
- 場合によっては、コンパイラは追加のクラスを生成するための基礎としてクラスを使用します。 これらのクラスはスタジオで見ることができますが、変更しないでください。 これは、たとえば、WebサービスとWebクライアントを定義するクラスをコンパイルするときに発生します
- クラスコンパイラは、クラスハンドルも生成します。 Cachéは実行時にそれを使用します。
- プリプロセッサ(マクロプリプロセッサ、MPPと呼ばれることもあります)は、INCファイルを使用してマクロを置き換えます。 さらに、ObjectScriptルーチンの埋め込みSQLを処理します。
- これらの変更はすべてメモリ内で発生し、ユーザーコード自体は変更されません。
- 次に、コンパイラーはObjectScriptルーチンのINTコードを作成します。 この層は中間コードとして知られています。 このレベルのデータへのすべてのアクセスは、グローバルを介して行われます。
- INTコードはコンパクトで人間が読める形式です。 表示するには、スタジオでCtrl + Shift + Vまたはボタンを押します

- INTコードはOBJコードの生成に使用されます
- Caché仮想マシンはこのコードを使用します。 生成後、CLS / MAC / INTコードは不要になり、削除できます(たとえば、ソースコードなしでソリューションを提供する場合)
- クラスが保存されている場合、SQLコンパイラは適切なSQLテーブルを作成します
マクロ
既に述べたように、マクロは、プログラム命令のシーケンスを備えたプリプロセッサによる処理中に置換される記号名です。
#Defineコマンドを使用して、最初にマクロ名を(おそらく引数のリストを使用して)、次にマクロ値を使用して決定します。
#Define Macro [( Args )] [Value]マクロはどこで定義できますか? コード内で直接、またはマクロのみを含む別の
INCファイルで 。 クラス定義の最初にある
MacroFileNameを含むコマンドを使用して、必要なファイルをクラスに接続します-これは、マクロをクラスに接続するための主要かつ推奨される方法です。したがって、クラス定義の任意の部分でマクロを追加できます。
#Include MacroFileNameコマンドを使用して、INCマクロファイルをMACルーチンまたは個々のクラスメソッドのコードに添付できます。
例
例1
使用例に移り、「Hello World」の行の出力から始めます。 COSコード:
「Hello、World!」と 書く次の行を表示するHWマクロを作成します。
#define HW Write "Hello、World!"
コードに
$$$ HWを記述するだけです(
$$$マクロを呼び出してから、マクロ名):
ClassMethod テスト()
{
#define HW 「Hello、World!」と 書く
$$$ HW
}
コンパイル時に、次のINTコードに変換されます。
zTest1 ( )
public {「Hello、World!」と 書く }ターミナルでは、このメソッドが起動されると、以下が表示されます:
Hello, World!
例2
次の例では、変数を使用します。
ClassMethod Test2()
{
#define WriteLn(%str、%cnt) For ## Unique(new)= 1:1:%cnt {## Continue
%strを書きます! ##続行
}
$$$ WriteLn ( "Hello、World!" 、5)
}
ここでは、string%strが%cnt回表示されます。 変数名は%で始まる必要があります。 ## Unique(new)コマンドは、生成されたコードに新しい一意の変数を作成し、 ## Continueコマンドを使用すると、次の行でマクロの定義を続行できます。 このコードは、次のINTコードに変換されます。
zTest2 ( )
public {%mmmu1 = 1:1:5の場合
{「Hello、World!」と 書く !
} }
ターミナルでは、このメソッドが起動されると、以下が表示されます:
Hello, World! Hello, World! Hello, World! Hello, World! Hello, World!
例3
さらに複雑な例に移りましょう。
ForEach演算子は、グローバルを反復処理するときに非常に便利です。追加します。
ClassMethod Test3()
{
#define ForEach(%key、%gn) Set ## Unique(new)= $ name(%gn)## Continue
Set%key = "" ##続行
{##続行
Set%key = $ o(@ ##一意(古い)@(%key))##続行
終了:%key = ""
#define EndFor }
セット ^テスト(1)= 111
セット ^テスト(2)= 222
セット ^テスト(3)= 333
$$$ ForEach ( キー 、^テスト)
「key:」 、 key 、!
「value:」 、^ test( key )、!
$$$ EndFor
}
INTコードでは次のようになります。
zTest3 ( )
public {セット ^テスト (1)= 111
セット ^テスト (2)= 222
セット ^テスト (3)= 333
%mmmu1 = $ nameを 設定 ( ^テスト)
キーを 設定 = ""{キーを 設定 = $ o ( @
%mmmu1 @ (
key ) )
終了 : key = ""「key:」 、 key 、!「value:」 、 ^ test(
key ) 、!
} }
これらのマクロはどうなりますか?
- 入力は、繰り返しグローバル%gnの現在のキー(添え字)が書き込まれる変数%キーを受け入れます。
- 新しい変数に、グローバルの名前 (関数$ name )を書き込みます
- キーは初期の空の値を取ります
- 反復ループを開始します
- インデックスと$順序関数を使用して、次の値をキーに割り当てます
- 事後条件を使用して、キーが値「」を受け入れているかどうかを確認し、受け入れている場合は、反復が完了し、ループを終了します
- 任意のユーザーコードが実行されます。この場合、キーと値の出力
- サイクルが閉じています
ターミナルでは、このメソッドが起動されると、以下が表示されます:
key: 1 value: 111 key: 2 value: 222 key: 3 value: 333
リストと
配列( %Collection.AbstractIteratorクラスの子孫)を使用する場合は、同様のイテレーターを既に作成できます。
例4
マクロのもう1つの可能性は、コンパイル段階で任意のCOSコードを実行し、実行結果をマクロの代わりに置き換えることです。 コンパイル時間のあるマクロを作成します。
ClassMethod Test4 ()
{
#Define CompTS ## Expression( "" "Compiled:" _ $ ZDATETIME($ HOROLOG)_ "" "、!" )
$$$ CompTSを書く
}
これは、次のINTコードに変換されます。
zTest4 ( )
public {「Compiled:05/19/2015 15:28:45」と書きます! }ターミナルでは、このメソッドが起動されると、以下が表示されます:
Compiled: 05/19/2015 15:28:45
式
##式はコードを実行し、結果を置き換えます;次のCOS言語要素を入力できます:
- 行: 「abc」
- ルーチン :$$ ラベル ^ルーチン
- クラスメソッド : ##クラス ( App.Test ) 。 GetString ( )
- COS関数 :$ name ( var )
- 上記の項目の任意の組み合わせ
例5
プリプロセッサディレクティブ
# If 、
# ElseIf 、
# Else 、
# EndIfは、このメソッドのように、ディレクティブの後の式の値に応じて、コンパイル時にソースコードを選択するために使用されます。
ClassMethod Test5()
{
#If $ SYSTEM .Version 。 GetNumber ()= "2015.1.1" && $ SYSTEM .Version 。 GetBuildNumber ()= "505"
「Cachéの最新リリースバージョンを使用しています」と 書く
#ElseIf $ SYSTEM .Version GetNumber ()= "2015.2.0"
「Cachéの最新ベータ版を使用しています」と記述します
#その他
「アップグレードを検討してください」と 書いて ください
#EndIf
}
Cachéバージョン2015.1.1.505では、次のINTコードがコンパイルされます。
zTest5 () public {
「Cachéの最新リリースバージョンを使用しています」と 書く
}
そして、ターミナルで出力されます:
You are using the latest released version of Caché
ベータポータルからダウンロードされたCachéは、別のINTコードにコンパイルされます。
zTest5 () public {
「Cachéの最新ベータ版を使用しています」と記述します
}
そして、ターミナルで出力されます:
You are using the latest beta version of Caché
また、Cachéの以前のバージョンは、アップグレードの提案とともに以下のINTコードをコンパイルします。
zTest5 () public {
「アップグレードを検討してください」と 書いて ください
}
そして、ターミナルで出力されます:
Please consider an upgrade
この機能は、たとえば、新しいバージョンのCachéDBMS機能を使用できる古いバージョンと新しいバージョンの間でクライアントアプリケーションの互換性を維持するために使用できます。 マクロの有無をそれぞれ確認するプリプロセッサディレクティブ
#IfDef 、
#IfNDefも、この目的に役立ちます。
結論
マクロは、コードを理解しやすくするだけでなく、コード内で頻繁に繰り返される構造を単純化するか、コンパイル段階でアプリケーションロジックの一部を実装して実行時の負荷を軽減することができます。
次は?
次の記事では、マクロを使用したより応用された例、ロギングシステムについて説明します。
参照資料
コンパイルについてプリプロセッサディレクティブのリストシステムマクロのリスト例付きのクラスパートII ロギングシステム著者はhabrayuzersの
Daimor 、
Greyder 、そしてコードの作成に協力してくれた匿名のままにしたいと思っていた別の有能なエンジニアに感謝しています。