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]。(これは正しく適用されます – Case '$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}}}}

Rule %[tick] – 最終結果。

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

私はすでにこれを試しました:

Yeccマニュアルで説明されているように、私はこれを行うことができました:

  • 演算子の優先順位で遊んでいます。
  • ルールに優先順位を適用します。ドキュメントから (「1 レベル上」の非端末の優先順位を宣言することも可能です。これは、演算子がオーバーロードされている場合に実用的です (以下の例 3 も参照))。

しかし、それは私にはうまくいかないようです。助けて?

ありがとう!

4

2 に答える 2

1

私が取り組んでいたLuaのパーサーでも同じ問題がありました。私が見つけた解決策は、同じ端末内で演算子を使用して機能させる必要があるということでした。優先順位のあるすべての二項演算子を処理する 1 つの端末に分割できます。

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 の文法を見ると、優先順位は使用されていませんが、各優先レベルが明示的に使用されていることがわかります。

レベルが 4 つしかないあなたの場合、比較的簡単なはずです。

于 2014-01-09T19:28:40.893 に答える