0

我正在尝试使用 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))。

但这似乎对我不起作用。有什么帮助???

谢谢!

4

2 回答 2

1
于 2014-01-09T10:09:25.877 回答
1

I had the same problem in a parser for Lua on which I was working. The solution I found was that you need to use the operators within the same terminal for it to work. I could break it out into one terminal which handled all the binary operators which had a precedence:

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

So if you could something like

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 : ... .

This is not of course not always possible. If you look at the examples which use precedence in the yecc documentation they are structured like this. Also if you look at the erlang grammar you will see that it does not use precedence but does each precedence level explicitly.

In your case with only four levels it should be relatively easy.

于 2014-01-09T19:28:40.893 回答