Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

BNF(ビーエヌエフ)とは | 意味や読み方など丁寧でわかりやすい用語解説

BNF(ビーエヌエフ)の意味や読み方など、初心者にもわかりやすいように丁寧に解説しています。

作成日: 更新日:

読み方

日本語表記

バッカス・ナウア記法 (バッカス・ナウアきほう)

英語表記

Backus-Naur Form (バッカスナウアフォーム)

用語解説

BNFは、Backus-Naur Form(バッカス・ナウア記法)の略称で、プログラミング言語やデータ形式といった「形式言語」の文法(構文)を記述するための標準的な記法の一つである。これは、言語がどのような要素で構成され、それらがどのような順序や組み合わせで現れるかを、曖昧さなく、数学的な厳密さを持って表現することを目的としている。開発者同士で言語の構造に関する共通認識を持つためや、言語を解析するプログラム(パーサー)を自動生成するための基盤として、非常に重要な役割を担っている。

詳細を説明する。BNFは、1950年代後半にジョン・バッカスとピーター・ナウアによって考案され、特に世界初の国際的なアルゴリズム記述言語であるALGOL 60の構文定義に用いられたことで広く知られるようになった。それ以前は、プログラミング言語の構文は自然言語(英語など)で記述されることが多く、曖昧さや誤解が生じやすかった。BNFの登場により、言語の構文を形式的に、かつ厳密に定義する道が開かれた。

BNFは主に以下の記号と概念を用いて文法規則を記述する。

  1. 非終端記号 (Non-terminal symbol): これらは、さらに別の記号の組み合わせで定義される、より抽象的な言語の要素を表す。通常、山括弧(<>)で囲まれる。例えば、<式><文> などがある。これらは文法規則の左辺に現れ、右辺によって定義される。

  2. 終端記号 (Terminal symbol): これらは、それ以上分解できない、言語の最小単位となる具体的な要素を表す。プログラミング言語で言えば、キーワード(ifwhileなど)、演算子(+-*など)、区切り記号(();など)、数字、文字列リテラルなどがこれにあたる。終端記号は通常、そのままの形で記述されるか、引用符で囲まれることもある。

  3. 定義記号 (Definition symbol): ::= という記号がこれにあたる。「左辺は右辺によって定義される」という意味を持つ。例えば、<A> ::= <B> とあれば、「非終端記号Aは非終端記号Bである」と定義される。

  4. 選択記号 (Alternation symbol): | という記号がこれにあたる。「右辺の複数の選択肢のうち、いずれか一つを選択する」という意味を持つ。例えば、<数字> ::= 0 | 1 | 2 とあれば、「数字は0、1、2のいずれかである」と定義される。

  5. 連結 (Concatenation): 複数の記号をスペースで区切って並べることで、それらの記号が記述された順序で連結されることを意味する。例えば、<宣言> ::= int <変数名> ; とあれば、「宣言はキーワードint、変数名、セミコロンの順で連結されたものである」と定義される。

これらの記号を使って、簡単な算術式の文法をBNFで記述する例を考える。

まず、最小単位である数字を定義する。 <数字> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

次に、より基本的な要素である「因子」を定義する。因子は数字か、括弧で囲まれた式、あるいは変数と考えることができる。 <変数> ::= a | b | c <因子> ::= <数字> | <変数> | ( <式> )

そして、「項」を定義する。項は因子、または項と乗算・除算記号と因子の組み合わせである。 <項> ::= <因子> <項> ::= <項> * <因子> <項> ::= <項> / <因子> これらの複数の定義を一つにまとめることもできる。 <項> ::= <因子> | <項> * <因子> | <項> / <因子>

最後に、「式」を定義する。式は項、または式と加算・減算記号と項の組み合わせである。 <式> ::= <項> | <式> + <項> | <式> - <項>

このBNFに従えば、「a + 1 * (b - 2)」のような文字列が有効な算術式であるかを判断できる。例えば、<式> から <項> を、そこから <因子> を、さらに <数字><変数> を展開していくことで、与えられた文字列が文法に適合するかどうかを検証できる。

BNFはプログラミング言語の構文定義に革命をもたらし、コンパイラやインタープリタを開発する上での基盤技術となった。パーサーは、このBNFで定義された文法規則に基づいて、入力されたプログラムコードが正しい構文であるかを解析し、抽象構文木と呼ばれる内部表現を生成する。この抽象構文木は、その後のコード生成や最適化の段階で利用される。

BNFには繰り返しや省略を直接表現する記法がないため、しばしば冗長な定義になりやすいという側面もあった。そのため、BNFを拡張したExtended Backus-Naur Form(EBNF)やAugmented Backus-Naur Form(ABNF)といった記法も考案され、より簡潔に文法を記述できるようになっている。EBNFでは、{...} で0回以上の繰り返し、[...] で0回または1回の出現(省略可能)を表現できるなど、表現力が強化されている。

システムエンジニアを目指す初心者にとって、直接BNFを記述する機会は多くないかもしれない。しかし、既存のプログラミング言語の仕様書や、通信プロトコル、データフォーマットなどの技術文書を読む際に、BNFやその拡張記法が用いられていることは珍しくない。これらの記法を理解していれば、曖昧な自然言語の説明に惑わされることなく、正確にその構文を把握することができる。また、BNFを学ぶことは、形式言語理論やコンパイラ理論の基本的な概念に触れることにもなり、プログラムがどのように解釈され実行されるかの深い理解へとつながる第一歩となるため、その重要性は非常に高い。

関連コンテンツ