
コンピュータプログラミングにおいて、マクロ(「マクロ命令」の略。ギリシャ語のμακρο ( 「長い、大きい」)[ 1 ]に由来)とは、特定の入力を置換出力にどのようにマッピングするかを指定する規則またはパターンです。マクロを入力に適用することをマクロ展開といいます。
入力と出力は、語彙トークンまたは文字のシーケンス、あるいは構文木です。文字マクロは、ソフトウェアアプリケーションでサポートされており、一般的なコマンドシーケンスの呼び出しを容易にします。トークンマクロと構文木マクロは、一部のプログラミング言語でサポートされており、コードの再利用や言語の拡張を可能にし、場合によってはドメイン固有言語向けにもサポートされています。
マクロは、一連の計算命令を単一のプログラム文としてプログラマーが利用できるようにするために使用され、プログラミング作業の煩雑さを軽減し、エラーの発生を少なくします。[ 2 ] [ 3 ]このように、「小さな」文字列から「大きな」コードブロックを展開できるため、「マクロ」と呼ばれます。マクロでは、条件付きアセンブラプログラムが生成するものを指示する位置パラメータやキーワードパラメータが使用されることが多く、オペレーティングシステム、プラットフォーム、その他の要因などの変数に応じて、プログラム全体またはプログラムスイートを作成するために使用されてきました。この用語は「マクロ命令」に由来し、このような展開はもともとアセンブリ言語コードの生成に使用されていました。
キーボードマクロとマウスマクロは、短いキー操作とマウス操作のシーケンスを、通常はより時間のかかる別のキー操作とマウス操作のシーケンスに変換します。これにより、頻繁に使用される、あるいは繰り返し実行されるキー操作とマウス操作のシーケンスを自動化できます。これらのマクロを作成するための別個のプログラムは、マクロレコーダーと呼ばれます。
1980年代には、マクロプログラム(当初はSmartKey 、その後SuperKey、KeyWorks、Prokey)が非常に人気を博しました。最初は脚本の自動フォーマット手段として、その後は様々なユーザー入力タスクに利用されました。これらのプログラムは、終了して常駐する動作モードに基づいており、どのようなコンテキストで発生したかに関係なく、すべてのキーボード入力に適用されました。マウス駆動型のユーザーインターフェースの登場と、ワードプロセッサやスプレッドシートなどのアプリケーションでのキーボードおよびマウスマクロの利用により、アプリケーション依存のキーボードマクロの作成が可能になったことで、これらのプログラムはある程度廃れていきました。
キーボードマクロは、大規模多人数同時参加型オンラインロールプレイングゲーム(MMORPG)において、反復的だが収益性の高いタスクを実行するために使用できます。これによりリソースが蓄積されます。これは人間の介入なしに実行されるため、ゲームの経済を歪める可能性があります。そのため、マクロの使用はほとんどのMMORPGの利用規約またはEULAに違反しており、管理者はマクロの抑制に多大な労力を費やしています。[ 4 ]
アプリケーションに組み込まれたマクロ機能を使用して作成されるキーボードおよびマウスのマクロは、アプリケーションマクロと呼ばれることもあります。これらのマクロは、シーケンスを一度実行し、アプリケーションにそのアクションを記録させることで作成されます。アプリケーションの機能に直接アクセスできる、 基盤となるマクロプログラミング言語(最も一般的なのはスクリプト言語)が存在する場合もあります。
プログラマー向けのテキストエディタであるEmacs(「editing macros」の略)は、この考え方を徹底的に踏襲しています。実際、エディタの大部分はマクロで構成されています。Emacsはもともと編集言語TECOのマクロ集として考案され、後にLispの方言に移植されました。
プログラマ向けのテキストエディタであるVim ( viの後継)にもキーボードマクロが実装されています。キーボードで入力した内容をレジスタ(マクロ)に記録し、 Microsoft OfficeのVBAマクロのように再生したり編集したりできます。Vimには、マクロを作成するためのVimscript [ 5 ]と呼ばれるスクリプト言語もあります。
Visual Basic for Applications (VBA) は、Office 97 から Office 2019 までのMicrosoft Officeに含まれるプログラミング言語です(Office 97 以前の一部の Office コンポーネントでも利用可能でした)。しかし、VBA の機能は、これらのアプリケーションの一部に元々含まれていたマクロ言語から進化し、それらのマクロ言語に取って代わりました。
VMの会話型モニターシステム(CMS) コンポーネント上で動作するXEDITは、 EXEC、EXEC2、REXXで記述されたマクロをサポートしています。一部の CMS コマンドは、実際には XEDIT マクロのラッパーでした。XEDITの部分的なクローンであるHessling Editor (THE) は、 Regina および Open Object REXX (oorexx)を使用した Rexx マクロをサポートしています。多くの一般的なアプリケーション、そして PC 上のアプリケーションの一部は、スクリプト言語として Rexx を使用しています。
VBAはMicrosoft Windowsのほとんどのシステムコールにアクセスでき、ドキュメントが開かれると実行されます。そのため、VBAでコンピュータウイルス(一般にマクロウイルスと呼ばれる)を作成するのは比較的容易です。1990年代半ばから後半にかけて、マクロウイルスは最も一般的なコンピュータウイルスの1つになりました。しかし、 Microsoftは1990年代後半から現在に至るまで、プログラムにパッチとアップデートを継続的に提供してきました。さらに、最新のウイルス対策プログラムは、このような攻撃に即座に対処します。
パラメータ化されたマクロとは、その展開に特定のオブジェクトを挿入できるマクロです。これにより、マクロは関数の能力の一部を得ることができます。
簡単な例として、C プログラミング言語では、これはパラメータ化されたマクロではない、つまりパラメータなしのマクロである典型的なマクロです。
#定義PI 3.14159
これにより、 は出現場所にPI関係なく常に に置き換えられます3.14159。一方、パラメータ化されたマクロの例は次のとおりです。
#定義pred(x) ((x)-1)
このマクロの展開結果は、渡される 引数xによって決まります。展開例は以下のとおりです。
予測値(2) → ((2) -1) 予測値(y+2) → ((y+2) -1) 予測(f(5)) → ((f(5))-1)
パラメータ化されたマクロは、インライン展開を実行するための便利なソースレベルのメカニズムですが、単純なテキスト置換を使用するCなどの言語では、インライン関数などのインライン展開を実行する他のメカニズムに比べていくつかの重大な欠点があります。
一方、Lisp、PL/I、Schemeなどの言語で使用されるパラメータ化されたマクロははるかに強力で、引数に基づいてどのようなコードを生成するかを決定できるため、実行時のコード生成に効果的に使用できます。
C言語や一部のアセンブリ言語には、コンパイラまたはアセンブラのプリプロセッサとして実装された基本的なマクロシステムがあります。Cプリプロセッサのマクロは、文字レベルではなくトークンレベルでの単純なテキスト置換によって機能します。しかし、 IBM High Level Assembler (HLASM) などのより高度なアセンブラのマクロ機能はプリプロセッサでは実装できません。命令とデータをアセンブルするコードが、マクロ呼び出しをアセンブルするコードと混在しているからです。
マクロの典型的な使用例は、コンピュータ組版システムのTeXとその派生システムであり、ほとんどの機能はマクロに基づいています。[ 6 ]
MacroMLは、静的型付けとマクロシステムの調和を目指す実験的なシステムです。Nemerleは型付けされた構文マクロを持っており、これらの構文マクロを多段階の計算として考えることは生産的な方法の一つです。
その他の例:
いくつかの主要なアプリケーションは、 CMS の XEDITなど、他のアプリケーションによって呼び出されるテキスト マクロとして作成されています。
PHPなどの一部の言語は、自由形式のテキストや他の言語のソースコードに埋め込むことができます。コードフラグメントを認識するメカニズム(例えば、 と で囲まれている<?php)?>はテキストマクロ言語に似ていますが、はるかに強力で、機能が充実した言語です。
PL/I言語のマクロは、PL/I自体のサブセットで記述されます。コンパイラはコンパイル時に「プリプロセッサ文」を実行し、その実行結果がコンパイルされるコードの一部となります。使い慣れた手続き型言語をマクロ言語として使用できることは、テキスト置換マクロよりもはるかに強力ですが、コンパイラのサイズが大きくなり、処理速度が遅くなるという欠点があります。PL/Iのマクロは、多くのアセンブラと同様に、他のマクロからアクセスできる変数を設定するなど、 副作用を持つ場合があります。
フレーム技術のフレームマクロは独自のコマンド構文を持ちますが、任意の言語のテキストを含めることもできます。各フレームは、ネストされたサブアセンブリ階層内の汎用コンポーネントであると同時に、サブアセンブリフレームと自身を統合するための手順(統合の競合を上位レベルのサブアセンブリに優先させる再帰プロセス)でもあります。出力はカスタムドキュメント(通常はコンパイル可能なソースモジュール)です。フレーム技術は、マクロやサブルーチンの発明以来、ソフトウェア開発を悩ませてきた、類似しているものの微妙に異なるコンポーネントの増殖を回避できます。
ほとんどのアセンブリ言語には、ループ展開のためにコード ブロックを N 回繰り返すことができるなど、それほど強力ではない手続き型マクロ機能がありますが、これらは実際のアセンブリ言語とはまったく異なる構文を持っています。
前述の C プリプロセッサなどの、字句トークンのレベルで動作するマクロ システムでは、字句構造を確実に保持できません。構文マクロ システムは、代わりに抽象構文木のレベルで動作し、元のプログラムの字句構造を保持します。構文マクロ システムの最も広く使用されている実装は、Lisp系言語に見られます。これらの言語は、統一された括弧で囲まれた構文 ( S 式と呼ばれる) のため、このスタイルのマクロに特に適しています。特に、統一された構文により、マクロの呼び出しを判別しやすくなります。Lisp マクロはプログラム構造自体を変換し、そのような変換を表現するために言語全体を利用できます。構文マクロはLisp系言語でよく見られますが、Prolog、[ 7 ] Erlang、[ 8 ] Dylan、 [9] Scala、[ 10 ] Nemerle、[ 11 ] Rust、[ 12 ] Elixir、[ 13 ] Nim、[ 14 ] Haxe、[ 15 ] Julia [ 16 ]などの他の言語でも利用できます。また、 JavaScript [ 17 ]やC# [ 18 ]のサードパーティ拡張機能としても利用できます。
Lispにマクロが導入される以前、いわゆるFEXPRと呼ばれる関数のような演算子が存在しました。これは、引数によって計算される値ではなく、引数の構文形式を入力とし、計算で使用される値を出力としていました。言い換えれば、FEXPRはEVALと同じレベルで実装され、メタ評価層への窓口となっていました。これは、一般的に、効果的に推論するのが難しいモデルであることがわかりました。[ 19 ]
1963年、ティモシー・ハートはAIメモ57「LISPのマクロ定義」の中で、Lisp 1.5にマクロを追加することを提案した。[ 20 ]
アナフォリックマクロは、マクロに与えられた何らかの形式を意図的に捕捉するプログラミングマクロの一種で、その形式はアナフォラ(別の表現を参照する表現)によって参照される可能性があります。アナフォリックマクロは、ポール・グレアムの著書『On Lisp』で初めて登場し、その名称は言語学におけるアナフォラ(先行する単語の代わりに単語を使用する表現)に由来しています。
1980年代半ば、いくつかの論文[ 21 ] [ 22 ]で、マクロ定義とマクロ使用の構文環境が区別されるパターンベースのシステムである衛生的マクロ展開( )の概念が導入されました。これにより、マクロの定義者とユーザーは、不注意による変数の捕捉を心配する必要がなくなりました(参照透過性)。衛生的マクロは、 R5RS、R6RS、およびR7RS標準でScheme向けに標準化されています。衛生的マクロの競合する実装としては、、、明示的な名前変更、構文クロージャなどが多数存在します。とはどちらもScheme標準で標準化されています。 syntax-rulessyntax-rulessyntax-casesyntax-rulessyntax-case
最近、ラケットは衛生的なマクロの概念と「評価器の塔」を組み合わせ、1つのマクロシステムの構文展開時間が別のコードブロックの通常の実行時間になるようにしました。[ 23 ]また、括弧のない言語でインターリーブ展開と解析を適用する方法を示しました。[ 24 ]
Scheme以外にも、多くの言語が衛生的なマクロを実装しているか、部分的に衛生的なシステムを実装しています。例としては、Scala、Rust、Elixir、Julia、Dylan、Nim、Nemerleなどが挙げられます。
condなど)を作成できます。例えば、制御構造はあるものの、制御構造が存在しないLisp方言ではif、マクロを用いることで、制御構造を前者に基づいて定義することが可能です。例えば、Schemeには継続マクロとハイジェニックマクロの両方があり、これによりプログラマはループや早期終了といった制御抽象化を言語に組み込むことなく独自に設計できます。letマクロは、新しい束縛構造を導入するためにも使用できます。最もよく知られている例は、関数を引数の集合に適用するマクロへの変換です。フェライセンは[ 26 ] 、これらの3つのカテゴリーが、このようなシステムにおけるマクロの主要な正当な用途を構成すると推測している。一方で、非衛生的な、あるいは選択的な非衛生的な変換を許容するマクロシステムにおけるアナフォリックマクロなど、マクロの代替的な用途を提案する者もいる。
マクロと他の言語機能との相互作用は、これまで多くの研究が行われてきました。例えば、コンポーネントやモジュールは大規模プログラミングに役立ちますが、マクロとこれらの構成要素を併用するには、それらの相互作用を定義する必要があります。マクロと相互作用できるモジュールシステムやコンポーネントシステムは、Schemeやその他のマクロ対応言語向けに提案されています。例えば、Racket言語はマクロシステムの概念を構文タワーへと拡張し、マクロを含む言語でマクロを記述できるようにします。構文レイヤーの分離を保証する衛生管理技術を採用し、モジュール間でマクロをエクスポートできるようにしています。
マクロは通常、短い文字列 (マクロ呼び出し) をより長い命令シーケンスにマッピングするために使用されます。あまり一般的ではありませんが、マクロのもう 1 つの使用法は、その逆、つまり命令シーケンスをマクロ文字列にマッピングすることです。これは、STAGE2 モバイル プログラミング システムで採用されたアプローチです。このシステムでは、基本的なマクロ コンパイラ (SIMCMP と呼ばれる) を使用して、特定のコンピュータの特定の命令セットをマシンに依存しないマクロにマッピングしました。これらのマシンに依存しないマクロで記述されたアプリケーション (特にコンパイラ) は、基本的なマクロ コンパイラを備えたコンピュータであれば、変更を加えることなく実行できます。このようなコンテキストで実行される最初のアプリケーションは、マシンに依存しないマクロ言語で記述された、より高度で強力なマクロ コンパイラです。このマクロ コンパイラは、ブートストラップ方式で自分自身に適用され、コンパイル済みのはるかに効率的なバージョンを生成します。このアプローチの利点は、複雑なアプリケーションを 1 台のコンピュータからまったく異なるコンピュータに、ほとんど労力をかけずに移植できることです (各ターゲット マシン アーキテクチャごとに、基本的なマクロ コンパイラを作成するだけです)。[ 27 ] [ 28 ]現代のプログラミング言語、特にC言語の登場により、事実上すべてのコンピュータでコンパイラが利用できるようになり、このようなアプローチは不要になった。しかしながら、これはコンパイラブートストラップの(最初の例ではないにしても)最初の例の一つであった。
マクロ命令は、ネイティブアセンブラプログラム命令の任意のセットに対してプログラマによって定義できます が、通常、マクロはオペレーティングシステムに付属するマクロライブラリに関連付けられており、次のようなオペレーティングシステムの機能にアクセスできます。
IBM メインフレームなどで使用されていた古いオペレーティング システムでは、標準のマクロ命令が必ずしも高級言語で使用できるルーチンに対応するものを持っていなかったため、完全なオペレーティング システム機能はアセンブラ言語プログラムでのみ使用でき、高級言語プログラムでは使用できませんでした (もちろん、アセンブリ言語のサブルーチンが使用されている場合を除く)。
1950年代半ば、アセンブリ言語プログラミングがコンピュータプログラミングの主流であった時代に、マクロ命令機能が開発され、ソースコードを削減(各マクロ命令から複数のアセンブリ文を生成する)し、コーディング規約を強制(例えば、入出力コマンドを標準的な方法で指定する)することができました。[ 31 ]アセンブリソースコードに埋め込まれたマクロ命令は、アセンブラのプリプロセッサであるマクロコンパイラによって処理され、マクロを1つ以上のアセンブリ命令に置き換えます。結果として得られるコードは純粋なアセンブリであり、アセンブラによって機械語に変換されます。 [ 32 ]
IBM 705 コンピュータ用のマクロ言語を開発する最も初期のプログラミング インストールのうち 2 つは、デラウェア州の Dow Chemical Corp. とカリフォルニア州の Air Material Command の弾道ミサイル兵站オフィスにありました。
マクロ命令は、アセンブリ言語プログラミングと、それに続くFORTRANやCOBOLなどの高級プログラミング言語との間の中間ステップであると考える人もいます。
1950年代後半には、マクロ言語に続いてマクロアセンブラが登場しました。これは、マクロプリプロセッサとアセンブラの両方の機能を1つのプログラムで実現するという、両者を組み合わせたものでした。[ 32 ]初期の例としては、IBM 709、7094、7040、7044上のFORTRANアセンブリプログラム(FAP)[ 33 ]とマクロアセンブリプログラム(IBMAP)[ 34 ] 、そして7070/7072/7074上のAutocoder [ 35 ]が挙げられます。
1959年、ベル研究所のダグラス・E・イーストウッドとダグラス・マキロイは、人気のSAPアセンブラに条件付きマクロと再帰マクロを導入し、[ 36 ]マクロSAPと呼ばれるものを作成しました。[ 37 ]マキロイの1960年の論文は、マクロプロセッサを通じてあらゆる(高水準を含む)プログラミング言語を拡張する分野で画期的なものでした。[ 38 ] [ 36 ]
マクロアセンブラにより、アセンブリ言語プログラマは独自のマクロ言語を実装できるようになり、同じCPUを搭載しながらも異なるオペレーティングシステム(例えば、初期のMS-DOSとCP/M-86 )間でのコードの移植性が限定的に向上しました。マクロライブラリはターゲットマシンごとに作成する必要がありましたが、アセンブリ言語プログラム全体を作成する必要はありませんでした。より強力なマクロアセンブラでは、マクロ命令内で条件付きアセンブリ構造を使用できるため、異なるマシンやオペレーティングシステムで異なるコードを生成でき、複数のライブラリの必要性が軽減されました。
1980年代から1990年代初頭にかけて、デスクトップPCは数MHzでしか動作せず、C、Fortran、Pascalなどで書かれたプログラムを高速化するために、アセンブリ言語のルーチンが一般的に使用されていました。当時、これらの言語はそれぞれ異なる呼び出し規約を使用していました。マクロを使用すれば、アセンブリ言語で書かれたルーチンを、ほぼあらゆる言語で書かれたアプリケーションのフロントエンドに接続できました。ここでも、基本的なアセンブリ言語のコードは変わりませんでしたが、マクロライブラリをそれぞれの対象言語に合わせて作成するだけで済みました。
Unixやその派生言語などの現代のオペレーティングシステムでは、オペレーティングシステムへのアクセスは、通常は動的ライブラリによって提供されるサブルーチンを通じて提供されます。C言語などの高級言語は、オペレーティングシステムの機能への包括的なアクセスを提供するため、そのような機能のためにアセンブラ言語プログラムを使用する必要はありません。
さらに、Goなどのいくつかの新しいプログラミング言語の標準ライブラリでは、移植性とセキュリティを向上させるために、必要がない限りプラットフォームに依存しないライブラリを優先し、システムコールの使用を積極的に推奨していません。[ 39 ]
プログラマーマクロの重要な用途の一つは、プログラムの実行中に頻繁に繰り返される命令列の記述にかかる時間と事務的なミスを削減することです。
TEXにはマクロプログラミング言語があり、機能を追加することができます。