2012-03-15 31 views

回答

3

這是因爲第二個其實是模棱兩可的。第一個語法也是如此,但您通過添加%left來解決模糊問題。

這個%left在第二個語法中不起作用,因爲關聯性和優先級不是從規則到規則繼承的。即即使產生了​​和MINUS,那麼binaryop非終結符也不會繼承任何此類事物。關聯性和預定性本地化爲一個規則,圍繞着終端符號。

我們不能做%left binaryop,但我們可以稍微重構語法:

exp : exp binaryop term 
exp : term; 
term : INT; 
binaryop: PLUS | MINUS ; 

那現在有沒有衝突,因爲它是隱含左結合。即產生更長和更長的表達式只能發生在binaryop的左側,因爲右側是僅產生INT的term

0

我認爲這屬於Bison手冊所稱的「Mysterious Conflicts」。你可以複製:

exp: exp plus exp; 
exp: exp minus exp; 
exp: INT; 
plus: PLUS; 
minus: MINUS; 

這給我四個S/R衝突。

+0

不,這些是減少減少衝突。 – MustafaM 2012-03-15 20:23:27

+0

不是野牛:'test2.y:衝突:4 shift/reduce'。 – 2012-03-16 01:47:59

+0

感謝您的更新 – MustafaM 2012-03-20 08:33:52

0

描述Linux上Bison(版本2.3)產生的衝突語法的輸出文件如下。頂部的關鍵信息是'國家7有衝突'。

State 7 conflicts: 2 shift/reduce 

Grammar 

    0 $accept: exp $end 

    1 exp: exp binaryop exp 
    2 | INT 

    3 binaryop: PLUS 
    4   | MINUS 

Terminals, with rules where they appear 

$end (0) 0 
error (256) 
PLUS (258) 3 
MINUS (259) 4 
INT (260) 2 

Nonterminals, with rules where they appear 

$accept (6) 
    on left: 0 
exp (7) 
    on left: 1 2, on right: 0 1 
binaryop (8) 
    on left: 3 4, on right: 1 

state 0 

    0 $accept: . exp $end 

    INT shift, and go to state 1 

    exp go to state 2 

state 1 

    2 exp: INT . 

    $default reduce using rule 2 (exp) 

state 2 

    0 $accept: exp . $end 
    1 exp: exp . binaryop exp 

    $end shift, and go to state 3 
    PLUS shift, and go to state 4 
    MINUS shift, and go to state 5 

    binaryop go to state 6 

state 3 

    0 $accept: exp $end . 

    $default accept 

state 4 

    3 binaryop: PLUS . 

    $default reduce using rule 3 (binaryop) 

state 5 

    4 binaryop: MINUS . 

    $default reduce using rule 4 (binaryop) 

state 6 

    1 exp: exp binaryop . exp 

    INT shift, and go to state 1 

    exp go to state 7 

這裏是關於「國家7」的信息:

state 7 

    1 exp: exp . binaryop exp 
    1 | exp binaryop exp . 

    PLUS shift, and go to state 4 
    MINUS shift, and go to state 5 

    PLUS  [reduce using rule 1 (exp)] 
    MINUS  [reduce using rule 1 (exp)] 
    $default reduce using rule 1 (exp) 

    binaryop go to state 6 

麻煩的是通過在該行的.標記描述標記1。由於某種原因,%left不像您預期​​的那樣「生效」,所以Bison在讀取exp PLUS exp時發現衝突,並在其後發現​​或MINUS。在這種情況下,Bison(和Yacc)會進行轉變而不是減少。在這種情況下,我認爲這等於給予規則正確的優先權。

%left更改爲%right並省略它不會更改結果(根據衝突警告)。我也在Solaris上嘗試過Yacc,它產生了基本相同的衝突。

那麼,爲什麼第一個語法工作?這裏的輸出:

Grammar 

    0 $accept: exp $end 

    1 exp: exp PLUS exp 
    2 | exp MINUS exp 
    3 | INT 

Terminals, with rules where they appear 

$end (0) 0 
error (256) 
PLUS (258) 1 
MINUS (259) 2 
INT (260) 3 

Nonterminals, with rules where they appear 

$accept (6) 
    on left: 0 
exp (7) 
    on left: 1 2 3, on right: 0 1 2 

state 0 

    0 $accept: . exp $end 

    INT shift, and go to state 1 

    exp go to state 2 

state 1 

    3 exp: INT . 

    $default reduce using rule 3 (exp) 

