[インデックス 1699] ファイルの概要
このコミットは、Go言語の公式リファレンスドキュメントである doc/go_ref.html
ファイルに対して行われたものです。具体的には、Go言語の字句解析(lexical analysis)に関するセクションを完成させることを目的としています。これにより、Go言語のソースコードがどのようにトークンに分割されるかという基本的なルールが詳細に定義されました。
コミット
commit 3d50b1e0e890f04b77ddcd4b00e60c83dbf68760
Author: Rob Pike <r@golang.org>
Date: Thu Feb 19 16:20:00 2009 -0800
Finish the lexical section.
DELTA=176 (172 added, 0 deleted, 4 changed)
OCL=25182
CL=25222
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/3d50b1e0e890f04b77ddcd4b00e60c83dbf68760
元コミット内容
このコミットの元々の内容は、Go言語のリファレンスドキュメント doc/go_ref.html
において、言語の字句構造に関する記述を完成させることです。具体的には、以下の要素に関する詳細な定義とEBNF(Extended Backus-Naur Form)による構文規則が追加されています。
- Notation (表記法): EBNFの記法とその演算子(
|
,()
,[]
,{}
)の説明。 - Identifiers (識別子): 識別子の定義、
letter
およびidentifier
のEBNF規則。 - Integer literals (整数リテラル): 10進数、8進数、16進数の整数リテラルの定義とEBNF規則。
- Floating-point literals (浮動小数点リテラル): 浮動小数点リテラルの定義とEBNF規則。
- Character literals (文字リテラル): 文字リテラルの定義、Unicodeコードポイント、バックスラッシュエスケープシーケンス(
\a
,\b
,\f
,\n
,\r
,\t
,\v
,\\
,\'
,\"
)、および数値エスケープ(\x
,\u
,\U
, 8進数)に関する詳細な説明とEBNF規則。 - String literals (文字列リテラル): 生文字列リテラル(raw string literals)と解釈済み文字列リテラル(interpreted string literals)の定義、バックスラッシュエスケープの解釈、およびEBNF規則。また、隣接する文字列リテラルの結合についても言及されています。
このコミットにより、Go言語の字句構造がより明確に、かつ形式的に定義されました。
変更の背景
このコミットは、Go言語がまだ開発の初期段階にあった2009年に行われました。Go言語は、Googleによって開発されたプログラミング言語であり、その設計目標の一つに「シンプルさ」と「明確さ」がありました。言語の仕様を明確に定義することは、コンパイラの実装、ツールの開発、そして開発者コミュニティが言語を正確に理解し、利用するために不可欠です。
「Finish the lexical section.」というコミットメッセージが示すように、この変更はGo言語の公式リファレンスドキュメントにおいて、言語の最も基本的な構成要素である「字句(lexical elements)」の定義を完成させることを目的としていました。字句は、ソースコードをコンパイラが理解できる最小単位(トークン)に分割するための規則を定めます。これには、識別子、キーワード、演算子、区切り文字、リテラル(数値、文字、文字列)などが含まれます。
この時期に字句セクションを完成させることは、Go言語のコンパイラやその他の開発ツールの安定化、そして言語仕様の一般公開に向けた重要なステップであったと考えられます。正確な字句規則が定義されることで、異なる環境やツール間でのGoコードの解釈の一貫性が保証されます。
前提知識の解説
このコミットの変更内容を理解するためには、以下の前提知識が役立ちます。
1. 字句解析 (Lexical Analysis) とトークン (Token)
コンパイラやインタプリタがソースコードを処理する最初の段階を「字句解析」と呼びます。字句解析器(レキサーまたはスキャナー)は、ソースコードの文字列を読み込み、意味のある最小単位である「トークン」の並びに変換します。
- トークン: プログラミング言語における意味を持つ最小単位です。例えば、
int x = 10;
というコードでは、int
(キーワード)、x
(識別子)、=
(演算子)、10
(整数リテラル)、;
(区切り文字)がそれぞれトークンになります。 - 字句規則: どのような文字の並びがどのような種類のトークンになるかを定義する規則です。
2. 拡張バッカス・ナウア記法 (Extended Backus-Naur Form, EBNF)
EBNFは、プログラミング言語の構文を形式的に記述するためのメタ言語です。このコミットでもGo言語の字句規則を記述するために使用されています。EBNFの基本的な記法は以下の通りです。
=
: 定義。左辺の非終端記号が右辺の規則で定義されることを示します。|
: 選択。複数の選択肢のうちいずれか一つを意味します。()
: グループ化。複数の要素をまとめて一つの単位として扱います。[]
: オプション。括弧内の要素が0回または1回出現することを示します。{}
: 繰り返し。括弧内の要素が0回以上繰り返されることを示します。""
または''
: 終端記号(リテラル)。引用符で囲まれた文字や文字列は、そのままの形で出現することを意味します。...
: 範囲。例えば0 ... 9
は0から9までの数字のいずれかを意味します。
3. UnicodeとUTF-8
Go言語はUnicodeを完全にサポートしており、ソースコードはUTF-8でエンコードされます。
- Unicode: 世界中の文字を統一的に扱うための文字コード標準です。各文字には一意の「コードポイント」(例: U+0061は'a')が割り当てられています。
- UTF-8: Unicode文字をバイト列にエンコードするための可変長エンコーディング方式です。ASCII文字は1バイトで表現され、他の多くの文字は2バイト以上で表現されます。
文字リテラルや文字列リテラルのセクションでは、UnicodeコードポイントとUTF-8エンコーディングの概念が重要になります。特に、文字リテラルが単一のUnicodeコードポイントを表すのに対し、文字列リテラルはUTF-8エンコードされたバイト列のシーケンスとして扱われる点が重要です。
4. 理想的な整数 (Ideal Integers) と理想的な浮動小数点数 (Ideal Floats)
Go言語の数値リテラル(整数リテラル、浮動小数点リテラル)は、コンパイル時に型が決定されるまで「理想的な」値として扱われます。これは、リテラルが特定のビット幅や精度に縛られず、可能な限り高い精度で表現されることを意味します。例えば、1000000000000000000000000000000000
のような非常に大きな整数リテラルも、それが変数に代入されるか、演算に使われるまで、オーバーフローすることなく「理想的な整数」として扱われます。これにより、コンパイル時の型推論や定数式の評価において柔軟性が高まります。
技術的詳細
このコミットで追加された技術的詳細は、Go言語の字句構造を厳密に定義するものです。
EBNFによる構文定義の導入
doc/go_ref.html
の冒頭にEBNFの記法が導入され、その後の字句規則がこの形式で記述されるようになりました。これにより、言語仕様の記述がより形式的かつ明確になり、曖昧さが排除されます。
識別子の定義
識別子(変数名、関数名など)の規則が明確化されました。
letter = unicode_letter | "_" .
identifier = letter { letter | unicode_digit } .
これは、識別子がUnicode文字またはアンダースコアで始まり、その後にUnicode文字またはUnicode数字が続くことを意味します。ただし、当時の実装ではASCII数字のみを許容していたという注意書き(赤字)があり、これは初期のGo言語がまだUnicodeの完全なサポートに向けて進化中であったことを示唆しています。
数値リテラルの詳細な定義
整数リテラルと浮動小数点リテラルについて、その形式とEBNF規則が詳細に定義されました。
- 整数リテラル: 10進数、8進数(
0
プレフィックス)、16進数(0x
または0X
プレフィックス)の形式が定義されています。int_lit = decimal_lit | octal_lit | hex_lit .
decimal_lit = ( "1" ... "9" ) { decimal_digit } .
octal_lit = "0" { octal_digit } .
hex_lit = "0" ( "x" | "X" ) hex_digit { hex_digit } .
decimal_digit = "0" ... "9" .
octal_digit = "0" ... "7" .
hex_digit = "0" ... "9" | "A" ... "F" | "a" ... "f" .
- 浮動小数点リテラル: 整数部、小数点、小数部、指数部から構成される形式が定義されています。
float_lit = decimals "." [ decimals ] [ exponent ] | decimals exponent | "." decimals [ exponent ] .
decimals = decimal_digit { decimal_digit } .
exponent = ( "e" | "E" ) [ "+" | "-" ] decimals .
これらのリテラルは「理想的な整数」または「理想的な浮動小数点数」として扱われ、型推論の柔軟性を提供します。
文字リテラルと文字列リテラルの詳細な定義とエスケープシーケンス
Go言語の文字リテラルと文字列リテラルは、UnicodeとUTF-8の特性を強く反映しています。
- 文字リテラル: 単一引用符で囲まれ、単一のUnicodeコードポイントを表します。バックスラッシュエスケープ(
\n
,\t
など)や数値エスケープ(\xHH
,\uHHHH
,\UHHHHHHHH
, 8進数)が詳細に定義されています。特に、\u
と\U
はUnicodeコードポイントを表し、\x
と8進数エスケープはバイト値を表す点が重要です。char_lit = "'" ( unicode_value | byte_value ) "'" .
unicode_value = unicode_char | little_u_value | big_u_value | escaped_char .
byte_value = octal_byte_value | hex_byte_value .
- 文字列リテラル:
- 生文字列リテラル (Raw string literals): バッククォート
`
で囲まれ、内部の文字はそのままのバイト列として解釈されます。エスケープシーケンスは処理されません。raw_string_lit = "
" { unicode_char } "" .
- 解釈済み文字列リテラル (Interpreted string literals): 二重引用符
""
で囲まれ、文字リテラルと同様にバックスラッシュエスケープが解釈されます。ここで重要なのは、3桁の8進数エスケープ(\000
)と2桁の16進数エスケープ(\x00
)が結果の文字列の個々のバイトを表すのに対し、他のエスケープ(\u
,\U
など)は個々の文字(UTF-8エンコードされた複数バイトになる可能性あり)を表すという点です。interpreted_string_lit = """ { unicode_value | byte_value } """ .
また、隣接する文字列リテラルが暗黙的に結合される規則も定義されています。
- 生文字列リテラル (Raw string literals): バッククォート
StringLit = string_lit { string_lit } .
これらの詳細な定義は、Go言語のコンパイラがソースコードを正確に解析し、開発者が意図した通りのプログラムを構築するための基盤となります。
コアとなるコードの変更箇所
このコミットのコアとなる変更箇所は、doc/go_ref.html
ファイルへの追加と修正です。
--- a/doc/go_ref.html
+++ b/doc/go_ref.html
@@ -13,6 +13,47 @@ Go is a general-purpose language designed with systems programming in mind. It i
The grammar is simple and regular, allowing for easy analysis by automatic tools such as integrated development environments.
</p>
+<h2>Notation</h2>
+
+<p>
+The syntax is specified using Extended Backus-Naur Form (EBNF):
+</p>
+
+<pre>
+Production = production_name "=" Expression .
+Expression = Alternative { "|" Alternative } .
+Alternative = Term { Term } .
+Term = production_name | token [ "..." token ] | Group | Option | Repetition .
+Group = "(" Expression ")" .
+Option = "[" Expression ")" .
+Repetition = "{" Expression "}" .
+</pre>
+
+<p>
+Productions are expressions constructed from terms and the following operators, in increasing precedence:
+</p>
+<pre>
+| alternation
+() grouping
+[] option (0 or 1 times)
+{} repetition (0 to n times)
+</pre>
+
+<p>
+Lower-case production names are used to identify lexical tokens. Non-terminals are in CamelCase. Lexical symbols are enclosed in double quotes <tt>""</tt> (the
+double quote symbol is written as <tt>'"'</tt>).
+</p>
+
+<p>
+The form <tt>"a ... b"</tt> represents the set of characters from <tt>a</tt> through <tt>b</tt> as alternatives.
+</p>
+
+<p>
+Where possible, recursive productions are used to express evaluation order
+and operator precedence syntactically.
+</p>
+
+
<h2>Lexical properties</h2>
<p>
@@ -43,9 +84,14 @@ There are two forms of comments. The first starts at a the character sequence <
<h3>Identifiers</h3>
<p>
-An identifier is a sequence of one or more letters and digits. The meaning of <i>letter</i> and <i>digit</i> is defined by the Unicode properties for the corresponding characters, with the addition that the underscore character <tt>_</tt> (U+005F) is considered a letter. The first character in an identifier must be a letter. <font color=red>(Current implementation accepts only ASCII digits for digits.)</font>
+An identifier is a sequence of one or more letters and digits. The meaning of <i>letter</i> and <i>digit</i> is defined by the Unicode properties for the corresponding characters, with the addition that the underscore character <tt>_</tt> (U+005F) is considered a letter. The first character in an identifier must be a letter.
</p>
+<pre>
+letter = unicode_letter | "_" .
+identifier = letter { letter | unicode_digit } .
+</pre>
+
<h3>Keywords</h3>
<p>
@@ -76,13 +122,139 @@ The following character sequences are tokens representing operators, delimiters,
<h4>Integer literals</h4>
+<p>
+An integer literal is a sequence of one or more digits in the corresponding base, which may be 8, 10, or 16. An optional prefix sets a non-decimal base: <tt>0</tt> for octal, <tt>0x</tt> or <tt>0X</tt> for hexadecimal. In hexadecimal literals, letters <tt>a-f</tt> and <tt>A-F</tt> represent values 10 through 15.
+</p>
+<pre>
+int_lit = decimal_lit | octal_lit | hex_lit .
+decimal_lit = ( "1" ... "9" ) { decimal_digit } .
+octal_lit = "0" { octal_digit } .
+hex_lit = "0" ( "x" | "X" ) hex_digit { hex_digit } .
+decimal_digit = "0" ... "9" .
+octal_digit = "0" ... "7" .
+hex_digit = "0" ... "9" | "A" ... "F" | "a" ... "f" .
+</pre>
+
+<p>
+Integer literals represent values of arbitrary precision, or <i>ideal integers</i>; they have no implicit size or type.
+</p>
+
<h4>Floating-point literals</h4>
+<p>
+A floating-point literal is a decimal representation of a floating-point number. It has an integer part, a decimal point, a fractional part, and an exponent part. The integer and fractional part comprise decimal digits; the exponent part is an <tt>e</TT> or <tt>E</tt> followed by an optionally signed decimal exponent. One of the integer part or the fractional part may be elided; one of the decimal point or the exponent may be elided.
+</p>
+<pre>
+float_lit = decimals "." [ decimals ] [ exponent ] |
+ decimals exponent |
+ "." decimals [ exponent ] .
+decimals = decimal_digit { decimal_digit } .
+exponent = ( "e" | "E" ) [ "+" | "-" ] decimals .
+</pre>
+
+<p>
+As with integers, floating-point literals represent values of arbitrary precision, or <i>ideal floats</i>.
+</p>
<h4>Character literals</h4>
+<p>
+A character literal represents an integer value, typically a Unicode code point, as one or more characters enclosed in single quotes. Within the quotes, any character may appear except single quote and newline; a quoted single character represents itself, while multi-character sequences beginning with a backslash encode values in various formats.
+</p>
+<p>
+The simplest form represents the exact character within the quotes; since Go source text is Unicode characters encoded in UTF-8, multiple UTF-8-encoded bytes may represent a single integer value. For instance, the literal <tt>'a'</tt> holds a single byte representing a literal <tt>a</tt>, Unicode U+0061, value <tt>0x61</tt>, while <tt>'ä'</tt> holds two bytes (<tt>0xc3</tt> <tt>0xa4</tt>) representing a literal <tt>a</tt>-dieresis, U+00E4, value <tt>0xe4</tt>.
+</p>
+<p>
+Several backslash escapes allow arbitrary values to be represented as ASCII text. There are four ways to represent the integer value as a numeric constant: <tt>\x</tt> followed by exactly two hexadecimal digits; <tt>\u</tt> followed by exactly four hexadecimal digits; <tt>\U</tt> followed by exactly eight hexadecimal digits, and a plain backslash <tt>\</tt> followed by exactly three octal digits. In each case the value of the literal is the value represented by the digits in the appropriate base.
+</p>
+<p>
+Although these representations all result in an integer, they have different valid ranges. Octal escapes must represent a value between 0 and 255 inclusive. (Hexadecimal escapes satisfy this condition by construction). The `Unicode\' escapes <tt>\u</tt> and <tt>\U</tt> represent Unicode code points so within them some values are illegal, in particular those above <tt>0x10FFFF</tt> and surrogate halves.
+</p>
+<p>
+After a backslash, certain single-character escapes represent special values:
+</p>
+<pre>
+\a U+0007 alert or bell
+\b U+0008 backspace
+\f U+000C form feed
+\n U+000A line feed or newline
+\r U+000D carriage return
+\t U+0009 horizontal tab
+\v U+000b vertical tab
+\\ U+005c backslash
+\' U+0027 single quote (legal within character literals only)
+\" U+0022 double quote (legal within interpreted string literals only)
+</pre>
+<p>
+All other sequences are illegal inside character literals.
+</p>
+<pre>
+char_lit = "'" ( unicode_value | byte_value ) "'" .
+unicode_value = unicode_char | little_u_value | big_u_value | escaped_char .
+byte_value = octal_byte_value | hex_byte_value .
+octal_byte_value = "\" octal_digit octal_digit octal_digit .
+hex_byte_value = "\" "x" hex_digit hex_digit .
+little_u_value = "\" "u" hex_digit hex_digit hex_digit hex_digit .
+big_u_value = "\" "U" hex_digit hex_digit hex_digit hex_digit
+ hex_digit hex_digit hex_digit hex_digit .
+escaped_char = "\" ( "a" | "b" | "f" | "n" | "r" | "t" | "v" | "\" | "'" | """ ) .
+</pre>
+
+<p>
+The value of a character literal is an ideal integer, just as with integer literals.
+</p>
+
<h4>String literals</h4>
+<p>
+String literals represent constant values of type <tt>string</tt>. There are two forms: raw string literals and interpreted string literals.
+</p>
+<p>
+Raw string literals are character sequences between back quotes <tt>``</tt>. Within the quotes, any character is legal except newline and back quote. The value of a raw string literal is the string composed of the uninterpreted bytes between the quotes.
+</p>
+<p>
+Interpreted string literals are character sequences between double quotes <tt>""</tt>. The text between the quotes forms the value of the literal, with backslash escapes interpreted as they are in character literals. The three-digit octal (<tt>\000</tt>) and two-digit hexadecimal (<tt>\x00</tt>) escapes represent individual <i>bytes</i> of the resulting string; all other escapes represent the (possibly multi-byte) UTF-8 encoding of individual <i>characters</i>. Thus inside a string literal <tt>\377</tt> and <tt>\xFF</tt> represent a single byte of value <tt>0xFF</tt>=255, while <tt>ÿ</tt>, <tt>\u00FF</tt>, <tt>\U000000FF</tt> and <tt>\xc3\xbf</tt> represent the two bytes <tt>0xc3 0xbf</tt> of the UTF-8 encoding of character U+00FF.
+</p>
+<pre>
+string_lit = raw_string_lit | interpreted_string_lit .
+raw_string_lit = "`" { unicode_char } "`" .
+interpreted_string_lit = """ { unicode_value | byte_value } """ .
+</pre>
+
+<p>
+During tokenization, two adjacent string literals separated only by the empty string, white space, or comments are implicitly combined into a single string literal whose value is the concatenated values of the literals.
+</p>
+<pre>
+StringLit = string_lit { string_lit } .
+</pre>
+
+<h2>Everything else</h2>
+
+<p>
+I don't believe this organization is complete or correct but it's here to be worked on and thought about.
+</p>
+
+<h2>Types</h2>
+
+<h2>Constants</h2>
+
+<h2>Expressions</h2>
+
+<h2>Declarations</h2>
+
+<h2>Control Structures</h2>
+
+<h2>Program structure</h2>
+
+<h2>Packages</h2>
+
+<h2>Differences between this doc and implementation - TODO</h2>
+<p>
+<font color=red>
+Current implementation accepts only ASCII digits for digits; doc says Unicode.
+<br>
+</font>
+</p>
</div>
<br class="clearboth" />
この差分は、doc/go_ref.html
ファイルに大量の新しいHTMLコンテンツが追加されていることを示しています。具体的には、EBNFの表記法、識別子、数値リテラル、文字リテラル、文字列リテラルの詳細な定義とEBNF規則が追加されています。既存の「Identifiers」セクションには、EBNF規則が追加され、ASCII数字のみを許容するという実装上の注意書きが削除されています(ただし、TODOセクションに同様の注意書きが移動しています)。
コアとなるコードの解説
このコミットは、Go言語のコンパイラやツールがソースコードを正しく解釈するための基盤となる「字句規則」を、公式ドキュメントに明文化したものです。
- EBNFの導入: 言語仕様を形式的に記述するための標準的な方法であるEBNFを導入することで、Go言語の構文定義の厳密性と明確性が大幅に向上しました。これにより、人間が仕様を理解しやすくなるだけでなく、自動ツール(パーサー生成器など)が仕様から直接構文解析器を生成することも容易になります。
- 識別子の明確化: 識別子の定義にEBNF規則が追加され、Unicode文字とアンダースコアが識別子の一部として許容されることが明示されました。これは、Go言語が多言語対応を重視していることを示しています。ただし、当時の実装との乖離(ASCII数字のみ許容)がTODOとして残されている点は、言語の進化過程における仕様と実装の調整フェーズを示唆しています。
- リテラルの詳細な定義: 整数、浮動小数点数、文字、文字列の各リテラルについて、その構文、意味、および特殊なケース(エスケープシーケンス、基数、精度など)が詳細に記述されました。
- 数値リテラル: 「理想的な整数」や「理想的な浮動小数点数」という概念は、Go言語の型システムにおける柔軟性を示しています。これにより、リテラルの値がコンパイル時に型に縛られず、より広い範囲の値を表現できるようになります。
- 文字・文字列リテラルとUnicode/UTF-8: Go言語がUnicodeとUTF-8を深く統合していることが、文字・文字列リテラルの定義から強く読み取れます。特に、文字リテラルがUnicodeコードポイントを表し、文字列リテラルがUTF-8エンコードされたバイト列を表すという区別は、多言語対応のプログラミングにおいて非常に重要です。エスケープシーケンスの挙動も、このUnicode/UTF-8の特性に基づいて詳細に定義されています。
- 文字列リテラルの結合: 隣接する文字列リテラルが自動的に結合されるという規則は、長い文字列を複数行に分けて記述する際に便利であり、Go言語のコードの可読性を高める一因となります。
このコミットは、Go言語の初期段階において、その言語仕様の基礎を固める上で極めて重要な役割を果たしました。これにより、Go言語のコンパイラや開発ツールがより堅牢になり、開発者がGo言語をより正確に理解し、効果的に利用するための基盤が築かれました。
関連リンク
- Go言語公式サイト: https://go.dev/
- Go言語の仕様: https://go.dev/ref/spec (現在の最新仕様)
- Go言語の歴史: https://go.dev/doc/history
参考にした情報源リンク
- Go言語のコミット履歴 (GitHub): https://github.com/golang/go/commits/master
- Extended Backus-Naur Form (EBNF) - Wikipedia: https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_Form
- Unicode - Wikipedia: https://ja.wikipedia.org/wiki/Unicode
- UTF-8 - Wikipedia: https://ja.wikipedia.org/wiki/UTF-8
- Go言語の数値リテラルに関する議論 (Stack Overflowなど): "Go ideal integers" "Go floating point literals" などのキーワードで検索。