[インデックス 1026] ファイルの概要
このコミットは、Go言語の初期コンパイラ(gc
)において、可変長引数(variadic arguments)を表す...
(ドット3つ)構文の内部的な処理を導入するものです。具体的には、パーサーが...
を認識し、コンパイラの型システムでそれを表現するための変更が含まれています。
コミット
- コミットハッシュ:
2fef4c7198e7d3215cbc14e530e1e08cbed3888d
- 作者: Ken Thompson ken@golang.org
- 日付: 2008年11月1日 土曜日 16:52:12 -0700
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/2fef4c7198e7d3215cbc14e530e1e08cbed3888d
元コミット内容
DOTDOTDOT import/export
R=r
OCL=18319
CL=18319
変更の背景
Go言語には、関数が可変個の引数を受け取ることができる「可変長引数(variadic arguments)」という機能があります。これは、関数定義の最後のパラメータの型名の前に...
を付けることで実現されます(例: func sum(nums ...int)
)。このコミットは、Go言語の初期段階において、この...
構文をコンパイラが正しく解析し、内部的に型として扱うための基盤を導入するものです。
Goコンパイラは、ソースコードを機械語に変換する過程で、まず字句解析(lexical analysis)と構文解析(parsing)を行います。この段階で、...
という特殊な記号を認識し、それをコンパイラ内部で扱える形式に変換する必要があります。このコミットは、そのためのパーサーのルール追加と、内部的な型定義の追加を行っています。
前提知識の解説
1. コンパイラの基本構造
コンパイラは、ソースコードを読み込み、それを実行可能な形式(機械語など)に変換するソフトウェアです。一般的なコンパイラは、以下の主要なフェーズで構成されます。
- 字句解析(Lexical Analysis): ソースコードをトークン(意味を持つ最小単位、例: 識別子、キーワード、演算子)の並びに分解します。
- 構文解析(Syntax Analysis): トークンの並びが言語の文法規則に合致するかを検証し、抽象構文木(AST: Abstract Syntax Tree)を構築します。ASTは、プログラムの構造を木構造で表現したものです。
- 意味解析(Semantic Analysis): ASTを走査し、型チェックや変数宣言の確認など、意味的な正当性を検証します。
- 中間コード生成(Intermediate Code Generation): ASTから、特定の機械に依存しない中間表現を生成します。
- コード最適化(Code Optimization): 中間コードをより効率的な形に変換します。
- コード生成(Code Generation): 中間コードから、ターゲットとなる機械語を生成します。
2. Yacc/Bisonとgo.y
- Yacc (Yet Another Compiler Compiler) および Bison (GNU Parser Generator): これらは、文法定義ファイルからパーサー(構文解析器)のソースコードを自動生成するツールです。文法規則をBNF(Backus-Naur Form)のような形式で記述することで、複雑な構文解析ロジックを手書きする手間を省きます。
go.y
: Go言語の初期コンパイラgc
において、go.y
ファイルはGo言語の文法規則をYacc形式で記述したものです。このファイルは、Goソースコードの構文解析を担当するパーサーを生成するために使用されます。go.y
内のルールは、特定のトークン列(例:LDDD
)がどのように解釈され、ASTのどのノードに対応するかを定義します。
3. 可変長引数(Variadic Arguments)
Go言語における可変長引数は、関数が任意の数の引数を受け取れるようにする機能です。
例: func printArgs(args ...interface{})
この関数は、printArgs(1, "hello", true)
のように任意の数の引数で呼び出すことができます。関数内部では、args
はスライス([]interface{}
)として扱われます。
4. gc
コンパイラ
Go言語の初期の公式コンパイラはgc
(Go Compiler)と呼ばれ、C言語で実装されていました。このコミットは、そのgc
コンパイラのソースコードに対する変更です。
技術的詳細
このコミットは、Go言語の可変長引数構文...
をコンパイラが認識し、内部的に処理するための2つの主要な変更を導入しています。
1. src/cmd/gc/go.y
におけるパーサーの拡張
go.y
はGo言語の文法定義ファイルであり、パーサーの動作を規定します。この変更では、hidden_type1
という文法規則にLDDD
という新しいトークンを追加しています。
LDDD
: これは、字句解析器(lexer)によって認識される...
(ドット3つ)という記号に対応するトークン名であると推測されます。パーサーは、このLDDD
トークンを検出すると、それに続くアクションを実行します。$$ = typ(TDDD);
:LDDD
トークンが検出された場合、パーサーはTDDD
という内部的な型を表すオブジェクトを生成し、それを現在の構文規則のセマンティック値($$
)として設定します。これは、AST内で...
構文が特定の型として表現されることを意味します。
この変更により、コンパイラのフロントエンド(パーサー)は、Goソースコード内の...
構文を正しく識別し、その存在を抽象構文木に反映できるようになります。
2. src/cmd/gc/subr.c
における内部型定義の追加
subr.c
は、Goコンパイラのバックエンドの一部であり、様々なユーティリティ関数や内部的なデータ構造の定義を含んでいます。この変更では、basicnames
という配列にTDDD
という新しい型を追加しています。
[TDDD] = "..."
: これは、コンパイラ内部でTDDD
という定数(おそらく列挙型の一部)が、Go言語の...
構文に対応する型であることを示しています。basicnames
配列は、内部的な型定数とその文字列表現をマッピングするために使用されることが多いです。これにより、コンパイラの他の部分(例えば、型チェックやコード生成フェーズ)がTDDD
を認識し、可変長引数に関連する処理を行うための参照点が得られます。
これらの変更は、Go言語の可変長引数機能がコンパイラによってどのように扱われるかの初期段階を示しています。LDDD
はパーサーが認識するトークン、TDDD
はそのトークンが表す内部的な型表現として機能します。
コアとなるコードの変更箇所
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index cb802025a9..0fbe0c1739 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -1871,6 +1871,10 @@ hidden_type1:
$$->type = $3;
$$->chan = Csend;
}\n+|\tLDDD
+\t{\n+\t\t$$ = typ(TDDD);\n+\t}\n hidden_type2:
LCHAN hidden_type
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index c0344a9899..9da4738292 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -968,6 +968,7 @@ basicnames[] =\n [TFLOAT80]\t= "float80",\n [TBOOL]\t\t= "bool",\n [TANY]\t\t= "any",\n+\t[TDDD]\t\t= "...",\n };
int
コアとなるコードの解説
src/cmd/gc/go.y
の変更
@@ -1871,6 +1871,10 @@ hidden_type1:
$$->type = $3;
$$->chan = Csend;
}\n+|\tLDDD
+\t{\n+\t\t$$ = typ(TDDD);\n+\t}\n hidden_type2:
LCHAN hidden_type
hidden_type1:
: これはYaccの文法規則の一部で、特定の型の定義に関連するものです。|\tLDDD
: これは、hidden_type1
が既存の定義に加えて、LDDD
というトークンも受け入れることを示しています。LDDD
は、Go言語の...
構文に対応する字句解析器によって生成されるトークンです。{\n+\t\t$$ = typ(TDDD);\n+\t}
: これは、LDDD
トークンが検出されたときに実行されるアクションです。$$
: Yaccにおいて、現在の規則のセマンティック値を表します。typ(TDDD)
:TDDD
という内部的な型定数に対応する型オブジェクトを生成する関数呼び出しです。- この行は、パーサーが
...
構文を認識した際に、その構文をコンパイラ内部でTDDD
という特殊な型として表現するように指示しています。これにより、抽象構文木(AST)上で...
が型情報として扱われるようになります。
src/cmd/gc/subr.c
の変更
@@ -968,6 +968,7 @@ basicnames[] =\n [TFLOAT80]\t= "float80",\n [TBOOL]\t\t= "bool",\n [TANY]\t\t= "any",\n+\t[TDDD]\t\t= "...",\n };
int
basicnames[] = { ... }
: この配列は、コンパイラ内部の基本的な型定数とその文字列表現をマッピングするために使用されます。[TDDD]\t\t= "...",
: この行は、TDDD
という内部的な型定数(おそらく列挙型の一部)が、Go言語の...
という文字列に対応することを定義しています。これにより、コンパイラの他の部分がTDDD
を認識し、可変長引数に関連する処理(例えば、エラーメッセージの生成やデバッグ情報の表示など)を行う際に、その意味を正しく解釈できるようになります。
これらの変更は、Go言語の可変長引数機能のコンパイラサポートの初期段階であり、パーサーが...
を認識し、それを内部的な型システムに統合するための重要なステップです。
関連リンク
- Go言語の可変長引数に関する公式ドキュメント: https://go.dev/tour/moretypes/12
- Go言語のコンパイラ設計に関する一般的な情報: https://go.dev/doc/articles/go_compiler.html
参考にした情報源リンク
- Go言語の可変長引数に関する解説記事:
- Yacc/BisonとGoコンパイラに関する情報:
- https://golangbridge.org/ (Yacc/Bisonの一般的な役割について言及)
- https://github.com/golang/go/blob/master/src/cmd/go/internal/modcmd/edit.go (Go言語のソースコード構造の例)
- Goコンパイラの初期のソースコード(
subr.c
のC言語の可変長引数実装について言及): https://go.googlesource.com/go/+/refs/heads/master/src/cmd/gc/subr.c - Go言語のツアー: https://go.dev/tour/moretypes/12
- Goコンパイラの記事: https://go.dev/doc/articles/go_compiler.html
- Go言語の
go.y
ファイルに関する情報: https://github.com/golang/go/blob/master/src/cmd/compile/internal/syntax/syntax.go (現代のGoコンパイラの構文解析に関するファイル構造の例)