3

私はドメイン固有言語を開発しています。言語の一部は、精度や記号などのセマンティクスを解析するC式とまったく同じです。

レモンパーサーを使用しています。同じトークンが2つの異なる目的で使用されているという問題が発生しましたが、レクサーの違いがわかりません。アンパサンド(&)記号は、「ビット単位」と「アドレス」の両方に使用されます。

最初は、それらが同じ結合性を持っていないことに気付くまで、それは些細な問題だと思いました。

同じトークンに2つの異なる関連性を与えるにはどうすればよいですか?AMPを(アンパサンドのように)使用してaddressofとbitwiseを作成し、ルールでAMPを使用するか、別のトークン(ADDRESSOFやBITWISE_ANDなど)を使用する必要があります。別々の記号を使用する場合、どのようにしてレクサーからどれを知る必要がありますか(パーサー自体でないとわかりません!)。

4

2 に答える 2

3

「優先順位」レベルごとに異なる非終端記号を使用してルールを明示的に書き出す場合は、優先順位を宣言する必要はまったくなく、そうすべきではありません。

レモンは、すべてのyacc派生語と同様に、優先順位宣言を使用して、あいまいな文法からあいまいさを取り除きます。参照される特定のあいまいな文法は次のとおりです。

expression: expression '+' expression
          | expression '*' expression
          | '&' expression
          | ... etc, etc.

その場合、すべての選択肢がシフト削減の競合につながります。パーサジェネレータに優先順位ルールがない場合、または正確にしたい場合は、それを明確な文法として記述する必要があります(これはあなたが行ったことです)。

term: ID | NUMBER | '(' expression ')' ;
postfix_expr:        term | term '[' expression '] | ... ;
unary_expr:          postfix_expr | '&' unary_expr | '*' unary_expr | ... ;
multiplicative_expr: unary_expr | multiplicative_expr '*' postfix_expr | ... ;
additive_expr:       multiplicative_expr | additive_expr '+' multiplicative_expr | ... ;
...
assignment_expr:     conditional_expr | unary_expr '=' assignment_expr | ...; 
expression:          assignment_expr ;
[1]

明確な文法は、左結合(上記の乗法および加法)および右結合(少し奇妙ですが、以下を参照)を示していることに注意してください。したがって、あいまいさは実際にはありません。

現在、優先順位宣言(%left、、%rightなど)は、曖昧性解消のためにのみ使用されています。あいまいさがない場合、宣言は無視されます。パーサジェネレータは、文法が反映されているかどうかさえチェックしません。(実際、多くの文法はこの種の優先関係として表現することはできません。)

したがって、文法が明確な場合は、優先順位の宣言を含めることは非常に悪い考えです。それらは完全に間違っている可能性があり、文法を読む人を誤解させる可能性があります。それらを変更しても、言語の解析方法には影響しません。これにより、文法を編集したい人を誤解させる可能性があります。

優先順位規則を使用してあいまいな文法を使用する方がよいのか、それとも明確な文法を使用する方がよいのかについて、少なくともいくつかの疑問があります。C単純な優先順位リストでは文法を表現できないような言語の場合は、あいまいでない文法を使用する方がおそらく良いでしょう。ただし、明確な文法にはより多くの状態があり、パーサジェネレータが単位削減を最適化できない限り、構文解析がわずかに遅くなる可能性があります(上記の文法の最初の選択肢はすべて、各式のタイプが前のものである可能性があります) ASTに影響を与えない式タイプ。ほとんどの場合は操作なしであり、多くのパーサジェネレーターがコードを挿入しますが、これらの各プロダクションを減らす必要があります。)

優先関係が正確に代入演算子であるため、理由Cを単純に表現することはできません。検討:

a = 4 + b = c + 4;

assignment-expressionでは、代入演算子は左側でのみ適用できるため、これは解析されませんunary-expression+これは、との間の可能な数値の優先順位を反映していません=。[2]

+よりも優先順位が高い場合=、式は次のように解析されます。

a = ((4 + b) = (c + 4));

+優先順位が低い場合は、次のように解析されます

(a = 4) + (b = (c + 4));

[1] cast_expressionを省略したことに気づきましたが、キャストして元に戻すことはできません。あなたはアイデアを得る)

[2]説明が修正されました。

于 2012-12-28T23:56:48.620 に答える
0

後で、間接参照(*)と乗算(*)の間に同じあいまいさがあることに気付きました。

レモンは、ピリオドの後に角括弧で囲まれた結合法則宣言(%left / right / nonassoc)で使用される名前を使用して、ルールに優先順位を割り当てる方法を提供します。

これが正しく機能することはまだ確認していませんが、これは可能だと思います(最後の方にある角かっこで囲まれていることに注意してください)。

.
.
.

%left COMMA.
%right QUESTION ASSIGN
    ADD_ASSIGN SUB_ASSIGN MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN
    LSH_ASSIGN RSH_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN.
%left LOGICAL_OR.
%left LOGICAL_AND.
%left BITWISE_OR.
%left BITWISE_XOR.
%left BITWISE_AND.
%left EQ NE.
%left LT LE GT GE.
%left LSHIFT RSHIFT.
%left PLUS MINUS.
%left TIMES DIVIDE MOD.
//%left MEMBER_INDIRECT ->* .*
%right INCREMENT DECREMENT CALL INDEX DOT INDIRECT ADDRESSOF DEREFERENCE.

.
.
.

multiplicative_expr ::= cast_expr.
multiplicative_expr(A) ::= multiplicative_expr(B) STAR cast_expr(C). [TIMES]
    { A = Node_2_Op(Op_Mul, B, C); }
.
.
.
unary_expr(A) ::= STAR unary_expr(B). [DEREFERENCE]
    { A = Node_1_Op(Op_Dereference, B); }
于 2012-12-28T22:36:53.130 に答える