はじめに
プログラミング言語のドキュメントを読んでいると、コードのような形で構文ルールが記述されているのを見たことがあるかもしれません。
functionDeclaration :
'fun' [modifiers] [typeParameters]
simpleIdentifier
[functionValueParameters]
[':' type]
[typeConstraints]
[functionBody]
このような形式は単なるサンプルコードではなく、EBNF(Extended Backus–Naur Form)=拡張BNF と呼ばれる言語仕様を定義するための記法です。
この記事では、KotlinやGoなど多くの言語仕様で採用されているEBNFについて、その仕組みと読み方を整理してみます。
EBNFとは?
EBNFは「Extended Backus–Naur Form(拡張バッカス・ナウア記法)」の略で、プログラミング言語などの構文を形式的に表現するためのメタ言語です。
BNF(Backus–Naur Form)という原型をもとに、より人間に読みやすく、実際の仕様書に使いやすく拡張されたものになります。
言語設計者が「この言語では、どういう順序で文法が構成されるか」を明示するために使われ、パーサーやコンパイラを作る際の仕様基盤にもなっています。
基本構文
EBNFでは「構文要素」と「その定義」を【生成規則】で表します。
代表的な記号をまとめると、以下のようになります。
| 記号 | 意味 | 例 |
|---|---|---|
= または ::=
|
定義を表す | `Expr = Term |
| ` | ` | 選択肢(or) |
[] |
省略可能(optional) |
[modifiers] はなくてもOK |
{} |
繰り返し(0回以上) |
{argument} は任意個の引数 |
() |
グループ化 | (expr '+' term) |
? |
0回または1回(optional) | `('+' |
'text' |
リテラル文字列 |
'fun', 'if', 'return' など |
/* comment */ |
コメント | 補足や注釈 |
Kotlinの例
Kotlinの公式仕様書にもEBNFが登場します。
以下は「関数定義(functionDeclaration)」の一部です。
functionDeclaration :
'fun' [modifiers] [typeParameters]
simpleIdentifier
[functionValueParameters]
[':' type]
[typeConstraints]
[functionBody]
この定義を読むと:
-
funキーワードで始まり - 修飾子や型パラメータは任意([]で省略可能)
- 関数名、引数、戻り値、制約、そして本体(functionBody)が続く
といった構造が明確に分かります。
Goの例
Go言語の仕様書でもEBNFが採用されています。
冒頭に Notation というセクションがあり、構文規則が次のように定義されています。
Production = production_name "=" expression .
このように、言語仕様全体がEBNFの生成規則をもとに構築されています。
KotlinやGoに限らず、RustやSwift、C#などの言語でも同様の表現が使われています。
EBNFの利点
EBNFには、次のような特徴があります。
- 構文が明確になる:文章ではなく「規則」で定義できる
- 曖昧さがない:人間にも機械にも理解可能
- 自動生成に使える:このルールからパーサーを作ることができる
つまりEBNFは、「人間にとっての説明書」と「機械にとっての仕様書」の中間に位置する存在です。
BNFとの違い
BNFとEBNFの主な違いは、表現の自由度です。
BNFは古典的で構文が厳密な反面、可読性が低くなりがちです。
EBNFでは [] や {} を導入することで、より自然に「任意」「繰り返し」を表現できるようになりました。
BNF:
<expr> ::= <term> | <expr> "+" <term>
EBNF:
Expr = Term | Expr '+' Term
シンプルな書き方に見えて、意味は同じです。
人間が読んで理解しやすい形になった、というのがEBNFの強みです。
EBNFを読むときのコツ
-
まず構文要素を単語として覚える
-
Expression,Statement,Declarationなどは構文の「分類名」
-
-
[] や {} に注目する
- それが任意か、繰り返しかを判断するポイント
-
“リテラル”と“構文要素”を区別する
-
'fun'は固定文字列 -
identifierは変化する構文要素
-
-
トップレベルから順に読む
- 仕様書は上から下へ階層的に構成されている
- 最初に出てくる規則が、その言語の骨格になる
まとめ
EBNF(拡張BNF)は、プログラミング言語の文法を定義するための国際的な標準記法です。
KotlinやGoなどの公式ドキュメントでよく見かけるコードのようでコードでないブロックは、実はこのEBNFによって記述されています。
文法を読む力を身につけることで、単なる仕様確認にとどまらず、「言語がどう設計されているか」をより深く理解できるようになります。
さいごに
EBNFを理解しておくと、「言語のルールを読む力」が身につきます。
仕様書を読むだけでなく解釈できるようになると、新しい言語の習得もぐっと早くなります。
ぜひ、今後の学習の中で仕様書を読むときの参考にしてもらえたら嬉しいです。