2

型名が大文字で始まり、変数名が小文字で始まる、私が設計した言語用のパーサーを構築しています。これにより、レクサーは違いを認識し、異なるトークンを提供できます。また、文字列 'this' はレクサー (OOP 言語) によって認識され、別のトークンとして渡されます。最後に、データ メンバーは「this」オブジェクトでのみアクセスできるため、次のように文法を作成しました。

%token TYPENAME
%token VARNAME
%token THIS

%%

start:
    Expression
    ;

Expression:
    THIS
    | THIS '.' VARNAME
    | Expression '.' TYPENAME
    ;
%%

Expression の最初の規則により、ユーザーは「this」を値として渡すことができます (たとえば、メソッドからそれを返すか、メソッド呼び出しに渡します)。2 つ目は、「this」のデータにアクセスするためのものです。3 番目の規則はメソッドの呼び出しに関するものですが、括弧とパラメーターは問題とは関係がないため削除しました。元の文法は明らかにこれよりもはるかに大きかったが、これは同じエラー (1 Shift/Reduce conflict) を生成する最小の部分である - 私はそれを独自のパーサー ファイルに分離し、これを検証したので、エラーは何の関係もないその他の記号。

私が見る限り、ここで与えられた文法は明確であり、エラーは発生しません。3 つのルールのいずれかを削除するか、2 番目のルールを

Expression '.' VARNAME

競合はありません。いずれにせよ、この競合が発生する理由と解決方法を明らかにする人が必要です。

4

2 に答える 2

4

問題は、文法が 1 つ先しか見ていないことです。したがって、 a のTHIS後に aが表示された.場合、行 2( Expression: THIS '.' VARNAME) または行 3 ( Expression: Expression '.' TYPENAME、行 1 による縮小を介して) にいます。

文法は に還元THIS.してからExpression.a を探すTYPENAMEか、それを にシフトしてa をTHIS.探すことができますVARNAMEが、いつ に到達するかを決定する必要があり.ます。

于 2010-07-30T18:50:36.200 に答える
3

私は y.output を避けようとしますが、時にはそれが役立つこともあります。私はそれが生成したファイルを見て見ました。

state 1

    2 Expression: THIS.  [$end, '.']
    3           | THIS . '.' VARNAME

    '.'  shift, and go to state 4

    '.'       [reduce using rule 2 (Expression)]
    $default  reduce using rule 2 (Expression)

基本的には、「。」が表示されると言っています。減らすことも、シフトすることもできます。リデュースは、細かくするのが難しいため、時々私をアンルグにします。シフトはルール 3 であり、明らかです (ただし、出力ではルール # について言及されていません)。「.」が表示される場所を減らします。この場合、行は

| Expression '.' TYPENAME

Expression に移動すると、次の文字 (「.」) を見て入力します。THIS |そのステートメントの最後に到達すると、「.」が期待されます。それが去ったとき、またはエラー。ただし、この「。」が表示されます。これと「。」の間 (したがって、出力ファイルのドット)、ルールを減らすことができるため、パスの競合が発生します。を使用%glr-parserして両方を試すことができると思いますが、競合が多いほど、予期しない出力またはあいまいなエラーが発生する可能性が高くなります。過去にあいまいなエラーがありました。特に、どのルールが原因または影響したかを覚えていない場合は、対処するのが面倒です。競合を避けることをお勧めします。

バイソンを使用する前に、この本を強くお勧めします。

「素晴らしい」解決策は考えられませんが、これにより競合は発生しません

start:
    ExpressionLoop
    ;

ExpressionLoop:
      Expression
    | ExpressionLoop ';' Expression
    ;
Expression:
      rval 
    | rval '.' TYPENAME
    | THIS //trick is moving this AWAY so it doesnt reduce
rval:

    THIS '.' VARNAME

別の方法として、ルールにさらに追加してすぐに縮小しないようにするか、後または前にトークンを追加して、どのパスを使用するか失敗するかを明確にすることで、後で縮小することができます (すべてのパスを縮小する前に知っておく必要があります)。

start:
    ExpressionLoop
    ;

ExpressionLoop:
      Expression
    | ExpressionLoop ';' Expression
    ;
Expression:
      rval 
    | rval '.' TYPENAME
rval:
      THIS '@'
    | THIS '.' VARNAME
%%

- 編集- レクサー関数による型は Var (A-Za-z09_) と型であるためfunc param、やりたいことができない場合は注意してください。type varnameparam と varname は両方とも var であるため、reduce/reduce の競合が発生します。これをそのままでは書けません。見た目だけです。そのため、書くときはそのことを念頭に置いてください。2 つを区別するトークンを記述するか、2 つのうちの 1 つとして記述する必要がありますが、追加のロジックをコード (ルールの右側の { } にある部分) に記述して、それが funcname であるかどうかを確認する必要があります。タイプと両方のケースを処理します。

于 2010-07-30T20:42:25.490 に答える