プログラミング言語において、予約語(予約識別子とも呼ばれる)とは、プログラマが変数名、関数名、ラベル名などの識別子として使用できない単語のことです。つまり、「使用が予約されている」状態です。簡単に言うと、識別子は文字で始まり、その後に任意の文字と数字の並びが続きます(言語によっては、アンダースコア「_」も文字として扱われます)。
命令型プログラミング言語や多くのオブジェクト指向プログラミング言語では、代入やサブルーチン呼び出しとは別に、if、while、do、forなどのキーワードが特定のステートメントを識別するためによく使用されます。Ada 、C、C ++、COBOL、Java、Pascalなど、多くの言語ではキーワードを予約語として扱います。予約語の数は言語によって大きく異なり、Cには約30個、COBOLには約400個あります。
一部の言語には予約語がありません。FortranとPL/I はコンテキストによってキーワードを識別しますが、Algol 60とAlgol 68 は一般的にストロッピングを使用して、キーワードとプログラマ定義の識別子を区別します。たとえば、または、またはは、識別子とは異なるキーワードです。.if'if'if'ifif
ほとんどのプログラミング言語には、標準ライブラリ(または複数のライブラリ)が用意されています。例えば、sin、cosなどの数学関数です。ライブラリによって提供される名前は予約されておらず、ライブラリの機能が不要になった場合は、プログラマーが再定義することができます。
対話型開発環境(IDE)を使用してプログラムを開発する場合、IDEは通常、予約語を別の色で強調表示します。一部のIDEでは、コメントも(さらに別の色で)強調表示されることがあります。これにより、プログラマーは予約語の予期せぬ使用や、コメントの終了が正しく行われていないことに容易に気づくことができます。
キーワードではない予約語が存在する場合があります。例えば、Javaでは、true およびはfalseブール(論理)リテラルとして使用される予約語です。別の例として、Pascalでは、divおよびはmod演算子(整数除算と剰余)として使用される予約語です。
また、定義されていない意味を持つ予約語も存在する場合があります。たとえば、Java では、gotoおよびはconst予約語としてリストされていますが、Java の構文規則ではそれ以外に言及されていません。[ 1 ]
ifやwhileなどのキーワードは、構文解析中に、どのような種類の文が検討されているかを判断するために使用されます。キーワードが予約語またはストロップされている場合、このような解析ははるかに簡単になります。Fortran 77 でコンテキスト解析を使用して区別する場合の複雑さを考えてみましょう。
IF (B) l1,l2 ! 双方向分岐、ここで B はブール式 IF (N) l1,l2,l3 ! 3分岐、ここでNは数値式 IF (B) THEN ! 条件ブロック開始 IF (B) THEN = 3.1 ! 変数への条件付き代入 THEN IF (B) X = 10 ! 単一の条件文 IF (B) GOTO l4 ! 条件付きジャンプ IF (N) = 2 ! IF という名前の添え字付き変数への代入
PL/Iでは、一見すると紛らわしい構文もいくつか許容される。
IF IF = THEN THEN ... /* (2番目IFと1番目THENは変数です */
ストロッピングを使用するプログラミング言語と比較すると、プログラムの可読性が向上する可能性がある。
IDE では、どの単語が実際にキーワードであるかを判断するために文脈分析を行う必要がないため、キーワードをハイライト表示することが容易になります (前のセクションの Fortran の例を参照)。
コンパイラは、任意の長さの文全体に対して文脈分析を行う必要なく、単語がキーワードであるかどうかを迅速に判断できるため、より高速になる可能性がある。
プログラミング言語は、識別子として使用できない予約語のリスト(場合によっては長い)を覚えなければならないため、新規ユーザーにとって習得が難しい場合があります。[ 2 ]
言語を拡張するのは難しい場合がある。なぜなら、新機能のために予約語を追加すると既存のプログラムが無効になる可能性があり、逆に、既存の予約語に新しい意味を「過剰に」与えると混乱を招く可能性があるからだ。
プログラムの移植は、あるシステムやコンパイラでは予約語ではない単語が、別のシステムやコンパイラでは予約語になっている可能性があるため、問題となる場合があります。
特定の単語リストを予約するだけでなく、一部の言語では、将来の言語バージョン、異なる方言、コンパイラベンダー固有の拡張機能、またはコンパイラによる内部使用(特に名前マングリング)のために、単語の範囲全体を予約します。
これは多くの場合、接頭辞、多くの場合 1 つ以上のアンダースコアを使用することによって行われます。C とC++ はこの点において注目に値します。C99 では、2 つのアンダースコアまたはアンダースコアの後に大文字が続く識別子が予約されており、さらに、ファイル スコープで使用するために (通常のスペースとタグ スペースで) 1 つのアンダースコアで始まる識別子が予約されています。[ 3 ] C++03では、どこにでも二重アンダースコアを含む識別子がさらに予約されています[ 4 ] – これにより、たとえば、二重アンダースコアを区切り文字として使用 (ユーザー識別子を接続するため) できます。
Python の内部識別子で二重アンダースコアが頻繁に使用されることから、dunderという略語が生まれました。これは、Mark Jackson [ 5 ]と Tim Hochberg [ 6 ]によって、それぞれ数分違いで考案され、どちらも 2002 年に同じ質問に回答しました。[ 7 ] [ 8 ]
言語における予約語とキーワードのリストは、言語開発時に定義され、どちらも言語の形式仕様の一部となります。一般的に、有効な識別子名を制限しないように、予約語の数を最小限に抑えることが望まれます。さらに、新しい予約語を導入すると、その単語を使用する既存のプログラムが動作しなくなるため(後方互換性がなくなるため)、これは避けられます。これを防ぎ、前方互換性を確保するために、現在使用されていない単語(キーワードではない予約語)を予約することがあります。これにより、既存のプログラムを壊すことなく、将来的にその単語を使用できるようになります。あるいは、新しい言語機能を事前定義として実装し、それをオーバーライドすることで、既存のプログラムを壊さないようにすることもできます。
柔軟性を持たせる理由としては、コンパイラベンダーが非標準機能を追加することで仕様を拡張できるようにすること、異なる標準言語方言で仕様を拡張できるようにすること、あるいは将来のバージョンで追加機能を含めることができるようにすることなどが挙げられます。例えば、手続き型言語では、将来のバージョンや方言でオブジェクト指向class機能を追加することを想定している場合があり、その際にやといったキーワードを追加する可能性がありますobject。このような可能性に対応するため、現在の仕様では、たとえ現在使用されていなくても、これらのキーワードを予約語とする場合があります。
注目すべき例として、Javaではconst、と はgoto予約語です。Java では意味を持ちませんが、識別子としても使用できません。これらの用語を予約することで、必要に応じて、古い Javaソース コードを破壊することなく、将来の Java バージョンで実装できます。たとえば、1999 年に、C++ のようなconst機能を言語に追加する提案がありましたconst。これは、予約語であるが現在使用されていない を使用することで可能でした。しかし、この提案は却下されました。主な理由は、この機能を追加しても既存のプログラムが壊れることはないものの、標準ライブラリ (特にコレクション内) で使用すると互換性が損なわれるためです。 [ 9 ] JavaScriptにも、特別な機能を持たない予約語が多数あります。正確なリストはバージョンとモードによって異なります。[ 10 ]
言語によって、新しい予約語やキーワードを導入する頻度やその命名方法が大きく異なり、既存のプログラムを壊さないように、新しいキーワードをめったに、あるいは全く導入しない非常に保守的な言語もあれば、新しいキーワードをより自由に導入し、既存のプログラムに競合する既存の識別子の変更を要求する言語もあります。2011年に導入されたC11とC++11の新しいキーワードを比較すると、その例がわかります。C と C++ では、アンダースコアの後に大文字が続く識別子は予約語であることを思い出してください。[ 11 ]
C 委員会は、一般的に C の各改訂版が古い C プログラムとの互換性を損なわないようにすることが期待されているため、ユーザー名空間に新しいキーワードを作成しないことを好みます。これに対し、C++ 委員会 (WG21) は、新しいキーワードを古いキーワードと同じように通常の見た目にすることを好みます。たとえば、C++11 では、
thread_local1 つのスレッドにローカルな静的ストレージを指定するための新しいキーワードが定義されています。C11 では、新しいキーワードを次のように定義しています。_Thread_local.新しい C11 ヘッダー< threads.h >には、通常の見た目の名前を提供するマクロ定義があります。[ 12 ]
#define thread_local _Thread_local
_Thread_localつまり、C11では、既存の予約語 (特定の接頭辞を持つもの) の中にキーワードを導入し、その後、別の機能 (マクロ処理) を使用して、接頭辞なしで新しいキーワードであるかのように使用できるようにしました。一方、C++11 ではthread_local、既存の予約語ではないにもかかわらずキーワードを導入したため、これを使用していたプログラムはすべて動作しなくなりましたが、マクロ処理は必要ありませんでした。
Microsoft の.NET共通言語インフラストラクチャ(CLI) 仕様では、40 種類以上のプログラミング言語で記述されたコードを最終製品に統合できます。そのため、ある言語で実装されたコードが別の言語で記述されたコードを実行しようとすると、識別子や予約語の衝突が発生する可能性があります。たとえば、Visual Basic (.NET)ライブラリには、次のようなクラス定義が含まれている場合があります。
Visual Basic.NET における This のクラス定義:Public Class this ' このクラスは何かをします... End Classこれがコンパイルされてツールボックスの一部として配布される場合、型 " の変数を定義しようとするC#thisプログラマーは問題に遭遇します。'this'は C# の予約語です。したがって、次のコードは C# ではコンパイルされません。
// C# でこのクラスを使用する:this x = new this (); // コンパイルできません!メンバーへのアクセス、仮想メソッドのオーバーライド、名前空間の識別を行う際にも同様の問題が発生します。
これはストロッピングによって解決されます。この問題を回避するために、仕様では(C#では)識別子の前にアットマークを配置することが許可されており、これによりコンパイラはそれを予約語ではなく識別子として認識します。
// C# でこのクラスを使用する:@this x = new @this (); // コンパイルされます!一貫性を保つため、この使用はローカル変数、パラメータ名、プライベートメンバーなどの非公開設定でも許可されています。