私は現在、初めて Flex と Bison で遊んでいます。Bison man pageで文脈上の優先順位について読みました。ディレクティブを使用せずに最小限の例を作成しようとしました%prec
が、それが実際に何をするのかよくわかっていません。これが私の最小限の例です。
フレックスファイル
%option noyywrap
%{
#include <iostream>
#include "parser.h"
int lineNum = 1;
%}
%%
[ \t]+ ;
\n { lineNum++; }
\/\/(.*) ;
"+" { return PLUS; }
"-" { return MINUS; }
"*" { return MULTIPLY; }
[0-9]+ {
yylval.int_val = atoi(yytext);
return INT;
}
. { std::cout << "Unknown token " << yytext << " at line " << lineNum << std::endl; yyterminate(); }
%%
バイソンファイル
%{
#include <iostream>
#include <string>
extern int lineNum;
extern int yylex();
void yyerror(const char* e) { std::cerr << "ERROR ON LINE " << lineNum << ": " << e << std::endl; }
extern int eval;
%}
%union
{
int int_val;
}
%define parse.error verbose
%token <int_val> INT PLUS MINUS MULTIPLY
%type <int_val> expr
%left PLUS MINUS
%left MULTIPLY
%start expr
%%
expr : expr PLUS expr { $$ = $1 + $3; eval = $$; }
| expr MINUS expr { $$ = $1 - $3; eval = $$; }
| expr MULTIPLY expr { $$ = $1 * $3; eval = $$; }
| MINUS expr { $$ = -$2; eval = $$; }
| INT
;
%%
メイン cpp ファイル
#include <iostream>
int eval = 0;
extern int yyparse();
int main()
{
yyparse();
std::cout << eval << std::endl;
return 0;
}
詳細なテストは行っていませんが、単項マイナスを使用したすべての組み合わせで、正しい結果が得られました。私は幸運ですか、それとも%prec
ディレクティブは特別な場合にのみ必要ですか? また、スタック上のシフトと削減を自分で評価できるように、ディレクティブが必要な場合の例をいただければ幸いです。
ありがとう