予約語
予約語(よやくご、英: reserved word)とは、プログラミング言語において字句的には変数名、関数名、クラス名などの識別子としてのルールを満たしているにもかかわらず、識別子にならない字句要素。
似ている言葉としてキーワードがある。多くのプログラミング言語において予約語とキーワードはほぼ同じものを指すため、しばしば混同されるが両者は異なる概念である。キーワードは言語仕様上特別な意味を持った語のことである。キーワードであっても予約語でないこともあるし、その逆もある。たとえば ECMAScript[1]では、class
は予約されており予約語だが言語で使われておらずキーワードではない。ECMA-262 では、キーワードは予約語の部分集合で、言語で制御構造などの意味を持つ予約語がキーワードである。Java では使っていなくてもキーワードであり、goto
もキーワードである。SQLには予約されたキーワードと予約されていないキーワードがある。例にも出てきたように、個々の規格によっても両者それぞれ微妙に意味が違うこともある。
処理系で内部的に使う名前と同じであるといった理由で予約されているためにユーザーは使えない識別子という意味で「予約語」という語を使っている規格もある。この場合キーワードと予約語は別のものである。
FORTRAN、PL/I のように予約語を持たないプログラミング言語も存在する。 また、共通言語基盤(共通言語仕様 (CLS))にしたがって実装されたC#やVB.NETでは予約語を識別子として利用する構文が用意されている。
典型的な予約語・キーワード
- 流れ制御を表す単語(
if
、while
など) - プログラムの構成要素を表す単語(
function
、const
など) - 組み込み関数(
open
、read
など) - 組み込みの型(
int
、string
など) - 他の言語などと混同して、誤用される可能性のある語(Javaの
goto
、const
など) - 将来キーワードとして利用するかも知れない語(JavaScriptの
let
、super
、C++11のexport
(以前は使われていた)) - 過去にキーワードだったため意味が無くなった後も残してあるもの
キーワード指向の言語と記号指向の言語
抽象構文的には全く違いは無いにもかかわらず、具象構文・字句構文(lexical syntax)的な違いは見た目の違いとしてわかりやすいこともあり、しばしばプログラマの好みの問題になりやすい。代表的にはブロックが { ... }
か begin ... end
か、などといった点であるが、そういった要素に記号を多用しがちな言語と、キーワードを多用しがちな言語がある。記号を使うのは簡潔だが、やりすぎると一見では暗号のようになりかねない(PerlやAPLなど)。キーワードを使う言語は冗長だが明示的という点は利点だが、識別子に使える名前が制限され、フォントを変えるなどシンタックスハイライトの支援がないと見た目にも区別しづらい。キーワードは全て大文字とし、識別子には必ず大文字アルファベット以外の文字が含まれるようにする、といった解決法もある。近年はISO 646の国際版に、世界的に7ビットの文字コードは定着したが、以前は、あるいは今もEBCDICは絶滅していないので記号は自由に使えない場合もあった。
コンテキストキーワード
コンテキストキーワード (contextual keywords) はC#やC++などの言語で採用されている特殊なキーワードで、文脈キーワード、文脈依存キーワードとも言われる。実際のところ、goto
を go to
とも書けたり、elseif
相当を else if
という2語で1語扱いであったりと、文脈依存文法的なキーワードはそう特殊で珍しいものでもない。
言語を後から拡張する場合、新しい構文や予約語を追加すると既存のコードが壊れてしまう場合がある。例えば、変数やメソッド名が予約語と同じだった場合。しかし、完全に将来の拡張を予期することは困難であり、予約語が拡張の障害になりうる。
そこで、新しく拡張された構文の中でのみ予約語(キーワード)として動作するのがコンテキストキーワードである。 コンテキストキーワードは特定の構文以外では変数などの名前として使用できるため、既存のコードを破壊することがない。 例えば、C#のプロパティ構文ではget、set、valueという多くの名前に使われているであろう語をコンテキストキーワードとして追加している。
コンテキストキーワードの問題点
- 文脈によってキーワードか否かが決まるので正規表現などでは判断しがたいこともあり、テキストエディタのシンタックスハイライトを正確に行うのが困難なこともある。しかし、パーサの設計次第ではあるが統合開発環境などでは言語処理系自体のパーサを利用するなどして構文解析を行って実現する、という手もある。
- パーサ(構文規則)が複雑になる場合もある。
- 他のスコープの変数やクラスメンバなどを使用する際に、新しい構文の中でも識別子として利用しないといけない場合がある。
- C#では@をつけることで識別子として利用することができる。この機能はC#が利用しているCLIのように、他の言語での名前を使う場合などでも有用である。
コンテキストキーワードの利点
- 前述の「問題点」は全て、レキシカルアナライザは厳密な正規表現(正規言語に限られた範囲の表現)によって先頭のトークンを切り出すことしかできず、パーサは厳密にLL(1)かLALR(1)の構文規則のみに従ってパースすることしかできない、という、聊か非現実的な前提の下では正しい。しかし実際の言語の処理系の実装では、レキシカルアナライザもパーザもアドホックに拡張されているのが普通である。コンテキストキーワードのようなものは一般に、何らかの指定されたキーワードの直後であるとか、記号の特殊な組み合わせといったような、アドホックな拡張によって容易に扱えるように設計されるのが通例であり、以上の問題点による実際の問題は小さい。
- CLIのように、他の言語と共通のバックエンドやライブラリを使うためには、予約されている綴りを識別子として使うためのエスケープとともに、重要で必須な対応とも言える。