0

次のコードがあります。

case 1
of 2
    3
of 3
    4
5

私のカスタム トークナイザーは次のように変換されます。

Tokens: [{'case',1},
         {integer,1,1},
         {eol,1},
         {'of',1},
         {integer,1,2},
         {block,[{integer,1,3}]},
         {eol,1},
         {'of',1},
         {integer,1,3},
         {block,[{integer,1,4}]},
         {eol,1},
         {integer,1,5}]

しかし、次の Yecc では解析できません。

Nonterminals
    grammar
    statements statement
    case_def case_conditions condition.


Terminals
    eol block
    integer
    case of.


Rootsymbol grammar.


grammar -> statements : '$1'.


statements -> statement eol statements : ['$1'|'$3'].
statements -> statement : ['$1'].

statement -> case_def : '$1'.
statement -> integer : '$1'.


case_def -> 'case' integer case_conditions : ''.

case_conditions -> case_condition case_conditions : ['$1'|'$2'].
case_conditions -> case_condition : ['$1'].

case_condition -> eol 'of' integer block : ''.

次の出力が得られます。

["syntax error before: ","5"]

どんな助けでも大歓迎です、ありがとう。

4

1 に答える 1

1

非終端リストでは、case_condition代わりにcondition.

カスタム スキャナーはインデントを無視します。と のトークンを発行する必要がINDENTありDEDENTます。yacc で例を見つけました。次に、それらのトークンを使用するように文法を変更できます。

あなたの例は、シフト/削減の競合を生成します。ドキュメントには、次のように記載されています。

演算子の優先順位宣言がない場合、シフト/リデュースの競合はシフトを優先して解決されます。

つまり、パーサーが|

of 3
    4|
5

改行が表示される場合、2 つのオプションがある可能性があります。

  • これは次の可能性があるcase_conditionため、パーサーは続きを読むために「シフト」し続ける必要があります
  • これはステートメントの終わりである可能性があるため、パーサーは前のすべてをステートメントとして処理し、スタックに置くか、つまり「削減」する必要があります

これらの競合は常にシフトに解決されるため、ケースを開始した後に次のステートメントを入れることはできません! 文法を変える必要があります。yecc:file/1で警告が生成されなくなるまで作業します。

ヒント: ケース内のすべてを次のようにインデントします。

case 1
    of 2
        3
    of 3
        4
5

このように、あなたは明確に、それcaseは 1 つのステートメントであり、5別のステートメントであると言っています。パーサーに関する私の知識は少しさび付いていましたが、インデントや何らかのターミネーターを追加しないcase_conditionと、左から右のパーサーを区別できる文法を書くことはできないと思います。statement

于 2014-12-04T06:47:06.307 に答える