Erlang的Yecc优先级问题

时间:2014-01-09 08:21:22

标签: erlang grammar bnf lalr

我正在尝试用Yecc编写一个Erlang解析器,但是我在语义规则的优先级方面遇到了一些麻烦。在我的例子中,我定义了语法,终端和非终端符号,规则和相关代码。

这是我为测试而写的。

%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))。

但它似乎对我不起作用。任何帮助???

谢谢!

2 个答案:

答案 0 :(得分: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. 即可
  3. 为什么有时会添加{·,1}?那应该是词作者的工作。

答案 1 :(得分: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语法,你会看到它不使用优先级,但是明确地表示每个优先级。

在只有四个级别的情况下,它应该相对容易。