state 2 

    0 $accept: exp . $end 
    1 exp: exp . PLUS exp 
    2 | exp . MINUS exp 

    $end shift, and go to state 3 
    PLUS shift, and go to state 4 
    MINUS shift, and go to state 5 

state 3 

    0 $accept: exp $end . 

    $default accept 

state 4 

    1 exp: exp PLUS . exp 

    INT shift, and go to state 1 

    exp go to state 6 

state 5 

    2 exp: exp MINUS . exp 

    INT shift, and go to state 1 

    exp go to state 7 

state 6 

    1 exp: exp . PLUS exp 
    1 | exp PLUS exp . 
    2 | exp . MINUS exp 

    $default reduce using rule 1 (exp) 

state 7 

    1 exp: exp . PLUS exp 
    2 | exp . MINUS exp 
    2 | exp MINUS exp . 

    $default reduce using rule 2 (exp) 

區別似乎是在狀態6和7,它能夠根據接下來的內容來區分做什麼。

解決這個問題的方法之一是:

%token <token> PLUS MINUS INT 
%left PLUS MINUS 

%% 

exp : exp binaryop term; 
exp : term; 
term : INT; 
binaryop: PLUS | MINUS; 
+0

'%left'沒有生效的原因是它的效果只發生在這些令牌出現的規則中。在'binaryop'中出現'PLUS'和'MINUS'。如果'binaryop'中存在左/右歧義,那麼這個關聯性就會「踢入」來修復它。一旦'PLUS'和'MINUS'減少到'binaryop',那個符號就不再和'PLUS'和'MINUS'以及它們的相關性有關。 'yacc'可以從中受益的一個擴展是允許非終結者具有結合性,所以你可以寫'%left binaryop'。 – Kaz 2012-03-15 22:16:06

+0

或者,'yacc'可以在解析時支持一些語法擴展,例如(PLUS | MINUS)。甚至是在語法分析時展現的宏觀規則。 – Kaz 2012-03-15 22:22:14

+0

@Kaz:這很有道理(優先級只在單個規則中有替代方法時纔有效),但我不記得以前看過它。 – 2012-03-15 23:14:25

4

你需要指定exp binop exp規則優先級,如果你想優先規則來解決歧義:

exp : exp binaryop exp %prec PLUS; 

與該改變,所有的衝突都得到解決。

編輯

的評論似乎表明一些混亂,什麼YACC /野牛優先規則做。

優先規則是一種半自動解決語法中的移位/減少衝突的方法。它們只是半自動的,因爲在指定優先級時,您必須知道自己在做什麼。基本上,每當在要移動的標記和要減少的規則之間存在移位/減少衝突時,yacc比較要移位的標記的優先級和要減少的規則,以及 - 只要兩者都有優先權 - 以較高優先權爲準。如果令牌或規則沒有分配優先級,則將衝突報告給用戶。

%left/%right/%nonassoc當令牌和規則具有相同的優先級時進入圖片。在這種情況下,%left表示執行縮減,%right表示執行移位,而%nonassoc表示兩者都不執行,如果解析器運行到此情況,則會在運行時導致語法錯誤。

優先級本身被分配給標記%left/%right/%nonassoc以及規則%prec。唯一的奇怪之處在於,沒有%prec的規則和RHS上的至少一個終端獲得了RHS上最後一個終端的優先級。這有時最終可能會將優先級分配給您不希望優先考慮的規則,而這些優先規則有時會因錯誤地解決而導致隱藏衝突。您可以通過在相關規則中添加額外級別的間接來避免這些問題 - 將RHS上的有問題的終端更改爲擴展到該終端的新的非終端。

+0

如果取出'%left'聲明並僅引入'%nonassoc LOW'和'%nonassoc HIGH'假冒標記,然後使用'%prec LOW'或'%prec HIGH將語法的所有規則分配優先級',無論使用什麼'LOW'和'HIGH'的組合,你都不會消除s/r衝突。 – Kaz 2012-03-16 02:18:53

+0

I.e.衝突消失的原因並不像它看起來那樣。如果你有'%left PLUS MINUS',那麼'%prec'聲明的所有類型都會壓制衝突。其中一些似乎通過在狀態7中的轉換或減少之間翻轉來使語法正確地聯合起來。 – Kaz 2012-03-16 02:19:21

+0

P.S.我在規則中使用了%prec黑客,如'foo_list:foo_list foo%prec HIGH |/*空* /;'。理由:在'foo_list'和'foo'之間沒有操作符,我們可以爲其指定優先級,並且hack執行這個操作。 – Kaz 2012-03-16 02:25:17

相關問題