3

私は、一見単純なシフト/削減の競合に無駄に取り組んでいます。当然、競合を無視すればパーサーは正常に機能しますが、ルールを再編成した方がはるかに安全だと感じます。ここでは、比較的複雑な文法を単一の競合に単純化しました。

statement_list
  : statement_list statement 
  | 
  ;

statement
  : lvalue '=' expression
  | function
  ;

lvalue
  : IDENTIFIER
  | '(' expression ')'
  ;

expression
  : lvalue
  | function
  ;

function
  : IDENTIFIER '(' ')'
  ;

yaccのverboseオプションを使用すると、前述の競合のある状態を説明する次の出力ファイルを取得します。

state 2

    lvalue  ->  IDENTIFIER .   (rule 5)
    function  ->  IDENTIFIER . '(' ')'   (rule 9)

    '('  shift, and go to state 7

    '('  [reduce using rule 5 (lvalue)]
    $default reduce using rule 5 (lvalue)

助けてくれてありがとう。

4

1 に答える 1

5

問題は、ステートメントの最後に到達したことを知るために2トークンの先読みが必要になることです。フォームを入力した場合:

ID = ID ( ID ) = ID

パーサーが2番目のIDをシフトした後(先読みは)、それが最初のステートメントの終わり( 2番目のステートメントの始まり)であるか、これが関数である(かはわかりません。(したがって、シフトします(関数の解析を続行します)。これは、上記の入力例では間違っています。

function括弧内の引数を許可し、実際の式を許可するように拡張するexpressionと、必要な先読みが無制限になるため、状況はさらに悪化します。パーサーは=、これが関数呼び出しではないことを判別するために、秒まで到達する必要があります。

ここでの基本的な問題は、パーサーがステートメントの終わりを見つけるのを助けるためのヘルパー句読点がないことです。有効なステートメントの先頭であるテキストも有効なステートメントの途中に表示される可能性があるため、ステートメントの境界を見つけるのは困難です。

于 2011-01-14T18:12:20.260 に答える