2013-09-22 77 views
1

下面是一個說明我的問題的Bison語法。我使用的實際語法比較複雜。野牛:如何解決減少/減少衝突

%glr-parser 
%% 
s : e | p '=' s; 
p : fp | p ',' fp; 
fp : 'x'; 
e : te | e ';' te; 
te : fe | te ',' fe; 
fe : 'x'; 

輸入的一些例子是:

x 
x = x 
x,x = x,x 
x,x = x;x 
x,x,x = x,x;x,x 
x = x,x = x;x 

我後是對的「=」左側X的比那些右邊不同解析。然而,可能出現在'=' - 符號右側的法律「表達式」集合大於左側的(由於';')。

野牛打印消息(輸入文件是test.y):

test.y: conflicts: 1 reduce/reduce. 

必須有解決這個問題的一些方式。在C中,你有類似的情況。下面的程序通過gcc沒有錯誤。

int main(void) { 
    int x; 
    int *px; 
    x; 
    *px; 
    *px = x = 1; 
} 

在這種情況下,「PX」和「X」得到不同的待遇取決於他們是否出現一個「=」的左邊或右邊 - 標誌。

回答

2

您使用的是%glr-parser,因此無需「修復」減少/減少衝突。 Bison只是告訴你有一個,所以你知道你的語法可能不明確,所以你可能需要添加%dprec%merge指令的歧義解決方案。但就你而言,語法並不含糊,所以你不需要做任何事情。

衝突不是錯誤,它只是表明您的語法不是LALR(1)。

2

的減少,降低你的語法衝突來自於背景:

... = ... x , 

在這一點上,解析器必須決定x是否是fefp,它不能與一個符號前瞻知道。事實上,它無法知道任何有限的預測,您可以在該點之後進行任意數量的重複,而不會遇到=,;或輸入的結束,其中任何一個都會揭示答案。

這與C問題並不完全相同,可以用單符號預測解決。然而,這個C例子是爲什麼SLR(1)語法不如LALR(1)語法強大的典型例證 - 它在龍書中用於這個目的 - 類似的有問題的語法就是一個例子LALR(1)和LR(1);

def: param_spec return_spec ','; 

param_spec: type | name_list ':' type; 

return_spec: type | name ':' type; 

type: "id"; 
name: "id"; 
name_list: name | name ',' name_list; 

(野牛手冊介紹如何解決此問題的LALR(1)語法,雖然使用GLR語法始終是一種可能性)

:它可以在野牛手冊( here)被發現

解決此類衝突而不使用GLR語法的關鍵是避免強制解析器做出過早的決定。

例如,在左值和右值之間進行語法區分是傳統的,並且一些語言繼續這樣做。然而,C和C++不會;這在C++中是一個非常強大的功能,因爲它允許定義可以充當左值的函數。我認爲這只是爲了簡化語法:C語法允許任何一元運算符的結果出現在賦值運算符的左側,但一元運算符實際上是左值的混合( *vv[expr])和右值(sizeof v,f(expr))。文法可能已經區分了兩種一元運算符,但它不能解決實際的限制,也就是說只能在賦值運算符的左側出現左值。

C++允許任意表達式出現在賦值運算符的左側(儘管有些需要用括號括起來);因此,以下是完全合法的:

(predicate(x) ? *some_pointer : some_variable) = 42; 

在你的情況,你可以通過語法與p更換te解決衝突,因爲這兩個非終端產生相同的一組推導的。這可能不是一般的解決方案,除非在完整語法中確實如此,左側表達式是右側表達式的嚴格子集。在一個完整的語法中,最終可能會有三種類型的表達式(僅用於左對齊,僅用於右對齊,常見),這可能會使語法複雜化得太多,而留下語義分析的解決方案可能會更容易(甚至作爲在C++的情況下,令人驚訝的有用)。

+0

我沒有看到C如何使用語法來區分左值和右值。從[ ] [C語法](http://www.lysator.liu.se/c/ANSI-C-grammar-y.html)可以得到語句 [CONSTANT = CONSTANT](https:// gist.github.com/toddkfisher/6665271)。 – tkf

+0

@tkf:是的,是的。消除這種推導(以及右值位於賦值左側的其他錯誤)會使語法的顯示覆雜化,但直到區分左值和右值纔有可能。 (與C++不同) – rici