[インデックス 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が生成するYYSTYPE
union
型のメンバー名がlint
からi
に変わります。 -
%token
ディレクティブの変更:-%token <lint> LASOP +%token <i> LASOP
LASOP
というトークン(おそらく "assignment operator" の略)のセマンティック値が、以前は%union
のlint
フィールドに関連付けられていましたが、新しいi
フィールドに関連付けられるように変更されました。 -
%type
ディレクティブの変更:-%type <lint> lbrace import_here +%type <i> lbrace import_here
lbrace
と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 asop
LASOP
トークンを認識した際に、そのセマンティック値を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言語のプリプロセッサに関する情報源)