C# スタイルのラムダで拡張された式の文法は LALR(1) ではありませんが、おそらく LALR(2) です。その結果、同等の LALR(1) 文法を生成することが可能です (必ずしも自明ではありません): 以下の編集を参照してください。
入力で削減/削減の競合が発生します。
( id )
は (2 番目のケースでは間接的に)または(間接的に)id
に還元される可能性があり、パーサーは 1 つの先読みトークン ( ) に基づいてどちらが正しいかを判断できないためです。identifier_list
expression
)
identifier_list
2 番目の次のトークンが である場合にのみ削減が可能であり、言語の演算子でない限り=>
、 2 番目の次のトークンが である場合は削減できないため、2 つの先読みトークンに基づいて判断できます。なので断言はできませんが、おそらくLALR(2)だと思います。=>
expression
=>
複数の識別子がある場合は問題ありません。
( id1 id2 )
id1 id2
式に還元することはできません (ほとんどの式言語では、もちろん、あなたのものは異なるかもしれません)。=>
`=>' が有効な演算子でない限り、括弧で囲まれていない単一の識別子が直後に続く場合も問題にはなりません。
編集
元の回答で、LALR(2) 言語のようなものは存在しないと言い忘れていました。LALR(2) 文法で認識される言語は、一部の LALR(1) 文法でも認識されます。実際、この主張の建設的な証明があり、元の構文木を復元する手順とともに、そのような LALR(1) 文法を機械的に作成できます。
この場合、上で述べたように、追加の先読みを必要とするプロダクションは 1 つしかないため、LALR(1) 文法を生成する方がさらに簡単です。解決策は、削減を 1 トークン遅らせることです。つまり、元の文法には次のようなものが含まれます。
primary: '(' expression ')'
lambda_parameters: '(' id_list ')'
ここで、 と の両方が端末id_list
をexpression
派生させますID
。は別としてID
、これら 2 つの非終端記号の派生は素であるため、次のように問題を解決できます。
primary: '(' expression_not_id ')'
| '(' ID ')'
lambda_parameters: '(' id_list_not_id ')'
| '(' ID ')'
残りは、 と の作品を分割して、ケースを分離するだけですがexpression
、id_list
これID
はそれほど難しいことではありません。以下は、簡単に拡張できる簡単な例です。加算、乗算、および関数の適用に制限されています (2 つのカンマ区切りのリストが問題にならないことを示すために含めました)。
%token ID LITERAL RIGHT_ARROW
%start expr
%%
primary: primary_not_id | ID ;
term: term_not_id | ID ;
sum: sum_not_id | ID ;
expr: expr_not_id | ID ;
expr_list: expr | expr_list ',' expr ;
arguments: '(' ')' | '(' expr_list ')' ;
ids: ID ',' ID | ids ',' ID ;
parameters: '(' ID ')' | '(' ids ')' ;
primary_not_id: LITERAL
| '(' expr_not_id ')'
| '(' ID ')'
| primary arguments
;
term_not_id: primary_not_id
| term '*' primary
;
sum_not_id: term_not_id
| sum '+' term
;
expr_not_id: sum_not_id
| parameters RIGHT_ARROW expr
;
注: OP の文法は、コンマで区切られていない一連の識別子として、複数のパラメーターを持つラムダを生成します: (a b) => a + b
. 実際の意図はコンマを使用することだったと思います: (a, b) => a + b
、そしてそれが上記の文法で行ったことです。C ファミリのように言語にカンマ演算子がある場合、この違いは重要です。その場合、式が になる可能性があり'(' expression_list ')'
、ラムダ パラメータ リストと競合するからです。単純な実装では、が任意に長くなる可能性があるため、有限先読みでは解決できないの最初expression
のリデュース/リデュース コンフリクトが発生します。expression_list
expression_list
ただし、この場合にも解決策があります。次のようにid_list
から分離することで構成されます。expression_list
id_list: ID
| id_list ',' ID
;
expression_list_not_id_list: expression_not_id
| id_list ',' expression_not_id
| expression_list_not_id_list ',' expression
;
expression_list: expression_list_not_id_list
| id_list
;
ただし、ターゲット言語が何を必要としているのかわからないため、完全な文法は実行しませんでした。