0

の排他的サブセットであるIDENTIFIER_ONE2つの識別子のセットを定義しました。次のようなパーサーを書きたいと思います。IDENTIFIER_TWOIDENTIFIER

"i1(arg) EOS" can't be parsed (1)
"i2(arg) EOS" can be parsed (2)
"i1(arg) = value EOS" can be parsed (3)
"i2(arg) = value EOS" can be parsed (4)

どこでi1(resp., ) は( resp., i2) に属します。に属します。以下は、私が求めているすべてのポイントをすでに実現しています。IDENTIFIER_ONEIDENTIFIER_TWOargvalueIDENTIFIERparser.mly(4)

identifier:
| IDENTIFIER_ONE { $1 }
| IDENTIFIER_TWO { $1 } 

block_statement_EOS:
| identifier LPAREN identifier RPAREN EQUAL identifier EOS { BSE_Let ($1, $3, $6) }
| IDENTIFIER_TWO LPAREN identifier RPAREN EOS { BSE_I_I ($1, $3) }

入力として与えられるi1(arg) = value EOSと、目標として(3)正しく読み取られBSE_Let (i1, arg, value)ます。ただし、i2(arg) = value EOS入力として与えられると、読み取り後に解析が停止しますEQUALi2(arg)解析が を満たすと、 の 2 番目のルールに進みblock_statement_EOS、後でEQUAL解析できないためだと思います。

理想的には、2 番目のルールが失敗した場合、パーサーが 1 番目のルールを試行できることを願っていblock_statement_EOSます。これを可能にするために誰か助けてもらえますか?

PS : 次のように記述すればparser.mly、すべての目標を達成できます。誰かが理由を知っていますか?さらに、他の多くのルールでは 2 つのサブセットの代わりに記述する必要があるため、この回避策は本当に好きではありませんidentifier。よりエレガントなソリューションを期待しています...

block_statement_EOS:
| IDENTIFIER_ONE LPAREN identifier RPAREN EQUAL identifier EOS { BSE_Let ($1, $3, $6) }
| IDENTIFIER_TWO LPAREN identifier RPAREN EQUAL identifier EOS { BSE_Let ($1, $3, $6) }
| IDENTIFIER_TWO LPAREN identifier RPAREN EOS { BSE_I_I ($1, $3) }
4

1 に答える 1

0

パーサーが のLPAREN後にIDENTIFIER_TWOを検出すると、シフトするか削減するかを決定する必要があります。

  • shift:LPARENスタックに置きます。
  • reduce:IDENTIFIER_TWOスタックの一番上にある を で置き換えますidentifier

パーサーがシフトすることを選択した場合、この特定のものを に減らすことはありませんIDENTIFIER_TWO(identifierこの特定IDENTIFIER_TWOのものは再びスタックの一番上に置かれることはないため) block_statement_EOS

block_statement_EOSパーサーが削減を選択した場合、この規則は ではなく で始まるため、 の 2 番目の規則を削減することはIDENTIFIER_TWOありませんidentifier

これが、2 番目のバージョンが機能する理由IDENTIFIER_TWOです。必要に応じて、選択は後で行われます。

于 2014-01-29T09:37:59.770 に答える