Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 16918] ファイルの概要

このコミットは、Goコンパイラのフロントエンドの一部であるcmd/gcが使用するBisonパーサジェネレータの出力処理に関するものです。具体的には、GNU Bison 3.0で導入された新しい%emptyディレクティブとの互換性を確保するための変更です。

コミット

  • コミットハッシュ: 4eaf91a7a729f96b020324cc78e66bc687f549f5
  • Author: Rémy Oudompheng oudomphe@phare.normalesup.org
  • Date: Tue Jul 30 04:31:15 2013 +0200

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/4eaf91a7a729f96b020324cc78e66bc687f549f5

元コミット内容

cmd/gc: make bisonerrors compatible with GNU Bison 3.0

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/11990043

変更の背景

この変更の背景には、パーサジェネレータであるGNU Bisonのバージョンアップがあります。Goコンパイラ(cmd/gc)は、その構文解析のためにBisonを使用しています。Bisonの以前のバージョンでは、空のプロダクションルール(右辺が空のルール)を表現するために、通常は/* empty */のようなコメントを使用するか、単に右辺を空のままにしていました。

しかし、GNU Bison 3.0では、空のルールを明示的に宣言するための新しいディレクティブ%emptyが導入されました。これは、意図しない空のルールを警告したり、より明確に空のルールを定義したりするための改善です。この変更により、Bison 3.0で生成されたパーサの出力が、以前のバージョンとは異なる形式で空のルールを表現するようになりました。

src/cmd/gc/bisonerrorsスクリプトは、Bisonが生成するエラーレポートや文法情報から、特定の情報を抽出・処理するために使用されていました。Bison 3.0が%emptyという新しいキーワードで空のルールを示すようになったため、このスクリプトが空のルールを正しく認識し、処理できるように更新する必要が生じました。もしこの更新が行われないと、Bison 3.0で生成されたパーサがGoコンパイラで正しく動作しない可能性がありました。

前提知識の解説

Bison (GNU Bison)

Bisonは、GNUプロジェクトによって開発されたパーサジェネレータです。これは、LALR(1)パーサを生成するために使用されます。コンパイラやインタプリタの構築において、ソースコードの構文解析(パース)を行う部分を自動生成するのに非常に役立ちます。開発者は、BNF(バッカス・ナウア記法)に似た形式で文法ルールを記述したファイル(通常.yまたは.yy拡張子)を作成し、Bisonはその文法定義に基づいてC、C++、Java、またはGoなどの言語でパーサのソースコードを生成します。

プロダクションルールと空のルール (Empty Rule / Epsilon Production)

文法は、非終端記号(構文の抽象的な要素、例: expression, statement)と終端記号(実際のトークン、例: +, if, identifier)から構成されます。プロダクションルールは、非終端記号がどのように終端記号や他の非終端記号のシーケンスに展開されるかを定義します。

例: statement: expression ';' | IF '(' condition ')' statement;

「空のルール」または「イプシロンプロダクション」とは、右辺が空であるプロダクションルールを指します。これは、特定の構文要素が「存在しない」ことを許容する場合に用いられます。例えば、オプションのセミコロンや、リストの最後の要素の後に続くカンマなどです。

例: optional_semicolon: ';' | /* empty */;

GNU Bison 3.0の%emptyディレクティブ

Bisonの以前のバージョンでは、空のルールは右辺を単に空にするか、/* empty */のようなコメントを付けて表現するのが一般的でした。しかし、Bison 3.0では、空のルールをより明示的に宣言するための%emptyディレクティブが導入されました。

例: optional_semicolon: ';' | %empty;

この%emptyディレクティブを使用することで、文法の意図がより明確になり、Bisonは意図しない空のルールに対して警告を発するようになります。これにより、文法定義の堅牢性が向上します。

src/cmd/gc/bisonerrorsスクリプト

Goコンパイラのソースツリーにあるsrc/cmd/gc/bisonerrorsは、Bisonが生成する出力(特にエラーや文法に関する情報)を処理するためのスクリプトです。このスクリプトは、Bisonの出力から文法ルールの左辺(rulelhs)や右辺の要素数(rulesize)などの情報を抽出し、Goコンパイラが内部的に利用できる形式に変換する役割を担っています。

