基本
簡単な紹介
Bisonは、.y ファイル内の事前定義されたルールに基づくユーザー入力コンテンツに基づいて構文分析ツリーを構築する構文アナライザーです。(いわゆるルールは、対応する文字を一致させた後、対応するアクションを実行するというものです。)
簡単な文法の例と分析:
statement :NAME '=' expression
expression : NUMBER '+' NUMBER
| NUMBER '-' NUMBER
コロン (:) は、ルールの左側と右側を区切るために使用されます。ステートメントは NAME '=' 式と同等です。
文法では、大文字と引用符の内容は終端記号であると規定されており、たとえば、NAME '=' という 2 文字は意味を持たなくなり、終了します。
Expression は非終端記号であり、2 行目の規定により、Expression は
2 つの数の加算または 2 つの数の減算に相当します。**垂直バー (|)** は、構文シンボルに 2 つの同等の方法があることを示します。
NUMBER '+' NUMBER NUMBER '-' NUMBER はすべて終端記号であり、文法の解析は終了します。
引っ越しプロトコル分析
Bison が解析ツリーを処理すると、一連の状態が作成されます。各状態は 1 つ以上の解析されたルール内の可能な位置に対応します。
読み取りトークンがルールを終了するのに十分でない場合、トークンは内部スタックにプッシュされ、新しい状態に切り替えられます。このプロセスは シフトイン と呼ばれます。
スタックにプッシュされたすべての構文シンボルがルールの右側の部分と同等の場合、これらのシンボルをすべてポップし、ルールの左側の部分をスタックにプッシュします。このプロセスは仕様と呼ばれます。
Bison コンポーネント
定義部
%%
ルール部
%%
ユーザ付加C言語部
最初の部分は定義部分で、主にオプション、テキスト ブロック、コメント、宣言シンボル、セマンティック値データ型のコレクション、指定された開始シンボルおよびその他の宣言などが含まれます。
%{ と %} の間に存在するテキスト ブロックは、変更されずに生成されたファイルにコピーされます。
/* 指定起始符号(start symbol)有时也称为目标符号(goal symbol) */
%start calclist
/* 声明tokens记号,以便于告诉bison在语法分析程序中记号的名称。通常这些记号总是使用大写字母,虽然bison本身并没有这个要求。 */
%token NUMBER
%{
/* 文字块,该部分的内容将直接复制到生成的代码文件的开头,
以便它们在使用yyparse定义之前使用。 */
#define _GNU_SOURCE
#include <stdio.h>
#include "ptypes.h"
%}
後半は主に文法規則についてです
%%
/* 空规则 -- 起始符号(start symbol)有时也称为目标符号(goal symbol) */
calclist:
/* 如果没有指定语义动作,bison将使用默认的动作: { $$ = $1; }*/
| calclist exp EOL { printf("- %d\n", $2); }
//EOL代表一个表达式的结束。像flex一样,大括号中的表示规则的动作
;
exp: factor // default $$ = $1
| exp ADD factor { $$ = $1 + $3; }
| exp SUB factor { $$ = $1 - $3; }
; // represent the termination of this rule.
factor: term // default $$ = $1
| factor MUL term { $$ = $1 * $3; }
| factor DIV term { $$ = $1 / $3; }
;
term: NUMBER // default $$ = $1
| ABS term { $$ = $2 >= 0? $2 : - $2; }
;
%%
3 番目の部分では、この部分の内容が、生成されたコード ファイルの末尾にそのままコピーされます。この部分は主に、以前に宣言されたいくつかの関数を実装するために使用されます。
int main(int argc, char ** argv)
{
printf(">");
yyparse();
return 0;
}
yyerror(char *s)
{
fprintf(stderr,"error:%s\n",s);
}
左再帰と右再帰 再帰
ルールを作成する場合、ルールの右側部分の左端または右端に再帰参照を配置できます。次に例を示します。
exprlist: exprlist ',' expr; /* 左递归 */
exprlist: expr ',' exprlist; /* 右递归 */
ほとんどの場合、どちらの方法でも構文を記述することができます。bison は、右再帰よりも左再帰を効率的に処理します。これは、内部スタックが現在分析中のすべてのルールのすべてのシンボルを追跡する必要があるためです。
YYINITDEPTH はパーサー スタックの長さを制御し、スタックの初期サイズ (通常は 200) を示します。また、YYMAXDEPTH を定義して最大スタック長 (通常は 1000) を設定することもできます。
%{
#define YYMAXDEPTH 50000
%}