我剛剛開始與Bison合作,並且遇到了一些問題。我的語法目標是識別一個「命令管道」語言,其中一個命令的輸出可以作爲另一個命令的輸入來管道。每個命令也可以有一個帶有可選值的參數列表。下面是一個例子:轉換減少野牛語法衝突
command1 --param1 test --param2 test2 | command2 | command3 --param3
在前面的例子,command1
採用兩個參數,param1
與值test
和param2
與值test2
。然後將command1
的輸出「傳送」至command2
,其不採用參數。最後,command2
的結果被傳送到command3
,該參數取一個參數(沒有值的參數被認爲是一個開關)。
相應的野牛語法如下:
%{
#include <string>
#include <iostream>
#include "AST.h"
#include "Evaluator.h"
void yyerror (const char *error);
int yylex();
%}
%code{
Evaluator eval;
}
%union {
char* s;
double d;
AbstractNode* abstractnode;
CmdletCall* cmdletdef;
ParameterDef* parameterdef;
ParameterListDef* paramlistdef;
}
/* declare tokens */
%token EOL
%token<s> PARAMETERNAME
%token<s> BUILTIN
%token<s> IDENTIFIER
%type <parameterdef> parameterDef
%type <cmdletdef> cmdletCall
%type <abstractnode> pipeLineDef
%type <paramlistdef> paramList
%%
input: /* nothing */
| input pipeLineDef EOL {
$2->accept(eval);
delete $2;
std::cout << eval.result() << std::endl;
}
| input EOL {}
;
pipeLineDef: cmdletCall {$$ = $1;}
| pipeLineDef '|' cmdletCall {$$ = new PipeLineDef($1, $3);}
;
cmdletCall: IDENTIFIER {$$ = new CmdletCall($1);}
| cmdletCall paramList {$1->setParameterList($2);}
;
paramList: parameterDef {
$$ = new ParameterListDef;
$$->addChildNode($1);
}
| paramList parameterDef {
$1->addChildNode($2);
$$ = $1;
}
;
parameterDef: PARAMETERNAME {$$ = new ParameterDef($1);}
| parameterDef IDENTIFIER {
$1->setValue($2);
}
;
%%
void yyerror (const char *error)
{
std::cout << error << std::endl;
}
以前的語法有一個班次,減少衝突,抄錄如下:
Terminals unused in grammar
BUILTIN
State 10 conflicts: 1 shift/reduce
State 10
7 cmdletCall: cmdletCall paramList .
9 paramList: paramList . parameterDef
PARAMETERNAME shift, and go to state 9
PARAMETERNAME [reduce using rule 7 (cmdletCall)]
$default reduce using rule 7 (cmdletCall)
parameterDef go to state 13
我想刪除衝突,但我我不知道應該如何繼續(我的理解是轉換/減少衝突表明模糊的語法)。但是,從我最初的測試中,一切似乎都按預期工作。另一個讓我感到困惑的點是Bison評估終端的方式。例如,如果我重寫cmdletCall
和paramList
規則如下,語法遊:
cmdletCall: IDENTIFIER paramList {$$ = new CmdletCall($1); $$->setParameterList($2);}
;
paramList: /*nothing*/
{
$$ = new ParameterListDef;
}
| paramList parameterDef {
$1->addChildNode($2);
$$ = $1;
}
;
如果我重寫語法如上所示,則對於輸入的,例如:
command1 --param1
在cmdletCall
規則,對應於IDENTIFIER
令牌的值$1
將爲command1 --param1
,而不是僅限於command1
。
儘管C(或可選的C++)是野牛生成代碼的語言,但這個問題實際上並不涉及這兩者之一。已編輯標籤。 –
這是兩個不同的問題,應該是兩個不同的問題。第二個問題幾乎可以肯定涉及你的詞法分析器(在某種意義上說,其中的C/C++代碼),儘管我建議你只是在你的詞法分析器中搜索複製yytext的需要;它在所有的常見問題。 – rici
將第二個問題作爲同一個問題的一部分,因爲它說明了在實踐中可以使用bison和flex的問題類型。因爲你已經給出了兩個問題的答案,所以將它們放在一起是有意義的:) – BigONotation