| 原作者 | ロバート・コーベット |
|---|---|
| 開発者 | GNUプロジェクト |
| 初回リリース | 1985年6月[1] |
| 安定版リリース | 3.8.2 [2]
/ 2021年9月25日 |
| リポジトリ |
|
| 書かれた | Cとm4 |
| オペレーティング·システム | Unixライク |
| タイプ | パーサージェネレーター |
| ライセンス | ライセンス |
| Webサイト | www.gnu.org/software/bison/ |
GNU Bison(通称Bison )は、 GNU プロジェクトの一部であるパーサージェネレーターです。Bison は、Bison 構文(「機械可読BNF」[3]と説明される)で仕様を読み取り、解析の曖昧さがあれば警告し、トークンのシーケンスを読み取り、そのシーケンスが文法で指定された構文に準拠しているかどうかを判断するパーサーを生成します。
生成されたパーサーは移植可能で、特別なコンパイラを必要としません。BisonはデフォルトでLALR(1)パーサーを生成しますが、標準的なLR、IELR(1)、GLRパーサーも生成できます。[4]
POSIXモードでは、BisonはYaccと互換性がありますが、この以前のプログラムに対していくつかの拡張機能も備えています。
- 競合に対する反例の生成
- 位置追跡(例:ファイル、行、列)
- 生成されたパーサー内の豊富で国際化可能な構文エラーメッセージ
- カスタマイズ可能な構文エラー生成、
- 再入可能パーサー
- 自動補完機能付きのプッシュパーサー
- 名前付き参照のサポート
- 生成されたパーサーに関するいくつかの種類のレポート(グラフィカル、XML)
- 複数のプログラミング言語(C、C++、D、Java)のサポート
自動字句解析器であるFlexは、入力データをトークン化し、Bisonにトークンを提供するために、Bisonと併用されることが多い。[5]
Bisonはもともと1985年にRobert Corbettによって書かれました。[1]その後、1989年にRobert CorbettはBerkeley Yaccという別のパーサージェネレータをリリースしました。BisonはRichard StallmanによってYacc互換になりました。[6]
Bison はフリーソフトウェアであり、 GNU General Public Licenseに基づいて利用可能ですが、例外として (後述)、ライセンスの コピーレフト要件に違反することなく、生成されたコードを使用できます。
特徴
反例生成
LR パーサー ジェネレーターのデリケートな問題の 1 つは、競合 (シフト/削減競合と削減/削減競合) の解決です。多くの LR パーサー ジェネレーターでは、競合を解決するにはパーサー オートマトンを分析する必要があり、ユーザーにはある程度の専門知識が求められます。
ユーザーがより直感的に競合を理解できるように、Bison は自動的に反例を生成することもできます。曖昧な文法の場合、Bison は文法が曖昧であることを示す反例を生成することさえあります。
例えば、悪名高いぶら下がりelse問題を抱えた文法では、Bisonは次のように報告する。
doc/if-then-else.y:警告: トークン「else」でシフト/リデュースの競合が発生しました [- Wcounterexamples ] 例: "if" expr "then" "if" expr "then" 文 • "else" 文 シフト導出 if_stmt ↳ "if" expr "then" stmt ↳ if_stmt ↳ "if" expr "then" stmt • "else" stmt 例: "if" expr "then" "if" expr "then" stmt • "else" stmt 派生を減らす if_stmt ↳ "if" 式 "then" 文 "else"文 ↳ if_stmt ↳ "if" 式 "then" 文 •
再入性
再入可能性は Bison に追加された機能であり、Yacc には存在しません。
通常、Bisonは再入可能ではないパーサを生成します。再入可能を実現するには宣言を%define api.pure使用する必要があります。Bisonの再入可能の詳細については、Bisonマニュアルを参照してください。[7]
出力言語
BisonはC、C++、D、Javaのコードを生成できる。[8]
Bison で生成されたパーサーを他の言語から使用するには、SWIGなどの言語バインディングツールを使用できます。
生成されたコードのライセンスと配布
Bison はソース コードを生成するため、それが他のソフトウェア プロジェクトのソース コードに追加され、いくつかの単純だが興味深い著作権の問題が生じます。
GPL互換ライセンスは不要
Bisonによって生成されたコードには、Bisonプロジェクト自体のコードが大量に含まれています。BisonパッケージはGNU General Public License(GPL)の条件に基づいて配布されていますが、出力にはGPLが適用されないように例外が追加されています。[9] [10]
Bison の以前のリリースでは、出力に元のソース コードの yyparse() 関数が含まれていたため、出力の一部も GPL の下でライセンスされることが規定されていました。
Bisonを使用したパッケージの配布
Bison を使用するフリー ソフトウェア プロジェクトでは、プロジェクトが Bison に入力するソース コードを配布するか、Bison によって出力された結果の C コードを配布するかを選択できます。どちらも、受信者がプロジェクトのソース コードをコンパイルするには十分です。ただし、入力のみを配布すると、プロジェクトのコンパイル時に必要な C コードを生成できるように、受信者が互換性のある Bison のコピーをインストールする必要があるという、ちょっとした不便が生じます。また、出力の C コードのみを配布すると、このコードは人間によって書かれたものでも、人間のために書かれたものでもないため、受信者がパーサーを変更するのが非常に困難になるという問題が生じます。このコードの目的は、C コンパイラに直接入力することです。
これらの問題は、入力ファイルと生成されたコードの両方を配布することで回避できます。ほとんどの人は、他のソフトウェア パッケージと違いなく、生成されたコードを使用してコンパイルしますが、パーサー コンポーネントを変更したい人は、まず入力ファイルを変更し、コンパイル前に生成されたファイルを再生成することができます。両方を配布するプロジェクトでは、通常、バージョン コントロールシステムに生成されたファイルがありません。ファイルはリリース時にのみ生成されます。
GPLなどの一部のライセンスでは、ソース コードが「変更を加えるための作品の推奨形式」であることが求められます。したがって、Bison を使用する GPL プロジェクトでは、Bison の入力となるファイルを配布する必要があります。もちろん、生成されたファイルも含めることができます。
使用
Bison は Yacc の代替として書かれており、互換性も高いため、Bison を使用する多くのプロジェクトのコードは、Yacc にそのまま流用できます。このため、プロジェクトが Bison 固有のソース コードを「使用」しているかどうかを判断するのは困難です。多くの場合、Bison の「使用」は、同等の Yacc または他の派生製品の使用に簡単に置き換えることができます。
Bison には Yacc にはない機能があるため、一部のプロジェクトでは Yacc だけでは不十分で、実際に Bison を「使用している」と言えます。
以下のリストは、より緩い意味で Bison を「使用」することが知られているプロジェクトの一覧です。これらのプロジェクトは、フリーソフトウェア開発ツールを使用し、Bison または Bison 互換パッケージに組み込むことを目的としたコードを配布しています。
- Bashシェルは、コマンド入力を解析するために yacc 文法を使用します。
- Bison独自の文法パーサーはBisonによって生成される。[11]
- CMakeはいくつかのBison文法を使用します。[12]
- GCCは当初Bisonを使用していたが、2004年にC++用(バージョン3.4)[13] 、 2006年にCとObjective-C用(バージョン4.1)[14]に手書きの再帰下降パーサーに切り替えた。
- Goプログラミング言語(GC)はBisonを使用していましたが、バージョン1.5で手書きのスキャナとパーサに切り替わりました。[ 15]
- LilyPondはパーサーを生成するためにBisonを必要とする。[16]
- MySQL [17]
- GNU OctaveはBisonで生成されたパーサーを使用しています。[18]
- Perl 5は5.10以降、Bisonで生成されたパーサーを使用しています。[19]
- PHPプログラミング言語(Zend Parser)。
- PostgreSQL [20]
- Rubyプログラミング言語のリファレンス実装であるRuby MRIは、Bison文法に依存しています。[21]
- syslog-ngは複数のBison文法を組み合わせて使用します。[22]
完全な再入可能パーサーの例
次の例は、Bison と flex を使用して、単純な計算機プログラム (加算と乗算のみ) と抽象構文木を作成するプログラムを作成する方法を示しています。次の 2 つのファイルは、構文木関数の定義と実装を提供します。
/*
* Expression.h
* 構文ツリーを構築するために使用される構造体の定義。
*/
#ifndef __EXPRESSION_H__
#define __EXPRESSION_H__
/**
* @brief 操作タイプ
*/
typedef enum tagEOperationType { eVALUE , eMULTIPLY , eADD } EOperationType ;
/**
* @brief 式の構造
*/
typedef struct tagSExpression { EOperationType type ; /* /< 操作の種類 */
int value ; /* /< 型が eVALUE の場合にのみ有効 */ struct tagSExpression * left ; /* /< ツリーの左側 */ struct tagSExpression * right ; /* /< ツリーの右側 */ } SExpression ;
/**
* @brief 識別子を作成します
* @param value 数値
* @return 式、またはメモリがない場合は NULL
*/
SExpression * createNumber ( int value );
/**
* @brief 操作を作成します
* @param type 操作タイプ
* @param left 左オペランド
* @param right 右オペランド
* @return 式、またはメモリがない場合は NULL
*/
SExpression * createOperation ( EOperationType type , SExpression * left , SExpression * right );
/**
* @brief 式を削除します
* @param b 式
*/
void deleteExpression ( SExpression * b );
#endif /* __EXPRESSION_H__ */
/*
* Expression.c
* 構文ツリーを構築するために使用される関数の実装。
*/
#include "Expression.h"
#include <stdlib.h>
/**
* @brief 式のためのスペースを割り当てます
* @return 式、またはメモリが足りない場合は NULL
*/
static SExpression * allocateExpression () { SExpression * b = ( SExpression * ) malloc ( sizeof ( SExpression ));
b == NULLの場合、NULLを返します。
b ->タイプ= eVALUE ; b ->値= 0 ;
b ->左= NULL ; b ->右= NULL ;
bを返す; }
SExpression * createNumber ( int値) { SExpression * b = allocateExpression ();
b == NULLの場合、NULLを返します。
b -> type = eVALUE ; b ->値=値;
bを返す; }
SExpression * createOperation ( EOperationType type 、SExpression * left 、SExpression * right ) { SExpression * b = allocateExpression ();
b == NULLの場合、NULLを返します。
b -> type = type ; b -> left = left ; b -> right = right ;
bを返す; }
void deleteExpression ( SExpression * b ) { b == NULLの場合、戻り値;
式bを左から削除します。式
b を右から削除します。
無料( b );
}
Bison パーサーに必要なトークンは、flex を使用して生成されます。
% {
/*
* Lexer.l ファイル
* 字句解析プログラムを生成するには、次のコマンドを実行します: "flex Lexer.l"
*/
#include "Expression.h" #include "Parser.h"
#include <stdio.h>
% }
%オプションoutfile = "Lexer.c"ヘッダー-ファイル= "Lexer.h" %オプションwarn nodefault
%オプションreentrant noyywrap never - interactive nounistd %オプションbison - bridge
%%
[ \ r \ n \ t ] * { continue ; /* 空白をスキップします。 */ } [ 0-9 ] + { sscanf ( yytext , "%d" , & yylval -> value ); return TOKEN_NUMBER ; }
"*" { return TOKEN_STAR ; } "+" { return TOKEN_PLUS ; } "(" { return TOKEN_LPAREN ; } ")" { return TOKEN_RPAREN ; }
. { continue ; /* 予期しない文字は無視します。 */ }
%%
int yyerror ( SExpression **式、yyscan_tスキャナ、const char * msg ) { fprintf ( stderr 、"エラー: %s \n " 、msg ); 0を返す; }
トークンの名前は通常、中立的です。「TOKEN_PLUS」と「TOKEN_STAR」であり、「TOKEN_ADD」と「TOKEN_MULTIPLY」ではありません。たとえば、単項演算子「+」(「+1」など) をサポートする場合、「+」を「TOKEN_ADD」と名付けるのは誤りです。C などの言語では、「int *ptr」は積ではなくポインタの定義を示します。「*」を「TOKEN_MULTIPLY」と名付けるのは誤りです。
トークンはflexによって提供されるため、パーサとレキサー間の通信手段を提供する必要があります。[23]通信に使用されるデータ型YYSTYPEは、Bison %union宣言を使用して設定されます。
このサンプルではflexとyaccの両方の再入可能バージョンを使用しているため、 yyparseから呼び出されるときにyylex関数にパラメータを提供する必要があります。[23]これはBisonの%lex-paramと%parse-param宣言を通じて行われます。 [24]
% {
/*
* Parser.y ファイル
* パーサーを生成するには、次のコマンドを実行します: "bison Parser.y"
*/
#include "Expression.h" #include "Parser.h" #include "Lexer.h"
// Lexer.l で提供されている実装を参照します
int yyerror ( SExpression ** expression , yyscan_t scanner , const char * msg );
% }
%コードには{ typedef void * yyscan_t ; }が必要です
%出力"Parser.c" %定義"Parser.h"
% api . pureを定義します% lex - param { yyscan_t scanner } % parse - param { SExpression **式} % parse - param { yyscan_t scanner }
% union { int値; SExpression *式; }
% token TOKEN_LPAREN "(" % token TOKEN_RPAREN ")" % token TOKEN_PLUS "+" % token TOKEN_STAR "*" % token <値> TOKEN_NUMBER "数値"
% type <式> expr
/* 優先順位 (増加) と結合性:
a+b+c は (a+b)+c です: 左結合性
a+b*c は a+(b*c) です: "*" の優先順位は "+" よりも高くなります。 */
% left "+" % left "*"
%%
入力
: expr { *式= $1 ; } ;
expr
: expr [ L ] "+" expr [ R ] { $$ = createOperation ( eADD , $L , $R ); } | expr [ L ] "*" expr [ R ] { $$ = createOperation ( eMULTIPLY , $L , $R ); } | "(" expr [ E ] ")" { $$ = $E ; } | "number" { $$ = createNumber ( $1 ); } ;
%%
Bison によって生成されたパーサーと flex によって生成されたスキャナーを使用して構文ツリーを取得するために必要なコードは次のとおりです。
/*
* main.c ファイル
*/
#include "Expression.h" #include "Parser.h" #include "Lexer.h"
#include <stdio.h>
int yyparse ( SExpression **式、yyscan_tスキャナ);
SExpression * getAST ( const char * expr ) { SExpression *式; yyscan_tスキャナ; YY_BUFFER_STATE状態;
if ( yylex_init ( & scanner )) { /* 初期化できませんでした */ return NULL ; }
状態= yy_scan_string (式、スキャナ);
if ( yyparse ( & expression , scanner )) { /* 解析エラー */ return NULL ; }
yy_delete_buffer (状態、スキャナ);
yylex_destroy (スキャナー);
戻り式; }
int assess ( SExpression * e ) { switch ( e -> type ) { case eVALUE : return e -> value ; case eMULTIPLY : return assess ( e -> left ) * assess ( e -> right ); case eADD : return assess ( e -> left ) + assess ( e -> right ); default : /* ここには記述しないでください */ return 0 ; } }
int main ( void ) { char test [] = " 4 + 2*10 + 3*( 5 + 1 )" ; SExpression * e = getAST ( test ); int result = assess ( e ); printf ( "'%s' の結果は %d です\n " , test , result ); deleteExpression ( e ); return 0 ; }
プロジェクトをビルドするための簡単な makefile は次のとおりです。
# メイクファイル
ファイル= Lexer.c Parser.c Expression.c main.c
CC = g++
CFLAGS = -g -ansi
テスト: $(ファイル) $( CC ) $( CFLAGS ) $(ファイル) -oテスト
Lexer.c : Lexer . l flex Lexer.l
Parser.c :パーサー。yレクサー。c bison Parser.y
クリーン:
rm -f *.o *~ Lexer.c Lexer.h Parser.c Parser.hテスト
参照
- Berkeley Yacc (byacc) – GNU Bisonと同じ作者による、もうひとつのフリーソフトウェアYacc代替品
- ANTLR言語認識のためのもう一つのツール、もう一つのオープンソースパーサージェネレーター
参考文献
- ^ ab Corbett, Robert Paul (1985 年 6 月)。静的セマンティクスとコンパイラ エラー回復( Ph.D.)。カリフォルニア大学バークレー校。DTIC ADA611756。
- ^ Akim Demaille (2021年9月25日). 「Bison 3.8.2」.
- ^ 「言語と文法(Bison 3.8.1)」。www.gnu.org 。 2021年12月26日閲覧。
- ^ Bison マニュアル: はじめに。
- ^ レヴィン、ジョン(2009年8月)。flex & bison。オライリーメディア。ISBN 978-0-596-15597-1。
- ^ Bison マニュアル: 純粋な (再入可能) パーサ
- ^ Bison マニュアル: Bison 宣言の概要
- ^ Bison マニュアル: Bison の使用条件
- ^ ソースコードファイルparse-gram.cには例外が含まれています
- ^ "parse-gram.y". bison.git. GNU Savannah . 2020年7月29日閲覧。
- ^ 「CMake の LexerParser」. github.com .
- ^ GCC 3.4 リリース シリーズの変更点、新機能、修正点
- ^ GCC 4.1 リリース シリーズの変更点、新機能、および修正点
- ^ Golang 文法定義
- ^ "Parser.yy - GNU LilyPond Git リポジトリ". git.savannah.gnu.org。
- ^ 「4. SQLの解析 - flex & bison [書籍]」。
- ^ "GNU Octave: Libinterp/Parse-tree/Oct-parse.cc ソース ファイル".
- ^ 「perl 5.10.0 の新機能は何ですか?」 perl.org.
- ^ 「パーサーステージ」。postgresql.org。2021年9月30日。
- ^ 「Ruby MRI パーサー」. github.com .
- ^ "syslog-ng の XML パーサー". github.com。 2021年10月14日。
- ^ ab Flex マニュアル: C スキャナと Bison パーサ アーカイブ済み 2010-12-17 at the Wayback Machine
- ^ Bison マニュアル: 純粋パーサの呼び出し規約
さらに読む
外部リンク
- GNU プロジェクトのウェブサイト
- マニュアル
- GNU Savannahの Bison プロジェクト
- フリーソフトウェアディレクトリへの登録
- GNU Bison によって生成された C パーサーの内部
- Linux に Bison (GNU パーサー ジェネレーター) をダウンロードしてインストールする方法
- GnuWin32 による Win32 バイナリ (バージョン 2.4.1)
