2014-01-09 47 views
0

我正在嘗試用Yecc編寫一個Erlang解析器,但我在語義規則的優先級上遇到了一些麻煩。在我的例子中,我定義了語法,終端和非終端符號,規則和相關的代碼。Erlang的Yecc優先問題

這是我寫的測試。

%Grammar non terminals 
Nonterminals product require require1 mandatory mandatory1. 

%Grammar terminals 
Terminals  'tick' 'feature' '(' ')' 'req' 'mand' ';' 'nil'. 

%Initial symbol 
Rootsymbol product. 

%Operands priority 

Left 200 require. 
Left 190 require1. 
Left 180 mandatory. 
Left 170 mandatory1. 

Left 80 'req'. 
Left 60 'mand'. 
Left 50 ';'.  %Secuence 
Left 40 'feature'. %Optional feature 



%-------------------------------------------------- 
%Grammar with operational rules 

%[req1 & req2] 
product -> require: '$1'. 
require -> feature req feature '(' feature ';' product ')' : if 
                    '$1' == '$5' -> {'$5', {'$4', '$7', '$8', {mand,1}, '$3'}}; 
                    true   -> {'$5', {'$1', '$2', '$3', '$4', '$7', '$8'}} 
                   end. 
%[req3] 
product -> require1 : '$1'. 
require1 -> feature req feature '(' tick ')' : {nil,1}. 



%[mand2 & mand3] 
product -> mandatory : '$1'. 
mandatory -> '(' feature ';' product ')' mand feature : if 
                 '$2' == '$7' -> {'$2', {'$4'}}; 
                 true   -> {'$2',{'$1', '$4', '$5', '$6', '$7'}} 
                end. 


%[mand1] 
product -> mandatory1: '$1'. 
mandatory1 -> '(' tick ')' mand feature : {$5, {tick,1}}. 


%[tick] 
product -> feature ';' tick : {'$1', {nil,1}}. 
product -> nil. 
product -> feature ';' product : {'$1', {'$3'}}. 


Erlang code.  
%To remove brackets and return only the third parameter, right now is not used. 
unwrap_feature({_,_,V}) -> V. 


%%How to compile and use 
%Save this as stack.yrl 
%Run erl and then 
%yecc:yecc("stack.yrl","stack.erl"). 
%c(stack). 

現在讓我們執行一個特定的術語來檢查規則是如何應用的。

stack:parse([{feature,1,'A'},{'req',1},{feature,1,'C'},{'(',1},{feature,1,'A'},{';',1},{feature,1,'B'},{';',1},{feature,1,'C'},{';',1},{tick,1},{')',1}]). 

解析器輸出是:

{ok,{{feature,1,'A'}, 
    {{'(',1}, 
     {{feature,1,'B'},{{{feature,1,'C'},{nil,1}}}}, 
     {')',1}, 
     {mand,1}, 
     {feature,1,'C'}}}} 

但我需要這個。只要解析器處理該術語(如調試輸出),我就會寫輸出。

初始期限。

{feature,1,'A'},{'req',1},{feature,1,'C'},{'(',1},{feature,1,'A'},{';',1},{feature,1,'B'},{';',1},{feature,1,'C'},{';',1},{tick,1},{')',1} 

規則%[req1 & req2]。 (這是正確應用 - 案例「$ 1」 ==「$ 5」)

{feature,1,'A'},{{'(',1},{feature,1,'B'},{';',1},{feature,1,'C'},{';',1},{tick,1},{')',1},{mand,1},{feature,1,'C'}} 

現在,我不知道會發生什麼,但輸出應該不過的了。

規則%[mand2 & mand3]。 (情況真)

{feature,1,'A'},{{feature,1,'B'},{{'(',1},{feature,1,'C'},{';',1},{tick,1},{')',1},{mand,1},{feature,1,'C'}}} 

規則%[mand2 & mand3]。 (案例'$ 2'=='$ 7')

{feature,1,'A'},{{feature,1,'B'},{{feature,1,'C'},{{tick,1}}}} 

規則%[tick] - 和最終結果。

{feature,1,'A'},{{feature,1,'B'},{{feature,1,'C'},{{{tick,1},{nil,1}}}}} 

我已經嘗試過這樣的:

由於Yecc手冊中解釋,我能做到這一點:

  • 與運算符優先播放。
  • 將規則應用於優先級。 從文檔(也可以聲明優先級爲 非終端,「上一級」。當操作員重載 (參見下面的示例3)時,這是實用的)。

但它似乎並沒有爲我工作。任何幫助?

謝謝!

回答

1

就在幾個注意事項:

1. Left 200 require. Left 190 require1. Left 180 mandatory. Left 170 mandatory1.無效。這些不是運營商,因爲它們不在->的右側。

  1. 再次約requirerequire1mandatorymandatory1:這些都不是相互抵觸的規則。只需編寫product -> feature req feature '(' feature ';' product ')': …. product -> feature req feature '(' tick ')': …. …

  2. 爲什麼你有時會添加{·,1}?這應該是詞法分析師的工作。

+0

嗨!感謝您的回答。 1-我只是在require ,require1,mandatory和mandatory1這兩個術語的優先部分中放了一些權重,以查看是否改變了解析器的行爲(不起作用:(): 2- require,require1,mandatory和mandatory1是輔助術語,也用於檢查是否通過添加一些權重優先級可以改變解析器的行爲(如文檔中詳述的) 3-您的意思是{mand,1} ??這是因爲y想要改變該術語使其符合其他規則。首先它沒有{mand,1}而不是{req,1},因此它符合一些或其他規則。 – ccamacho

+0

這是文檔的參考文獻 「這是當操作員超載時也很實用(參見下面的示例3)「,http://erldocs.com/R14B01couch/parsetools/yecc.html – ccamacho

1

我在我工作的Lua的解析器中遇到同樣的問題。我發現的解決方案是,您需要使用相同的終端內的運營商才能正常工作。如果你能

bin_op -> exp '+' exp : ... . 
bin_op -> exp '-' exp : ... . 
... 
bin_op -> exp 'and' exp -> ... . 
bin_op -> exp 'or' exp -> ... . 

因此,像

Left 80 'req'. 
Left 60 'mand'. 
Left 50 ';'.  %Secuence 
Left 40 'feature'. %Optional feature 

product -> feature 'req' feature : ... . 
product -> feature mand feature : ... . 
product -> feature ';' feature : ... . 

這當然不是並不總是可行的:我就能把它伸到其處理的所有二進制運算其中有一個優先級一個終端。如果你看看在yecc文檔中使用優先級的例子,它們的結構就像這樣。另外,如果你看一下erlang語法,你會發現它不使用優先級,但明確地確定每個優先級。

在你的情況下,只有四個級別應該是相對容易的。

+0

我將重寫規則作爲操作數運算符來查看會發生什麼。 :) – ccamacho

+0

不,我不能將規則重寫爲操作數運算符操作數,就像在規則[req1&req2]中我必須問'$ 1'=='$ 5'。 我需要整個規則,當它匹配的模式具有比其他規則誰也匹配更多...優先 我沒有什麼測試更多的想法.. :( – ccamacho

+0

我不認爲你可以將運算符優先級放在非終端上,我沒有嘗試過,但是文檔只顯示終端,我已經加載了.yrl,並試圖理解它,你有沒有更好的例子說明你喜歡它以處理各種輸入,[...] ==> {...}?將嘗試在今天晚些時候或明天回來。 – rvirding