我正在尝试用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手册中所解释的那样,我能够做到这一点:
但它似乎对我不起作用。任何帮助???
谢谢!
答案 0 :(得分:1)
只是几点说明:
1。
Left 200 require.
Left 190 require1.
Left 180 mandatory.
Left 170 mandatory1.
无效。这些不是运算符,因为它们不在->
的右侧。
再次关于require
,require1
,mandatory
和mandatory1
:这些不是冲突的规则。只需写下product -> feature req feature '(' feature ';' product ')': …. product -> feature req feature '(' tick ')': …. …
为什么有时会添加{·,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语法,你会看到它不使用优先级,但是明确地表示每个优先级。
在只有四个级别的情况下,它应该相对容易。