[インデックス 17558] ファイルの概要
このコミットは、Go言語のcmd/yacc
ツールにおけるサンプルコードの変更に関するものです。具体的には、既存のunits
(単位変換)の例を、よりシンプルでライセンス上の懸念がないexpr
(式評価)の例に置き換えることを目的としています。
コミット
commit fdaf88ea5b7a3bc937e68875d55b5741ecb2f092
Author: Ian Lance Taylor <iant@golang.org>
Date: Wed Sep 11 09:01:47 2013 -0700
cmd/yacc: replace units example with simpler expr example
The units example is nice but is covered by the Lucent
license, which may be a concern for some people making a
commercial source code distribution of Go.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/13283045
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/fdaf88ea5b7a3bc937e68875d55b5741ecb2f092
元コミット内容
cmd/yacc: replace units example with simpler expr example
units
の例は良いものだが、Lucentライセンスにカバーされており、Goの商用ソースコード配布を行う一部の人々にとっては懸念事項となる可能性がある。
変更の背景
このコミットの主な背景は、Go言語のcmd/yacc
ツールに含まれていたunits
(単位変換)のサンプルコードが、Lucent Public License (LPL) の下でライセンスされていたことにあります。
Lucent Public Licenseは、オープンソースライセンスの一つですが、その条項が一部の商用利用シナリオにおいて懸念を引き起こす可能性がありました。特に、Go言語の公式配布物の一部として含まれる場合、Go自体がBSDライセンスという非常に寛容なライセンスを採用しているため、より制約の厳しいLPLのコードが含まれることは、Goの商用利用を検討する開発者や企業にとって法的な複雑さや不確実性をもたらす可能性がありました。
Goプロジェクトは、そのエコシステム全体で可能な限り寛容なライセンス(BSDライセンスなど)を採用し、開発者がGoを自由に利用・配布できることを重視しています。このような背景から、ライセンス上の懸念を排除し、より広範な利用を促進するために、LPLでライセンスされたunits
の例を、よりシンプルでライセンス上の問題がないexpr
の例に置き換えることが決定されました。
前提知識の解説
Go言語のcmd/yacc
(goyacc)
cmd/yacc
は、Go言語で書かれたYacc(Yet Another Compiler Compiler)ツールです。Yaccは、文法定義から構文解析器(パーサー)を自動生成するためのツールであり、コンパイラやインタプリタのフロントエンド開発において広く利用されます。
goyacc
は、C言語のYaccと同様に、BNF(Backus-Naur Form)に似た文法定義ファイル(通常.y
拡張子)を読み込み、Go言語のソースコードとしてパーサーを生成します。生成されたパーサーは、字句解析器(レクサー)からのトークンストリームを受け取り、文法規則に従って構文木を構築したり、直接アクションを実行したりします。
goyacc
の主な特徴は以下の通りです:
- Go言語への統合: 生成されるコードはGo言語であり、Goの標準ライブラリや慣習に沿っています。
- 再入可能性: 生成されるパーサーはデフォルトで再入可能です。これは、複数のゴルーチンから同時にパーサーを使用できることを意味し、並行処理が重要なGoアプリケーションに適しています。
- 字句解析器との連携: ユーザーは
Lex
メソッドとError
メソッドを持つインターフェースを実装した字句解析器を提供する必要があります。
Lucent Public License (LPL)
Lucent Public License (LPL) は、Bell Labs (旧Lucent Technologies) が開発したオープンソースライセンスです。LPLは、フリーソフトウェア財団(FSF)によってフリーソフトウェアライセンスとして認識されていますが、GNU General Public License (GPL) のようなコピーレフトライセンスとは異なり、より寛容な性質を持っています。
LPLの主な特徴は以下の通りです:
- ソースコードの公開: LPLの下で配布されるソフトウェアの派生版を配布する場合、そのソースコードを公開する必要があります。
- 特許条項: LPLには特許に関する条項が含まれており、ライセンスされたソフトウェアを使用、複製、配布、変更する者に対して、関連する特許の非独占的、ロイヤリティフリーのライセンスを付与します。
- 互換性: 他のオープンソースライセンス、特にGPLとの互換性について議論されることがあります。LPLはGPLと直接互換性がないと見なされることがあり、LPLとGPLのコードを組み合わせたプロジェクトの配布には注意が必要です。
Goプロジェクトのような大規模なオープンソースプロジェクトでは、ライセンスの複雑さを避け、開発者が安心してコードを利用できるように、よりシンプルで広く受け入れられているライセンス(例: BSD, MIT, Apache 2.0)を好む傾向があります。LPLの特許条項やGPLとの互換性の問題は、Goの商用利用を検討する際に潜在的な法的リスクと見なされる可能性があったため、このコミットでunits
の例が削除されることになりました。
math/big
パッケージ
Go言語の標準ライブラリに含まれるmath/big
パッケージは、任意精度の算術演算を提供します。これは、標準のint
やfloat64
型では表現できない非常に大きな整数、有理数、または浮動小数点数を扱う必要がある場合に非常に有用です。
expr.y
の例では、big.Rat
型が使用されています。
big.Rat
: 有理数を表現するための型で、分子と分母を任意精度の整数で保持します。これにより、浮動小数点演算で発生する可能性のある精度誤差を回避し、正確な分数計算が可能です。
expr.y
がbig.Rat
を使用しているのは、シンプルな式評価において、特に除算を含む場合に正確な結果を保証するためです。例えば、1/3
のような計算は浮動小数点数では循環小数になりますが、big.Rat
では1/3
として正確に表現できます。
技術的詳細
このコミットは、goyacc
のサンプルコードを置き換えることで、ライセンス上の懸念を解消し、よりシンプルで教育的な例を提供します。
変更の具体的な内容:
-
units
例の削除:src/cmd/yacc/units.y
: 単位変換パーサーのYacc文法定義ファイルが削除されました。src/cmd/yacc/units.txt
:units
パーサーが使用する単位定義データファイルが削除されました。- これらのファイルは、Plan 9の
units
ツールから派生したもので、Lucent Public Licenseの下でライセンスされていました。
-
expr
例の追加:src/cmd/yacc/expr.y
: 新しいシンプルな式評価パーサーのYacc文法定義ファイルが追加されました。- この
expr.y
は、四則演算(加算、減算、乗算、除算)と括弧をサポートする基本的な電卓のような機能を提供します。 - 数値の表現には、Goの
math/big
パッケージのbig.Rat
型を使用しており、これにより任意精度の有理数計算が可能となり、浮動小数点数の精度問題を回避しています。 - 字句解析器(lexer)は、数字、演算子、括弧を認識し、Unicodeの乗算記号(
×
)と除算記号(÷
)もサポートしています。
-
ビルドシステムの更新:
src/cmd/yacc/Makefile
: ビルドターゲットがunits
からexpr
に変更されました。これにより、goyacc
ツールを使ってexpr.y
からパーサーを生成し、実行可能ファイルexpr
をビルドするようになります。
-
ドキュメントの更新:
src/cmd/yacc/doc.go
:cmd/yacc
ツールのドキュメントが更新され、units.y
の代わりに新しく追加されたexpr.y
が例として参照されるようになりました。
expr.y
の技術的詳細:
-
Yacc文法:
%union
: Yaccのセマンティック値(構文解析中にノードに関連付けられる値)の型を定義します。ここではnum *big.Rat
が定義されており、数値はbig.Rat
のポインタとして扱われます。%type
: 非終端記号(expr
,expr1
,expr2
,expr3
)のセマンティック値の型をnum
(*big.Rat
)として指定します。%token
: 終端記号(トークン)の型を定義します。NUM
トークンはnum
型、その他の演算子や括弧は文字そのものがトークン値となります。- 文法規則: 算術式の優先順位と結合規則に従って定義されています。
top
: 最上位の規則で、最終的な結果を出力します。expr
,expr1
,expr2
,expr3
: 演算子の優先順位(+
,-
<*
,/
)と結合性(左結合)を表現するために階層的に定義されています。NUM
: 数値リテラル。'(' expr ')'
: 括弧によるグループ化。
- アクション: 各文法規則には、Go言語のコードブロック(アクション)が関連付けられています。これらのアクションは、
big.Rat
のメソッド(Add
,Sub
,Mul
,Quo
,Neg
)を呼び出して計算を実行し、結果を$$
(現在の規則のセマンティック値)に代入します。
-
字句解析器 (
exprLex
):Lex
メソッド:goyacc
が生成するパーサーが呼び出す字句解析器の主要なメソッドです。入力ストリームから次のトークンを読み取り、その型とセマンティック値をyylval
に設定して返します。num
メソッド: 数字列を解析し、big.Rat
オブジェクトに変換します。小数点や指数表記(e
,E
)もサポートしています。next
メソッド: 入力ストリームから次のUnicodeルーンを読み取ります。Error
メソッド: 字句解析エラーが発生した場合に呼び出されます。
-
main
関数:- 標準入力から1行ずつ式を読み込み、
exprParse
関数(goyacc
によって生成されるパーサーのエントリポイント)を呼び出して解析・評価を行います。 - 結果は標準出力に表示されます。
big.Rat
が整数であれば整数として、そうでなければ分数として出力されます。
- 標準入力から1行ずつ式を読み込み、
この変更により、cmd/yacc
のサンプルは、よりシンプルで、Goのmath/big
パッケージの利用例としても機能する、教育的なものとなりました。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更は、主に以下のファイルの追加と削除、そして既存ファイルの修正に集約されます。
-
src/cmd/yacc/Makefile
:--- a/src/cmd/yacc/Makefile +++ b/src/cmd/yacc/Makefile @@ -2,9 +2,9 @@ # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. -units: yacc.go units.y - go run yacc.go -p units_ units.y - go build -o units y.go +expr: yacc.go expr.y + go run yacc.go -p expr expr.y + go build -o expr y.go clean: - rm -f y.go y.output units + rm -f y.go y.output expr
units
ターゲットをexpr
ターゲットに置き換え、ビルド対象のYacc文法ファイルと出力ファイル名を変更。
-
src/cmd/yacc/doc.go
:--- a/src/cmd/yacc/doc.go +++ b/src/cmd/yacc/doc.go @@ -20,10 +20,8 @@ written in C and documented at Adepts of the original yacc will have no trouble adapting to this form of the tool. -The file units.y in this directory is a yacc grammar for a version of -the Unix tool units, also written in Go and largely transliterated -from the Plan 9 C version. It needs the flag "-p units_" (see -below). +The file expr.y in this directory is a yacc grammar for a very simple +expression parser. It needs the flag "-p expr" (see below). The generated parser is reentrant. Parse expects to be given an argument that conforms to the following interface:
- ドキュメント内の
units.y
への参照をexpr.y
に更新。
- ドキュメント内の
-
src/cmd/yacc/expr.y
: (新規追加ファイル、全205行)- 新しい式評価パーサーのYacc文法定義とGo言語の字句解析器・メイン関数を含む。
math/big
パッケージのbig.Rat
型を使用して任意精度の有理数計算を実装。- 四則演算、括弧、Unicode演算子(
×
,÷
)をサポート。
-
src/cmd/yacc/units.txt
: (削除ファイル、全576行)- 既存の
units
例で使用されていた単位定義データファイル。
- 既存の
-
src/cmd/yacc/units.y
: (削除ファイル、全768行)- 既存の
units
例のYacc文法定義ファイル。
- 既存の
コアとなるコードの解説
このコミットの核心は、units
例の削除とexpr
例の追加にあります。
units
例の削除 (units.y
, units.txt
):
これらのファイルは、Unixのunits
ツールをGoで再実装したもので、様々な単位間の変換を行うパーサーでした。しかし、そのコードがLucent Public Licenseの下でライセンスされていたため、Goの商用利用におけるライセンス上の懸念を避けるために削除されました。これは、Goプロジェクトがライセンスのシンプルさと寛容性を重視していることの表れです。
expr
例の追加 (expr.y
):
このファイルは、新しく追加されたシンプルな式評価パーサーの例です。
- 文法定義: Yaccの文法定義セクションでは、算術式の構文が定義されています。
expr
,expr1
,expr2
,expr3
といった非終端記号を階層的に定義することで、演算子の優先順位(乗除算が加減算より優先)と結合性(左結合)が表現されています。例えば、expr1: expr1 '+' expr2
は加算が左結合であることを示し、expr2: expr2 '*' expr3
は乗算が左結合であることを示します。 - セマンティックアクション: 各文法規則にはGo言語のコードブロックが埋め込まれており、これがセマンティックアクションです。これらのアクションは、構文解析中に実行され、式の評価を行います。特に注目すべきは、
math/big
パッケージのbig.Rat
型を使用している点です。%union { num *big.Rat }
: これにより、パーサーのスタックに*big.Rat
型の値を保持できるようになります。$$ = $1.Add($1, $3)
のような行は、big.Rat
のAdd
メソッドを呼び出して加算を行い、その結果を現在の規則のセマンティック値($$
)に代入しています。big.Rat
を使用することで、1/3
のような割り切れない計算でも正確な有理数として結果を保持できます。
- 字句解析器 (
exprLex
):expr.y
のGo言語セクションには、字句解析器exprLex
の実装が含まれています。Lex
メソッドは、入力ストリームから文字を読み込み、トークン(数値、演算子、括弧など)に変換します。num
メソッドは、数字列を解析し、big.Rat
オブジェクトに変換します。これにより、整数だけでなく、浮動小数点表記の数値も正確に有理数として扱えます。- Unicodeの乗算記号(
×
)と除算記号(÷
)を認識し、それぞれASCIIの*
と/
としてパーサーに渡すことで、より柔軟な入力に対応しています。
main
関数: 標準入力から式を読み込み、exprParse
(goyacc
が生成するパーサーのエントリポイント)を呼び出して解析と評価を実行します。結果はbig.Rat
のIsInt()
メソッドで整数かどうかを判定し、適切な形式で出力されます。
このexpr.y
の例は、goyacc
の基本的な使い方、Yacc文法の構造、セマンティックアクションによる値の計算、そしてGoのmath/big
パッケージの強力な機能を示す、優れた教育的サンプルとなっています。
関連リンク
- Go言語の
cmd/yacc
(goyacc) のソースコード: https://github.com/golang/go/tree/master/src/cmd/yacc - Go言語の
math/big
パッケージのドキュメント: https://pkg.go.dev/math/big - Yacc (Wikipedia): https://ja.wikipedia.org/wiki/Yacc
参考にした情報源リンク
- Lucent Public License (Wikipedia): https://en.wikipedia.org/wiki/Lucent_Public_License
- Free Software Foundation (FSF) - Various Licenses and Comments about Them: https://www.gnu.org/licenses/license-list.html#LucentPublicLicense
- Go CL 13283045: cmd/yacc: replace units example with simpler expr example: https://go-review.googlesource.com/c/go/+/13283045
- Go issue 6090: cmd/yacc: units example is Lucent licensed: https://github.com/golang/go/issues/6090
- Go issue 6091: cmd/yacc: add a simpler example: https://github.com/golang/go/issues/6091