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 も参照))。
しかし、それは私にはうまくいかないようです。助けて?
ありがとう!