[インデックス 10661] ファイルの概要
このコミットは、Goコンパイラの字句解析器および構文解析器に関連する部分において、Bisonパーサジェネレータの内部的な予約語との衝突を避けるために、%union ディレクティブ内のフィールド名を lint から i へと変更するものです。具体的には、#define lint というBisonのプリプロセッサ定義が、%union 内の lint というフィールド名と衝突し、コンパイルエラーや予期せぬ動作を引き起こす可能性があったため、この名称変更が行われました。
コミット
commit f00340f02287456b24a414b4b10051b727c6ad2e
Author: Russ Cox <rsc@golang.org>
Date: Wed Dec 7 23:38:32 2011 -0500
gc: rename %union field name from lint to i
#define lint has special meaning to Bison;
having a field named lint conflicts with that.
R=ken2
CC=golang-dev
https://golang.org/cl/5462044
---
src/cmd/gc/go.y | 6 +++---
src/cmd/gc/lex.c | 2 +-\n 2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index 1b00235083..075117102b 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -31,13 +31,13 @@ static void fixlbrace(int);\n Type* type;\n Sym* sym;\n struct Val val;\n-\tint lint;\n+\tint i;\n }\n \n // |sed 's/.* //' |9 fmt -l1 |sort |9 fmt -l50 | sed 's/^/%xxx /'\n \n %token <val> LLITERAL\n-%token <lint> LASOP\n+%token <i> LASOP\n %token <sym> LBREAK LCASE LCHAN LCOLAS LCONST LCONTINUE LDDD\n %token <sym> LDEFAULT LDEFER LELSE LFALL LFOR LFUNC LGO LGOTO\n %token <sym> LIF LIMPORT LINTERFACE LMAP LNAME\n@@ -47,7 +47,7 @@ static void fixlbrace(int);\n %token LANDAND LANDNOT LBODY LCOMM LDEC LEQ LGE LGT\n %token LIGNORE LINC LLE LLSH LLT LNE LOROR LRSH\n \n-%type <lint> lbrace import_here\n+%type <i> lbrace import_here\n %type <sym> sym packname\n %type <val>\toliteral\n \ndiff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index cf7bbae9ed..3dbd6dda1a 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -1098,7 +1098,7 @@ lx:
return c;
asop:
-\tyylval.lint = c; // rathole to hold which asop
+\tyylval.i = c; // rathole to hold which asop
DBG("lex: TOKEN ASOP %c\n", c);
return LASOP;
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/f00340f02287456b24a414b4b10051b727c6ad2e
元コミット内容
このコミットは、Goコンパイラのgc(Go Compiler)部分における、Bisonパーサジェネレータが使用する文法ファイル(go.y)と字句解析器のC言語ソースファイル(lex.c)に対して行われた修正です。具体的には、%union ディレクティブ内で定義されていた lint というフィールドの名前を i に変更し、それに伴い、このフィールドを参照していた %token および %type の宣言、そして lex.c 内の yylval.lint の使用箇所も yylval.i に修正しました。
変更の背景
この変更の背景には、Bisonパーサジェネレータの内部的な動作と、C言語のプリプロセッサの挙動が関係しています。コミットメッセージに「#define lint has special meaning to Bison; having a field named lint conflicts with that.」とあるように、Bisonは内部的に lint という名前を特別な意味を持つマクロとして定義している可能性があります。
C言語のプリプロセッサは、コンパイルの前にソースコード内のマクロ定義を置換します。もしBisonが生成するコードや、Bisonが処理する入力ファイルにおいて、#define lint ... のようなマクロ定義が存在する場合、%union 内で lint というフィールド名を使用すると、プリプロセッサがこのフィールド名をマクロの定義内容で意図せず置換してしまい、結果として構文エラーや意味の誤解釈、あるいはコンパイル時の問題を引き起こす可能性がありました。
このような衝突を避けるため、Goコンパイラの開発者は、Bisonの内部的な予約語やマクロと衝突しないように、lint という一般的な名前をより汎用的な i(おそらく "integer" の略)に変更することを決定しました。これにより、コンパイラのビルドプロセスにおける潜在的な問題を解消し、安定性を向上させることが目的です。
前提知識の解説
このコミットを理解するためには、以下の前提知識が必要です。
Goコンパイラ (gc)
Go言語の公式コンパイラは、通常 gc と呼ばれます。これはGo言語自体で書かれており、Goのソースコードを機械語に変換する役割を担っています。src/cmd/gc ディレクトリには、このコンパイラの主要な部分が含まれています。コンパイラは、字句解析、構文解析、意味解析、中間コード生成、最適化、コード生成といった複数のフェーズを経て動作します。
Bison (Yacc)
Bisonは、GNUプロジェクトが開発しているパーサジェネレータであり、Yacc (Yet Another Compiler Compiler) のGNU版です。Bisonは、BNF (Backus-Naur Form) に似た形式で記述された文法定義ファイル(通常 .y 拡張子を持つ)を読み込み、その文法を解析するためのC言語のソースコード(パーサ)を生成します。
- 文法ファイル (
.y): 構文規則と、各規則が認識されたときに実行されるC言語のコード(セマンティックアクション)を記述します。 %unionディレクティブ: Bisonにおいて非常に重要なディレクティブです。パーサが扱うトークンや非終端記号の「セマンティック値」(意味的な値)を格納するためのC言語のunion型を定義します。デフォルトでは、Bisonはセマンティック値をint型として扱いますが、%unionを使うことで、整数、文字列、ポインタ、構造体など、様々な型の値を扱えるようになります。%unionで定義されたunion型は、通常YYSTYPEという名前で生成されます。%token <member_name>: トークン(字句解析器が生成する最小単位)に、%unionで定義されたどのメンバーをセマンティック値として関連付けるかを指定します。%type <member_name>: 非終端記号(文法規則の左辺に現れる記号)に、%unionで定義されたどのメンバーをセマンティック値として関連付けるかを指定します。
Lex (Flex)
Lexは、字句解析器(レクサー、スキャナーとも呼ばれる)を生成するためのツールです。Flex (Fast Lexical Analyzer) はLexのGNU版です。Lexは、正規表現に似た形式で記述された規則ファイル(通常 .l 拡張子を持つ)を読み込み、入力ストリームからトークンを識別するためのC言語のソースコード(字句解析器)を生成します。
yylval: Lexによって生成される字句解析器とBisonによって生成される構文解析器の間で、トークンのセマンティック値をやり取りするためのグローバル変数です。yylvalの型は、Bisonの%unionディレクティブによって定義されたYYSTYPEになります。字句解析器は、認識したトークンのセマンティック値をyylvalに格納し、構文解析器はそれを取り出して利用します。
#define プリプロセッサディレクティブ
C言語における #define は、プリプロセッサディレクティブの一つで、マクロを定義するために使用されます。プリプロセッサは、コンパイルの前にソースコードを走査し、定義されたマクロ名をその定義内容で置換します。例えば、#define PI 3.14159 と定義されていれば、ソースコード中の PI はすべて 3.14159 に置換されます。この置換は単純なテキスト置換であり、C言語の構文解析よりも前に行われます。
今回のケースでは、Bisonが内部的に #define lint ... のようなマクロを定義している可能性があり、これが union のフィールド名 lint と衝突したと考えられます。
技術的詳細
このコミットの技術的な核心は、Bisonパーサジェネレータの内部的な動作と、C言語のプリプロセッサによるマクロ展開の相互作用にあります。
-
%unionの役割とフィールド名:%unionディレクティブは、パーサのセマンティック値を保持するためのunion型を定義します。このunionの各フィールドは、異なる種類のセマンティック値を表します。例えば、int lint;は整数型のセマンティック値をlintという名前で参照できるようにします。Bisonは、この%unionの定義に基づいてYYSTYPEという名前のC言語のunion型を生成します。 -
lintフィールド名とBisonの衝突: コミットメッセージが示唆するように、Bisonは内部的にlintという名前を特別な目的で使用している可能性があります。これは、Bisonが生成するCコード内でlintという名前のマクロ(例:#define lint some_value)を定義しているか、あるいは特定のコンパイル環境やリンティングツールとの互換性のためにlintという識別子を予約しているかのいずれかです。 もしBisonが#define lintを行っている場合、go.yファイルがBisonによって処理され、その結果生成されるCコードがCプリプロセッサによって処理される際に問題が発生します。具体的には、%union内で定義されたint lint;という行が、プリプロセッサによってlintのマクロ定義内容で置換されてしまい、結果としてunionのメンバー定義として不正なCコードが生成されることになります。これは、コンパイルエラーや、最悪の場合、意図しない動作を引き起こす可能性があります。 -
LASOPトークンとlbrace,import_here型:go.yファイルの変更箇所を見ると、LASOPというトークンと、lbraceおよびimport_hereという非終端記号(または型)が、以前はlintフィールドをセマンティック値として使用するように指定されていました(例:%token <lint> LASOP)。これは、これらの要素が整数型のセマンティック値を持つことを意味します。衝突を避けるため、これらの参照も新しいフィールド名iに変更されました。 -
lex.cにおけるyylval.lintの使用:lex.cは字句解析器のC言語ソースファイルであり、yylvalグローバル変数を通じてトークンのセマンティック値を構文解析器に渡します。yylval.lint = c;という行は、字句解析器が認識した文字cをLASOPトークンのセマンティック値としてyylvalのlintフィールドに格納していることを示しています。%unionのフィールド名が変更されたため、この字句解析器側のコードもyylval.i = c;に更新する必要がありました。これにより、字句解析器と構文解析器の間でセマンティック値の受け渡しが正しく行われるようになります。
この変更は、GoコンパイラのビルドシステムがBisonとCプリプロセッサをどのように連携させているかを考慮した、低レベルながらも重要な修正です。特定の識別子がツールチェーンの異なるレイヤーで衝突する可能性を考慮し、堅牢なコンパイラを構築するためのベストプラクティスを示しています。
コアとなるコードの変更箇所
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -31,13 +31,13 @@ static void fixlbrace(int);\n Type* type;\n Sym* sym;\n struct Val val;\n-\tint lint;\n+\tint i;\n }\n \n // |sed 's/.* //' |9 fmt -l1 |sort |9 fmt -l50 | sed 's/^/%xxx /'\n \n %token <val> LLITERAL\n-%token <lint> LASOP\n+%token <i> LASOP\n %token <sym> LBREAK LCASE LCHAN LCOLAS LCONST LCONTINUE LDDD\n %token <sym> LDEFAULT LDEFER LELSE LFALL LFOR LFUNC LGO LGOTO\n %token <sym> LIF LIMPORT LINTERFACE LMAP LNAME\n@@ -47,7 +47,7 @@ static void fixlbrace(int);\n %token LANDAND LANDNOT LBODY LCOMM LDEC LEQ LGE LGT\n %token LIGNORE LINC LLE LLSH LLT LNE LOROR LRSH\n \n-%type <lint> lbrace import_here\n+%type <i> lbrace import_here\n %type <sym> sym packname\n %type <val>\toliteral\n \ndiff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index cf7bbae9ed..3dbd6dda1a 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -1098,7 +1098,7 @@ lx:
return c;
asop:
-\tyylval.lint = c; // rathole to hold which asop
+\tyylval.i = c; // rathole to hold which asop
DBG("lex: TOKEN ASOP %c\n", c);
return LASOP;
コアとなるコードの解説
src/cmd/gc/go.y の変更
このファイルはGoコンパイラの構文解析器の文法定義です。Bisonによって処理されます。
-
%unionディレクティブ内の変更:- int lint; + int i;%unionブロック内で定義されていたlintという名前のint型フィールドがiに変更されました。これにより、Bisonが生成するYYSTYPEunion型のメンバー名がlintからiに変わります。 -
%tokenディレクティブの変更:-%token <lint> LASOP +%token <i> LASOPLASOPというトークン(おそらく "assignment operator" の略)のセマンティック値が、以前は%unionのlintフィールドに関連付けられていましたが、新しいiフィールドに関連付けられるように変更されました。 -
%typeディレクティブの変更:-%type <lint> lbrace import_here +%type <i> lbrace import_herelbraceとimport_hereという非終端記号(または型)のセマンティック値も、同様に%unionのlintフィールドからiフィールドに関連付けられるように変更されました。
src/cmd/gc/lex.c の変更
このファイルはGoコンパイラの字句解析器のC言語ソースコードです。
yylvalのフィールド参照の変更:
字句解析器が- yylval.lint = c; // rathole to hold which asop + yylval.i = c; // rathole to hold which asopLASOPトークンを認識した際に、そのセマンティック値をyylvalグローバル変数に格納する箇所です。%unionのフィールド名がlintからiに変更されたため、yylvalの参照もyylval.lintからyylval.iに更新されました。コメントの「rathole to hold which asop」は、このフィールドがどの代入演算子であるかを保持するための一時的な場所であることを示唆しています。
これらの変更は一貫しており、%union のフィールド名変更に伴う影響範囲全体をカバーしています。
関連リンク
- Go Gerrit Code Review: https://golang.org/cl/5462044
参考にした情報源リンク
- Bison Manual - The Union Declaration: https://www.gnu.org/software/bison/manual/html_node/Union-Declaration.html
- Bison Manual - Semantic Values: https://www.gnu.org/software/bison/manual/html_node/Semantic-Values.html
- Flex Manual - yylval: https://flex.sourceforge.io/manual/yylval.html
- C Preprocessor Directives:
#define: (一般的なC言語のプリプロセッサに関する情報源)