2016-01-01 130 views
1

我剛剛開始與Bison合作,並且遇到了一些問題。我的語法目標是識別一個「命令管道」語言,其中一個命令的輸出可以作爲另一個命令的輸入來管道。每個命令也可以有一個帶有可選值的參數列表。下面是一個例子:轉換減少野牛語法衝突

command1 --param1 test --param2 test2 | command2 | command3 --param3 

在前面的例子,command1採用兩個參數,param1與值testparam2與值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評估終端的方式。例如,如果我重寫cmdletCallparamList規則如下,語法遊:

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

+0

儘管C(或可選的C++)是野牛生成代碼的語言,但這個問題實際上並不涉及這兩者之一。已編輯標籤。 –

+0

這是兩個不同的問題,應該是兩個不同的問題。第二個問題幾乎可以肯定涉及你的詞法分析器(在某種意義上說,其中的C/C++代碼),儘管我建議你只是在你的詞法分析器中搜索複製yytext的需要;它在所有的常見問題。 – rici

+0

將第二個問題作爲同一個問題的一部分,因爲它說明了在實踐中可以使用bison和flex的問題類型。因爲你已經給出了兩個問題的答案,所以將它們放在一起是有意義的:) – BigONotation

回答

3

您對cmdletCall的定義實際上是IDENTIFIER paramList*(使用標準的常規語言Kleene星算子)。但是paramListparamDef+。所以這顯然是模棱兩可的;沒有辦法知道有多少paramList遵循IDENTIFIER,因爲沒有指示哪裏結束,下一個開始。

實際上,您只想要(或至多)一個paramList。有幾個選項,但最簡單的是:

cmdletCall: IDENTIFIER paramList 
paramList : /* empty */ 
      | paramList parameterDef 

另一種選擇是保持paramList非空的,並添加cmdletCall選項只由一個IDENTIFIER。真的,只有當你需要爲了語義規則而分開案例時纔有用,但是肯定是可行的。

或爲一個更簡單的語法,剛剛擺脫的paramList

cmdletCall: IDENTIFIER 
      | cmdletCall parameterDef 

由於野牛生成解析器寧願轉向減少,從模糊的語法生成的解析器將做你所期望的:只生產零或每個命令一個paramList。但是,無論如何,你最好還是建議消除歧義。


你有沒有和相關的語義值的問題是不是抄襲的yytext從掃描儀的內容的結果; yytext是靈活構建的掃描儀的內部數據結構,其內容不屬於您,因爲掃描儀可以並且會根據其認爲合適的方式修改它們。

+0

所以,你的意思是在flex掃描儀中,我需要複製yytext的內容?目前我一直在做像yylval.s = yytext這樣的東西。 – BigONotation

+0

@BigLudinski:是的,問題一遍又一遍地出現。這裏有一個最近的答案:http://stackoverflow.com/a/33878874/1566221,這是幾年前的一個:http://stackoverflow.com/a/13166741/1566221正如我所說,它在所有的常見問題,包括野牛FAQ – rici

+0

非常感謝所有的啓發!我度過了除夕的大部分時間。我按照你的建議修改了語法,這解決了轉換/減少衝突。我還使用yylval.s = strdup(yytext)製作了yytext內容的私人副本,現在一切正常!我仍然需要獲得內存管理,但感謝你我正確的道路:) – BigONotation