技術的詳細

このコミットは、src/cmd/gc/bisonerrorsスクリプトが、GNU Bison 3.0で導入された%emptyディレクティブによって表現される空のルールを正しく解釈できるようにするためのものです。

Bison 3.0では、空のルールが%emptyというキーワードで明示されるようになりました。bisonerrorsスクリプトは、Bisonの出力から各プロダクションルールの情報をパースし、そのルールの右辺の要素数(rulesize)を計算しています。従来の空のルールは右辺が空であるため、rulesizeが0として計算されていました。しかし、Bison 3.0の出力では、%emptyが右辺の要素として現れるため、単純に要素数を数えるとrulesizeが1と誤って計算されてしまう可能性がありました。

このコミットの目的は、bisonerrorsスクリプトが%emptyを検出した場合に、そのルールのrulesizeを正しく0として扱うように修正することです。これにより、GoコンパイラがBison 3.0で生成されたパーサを使用する際に、文法ルールの解釈に齟齬が生じないようにします。

具体的には、スクリプトはBisonの出力行を解析し、ルールの右辺が%emptyという単一の要素で構成されている場合に、そのルールのサイズを0に設定します。これにより、Bison 3.0の新しい空ルール表現が、Goコンパイラのビルドプロセスで正しく処理されるようになります。

コアとなるコードの変更箇所

変更はsrc/cmd/gc/bisonerrorsファイルにあります。

--- a/src/cmd/gc/bisonerrors
+++ b/src/cmd/gc/bisonerrors
@@ -35,6 +35,9 @@ grammar && NF>0 {
 	}
 	rulelhs[$1] = r
 	rulesize[$1] = NF-2
+	if(rulesize[$1] == 1 && $3 == "%empty") {
+		rulesize[$1] = 0
+	}
 	if(rulesize[$1] == 3 && $3 $4 $5 == "/*empty*/") {
 		rulesize[$1] = 0
 	}

追加されたのは以下の3行です。

	if(rulesize[$1] == 1 && $3 == "%empty") {
		rulesize[$1] = 0
	}

コアとなるコードの解説

この変更は、awkスクリプトであるsrc/cmd/gc/bisonerrors内で行われています。

  • grammar && NF>0 { ... }:このawkブロックは、Bisonの出力のうち、文法ルールに関する行を処理します。NFはフィールドの数を表します。
  • rulelhs[$1] = r:ルールの左辺(非終端記号)を記録しています。$1は通常、ルールの左辺の非終端記号に対応します。
  • rulesize[$1] = NF-2:ルールの右辺の要素数を計算しています。Bisonの出力形式では、最初の2つのフィールドがルールの番号や左辺の記号などであるため、NF-2で右辺の実際の要素数を取得します。
  • if(rulesize[$1] == 1 && $3 == "%empty") { rulesize[$1] = 0 }
    • これが今回追加された主要なロジックです。
    • rulesize[$1] == 1:計算されたルールの右辺の要素数が1であるかをチェックします。
    • $3 == "%empty":そして、その唯一の要素が文字列"%empty"であるかをチェックします。Bison 3.0では、空のルールが%emptyという単一のトークンとして出力されるため、この条件が合致します。
    • rulesize[$1] = 0:もし上記の条件が真であれば、そのルールの実際のサイズは0(空)であると判断し、rulesizeを0に上書きします。
  • if(rulesize[$1] == 3 && $3 $4 $5 == "/*empty*/") { rulesize[$1] = 0 }
    • これは既存のロジックで、従来の/* empty */コメントで表現された空のルールを処理するためのものです。
    • /* empty */は3つのトークン(/*, empty, */)として扱われるため、rulesizeが3になる場合に、それが/*empty*/であればrulesizeを0に設定していました。

この変更により、bisonerrorsスクリプトは、Bison 3.0で導入された%emptyディレクティブによって表現される空のルールを正しく認識し、そのサイズを0として処理できるようになりました。これにより、Goコンパイラのビルドシステムが新しいBisonバージョンと互換性を持つことが保証されます。

関連リンク

参考にした情報源リンク