LALR(1)ではなく、あいまいな文法、デフォルトでは解析できないyaccモード
長い話を短くするために、%glr-parser
次のように宣言を使用してこれを「修正」できます。
%glr-parser
%%
start: rule1_list
. . .
. . .
ロングストーリーのようなミディアムレングスを作るには...
Shift-reduceの競合は、通常、エラーではありません。競合は、通常は必要なシフトを常に実行することで解決されます。ほとんどまたはすべての実際の文法には、shift-reduceの競合があります。また、削減が必要な場合は、優先順位宣言を使用して削減を調整できます。
ただし、真にあいまいな文法では、シフトを実行すると、パーサーが2つのパスのいずれかに送信され、そのうちの1つだけが最終的に文法内の文字列を検出します。この場合、S/Rの競合は致命的なエラーです。
最初のものを分析すると、パーサーが| rule2 NEWLINE rule3_list
ケース内の改行を検出すると、rule3_listが期待される新しい状態に移行するかrule1: rule2
、を使用してrule1を減らすことができます。デフォルトでshiftが選択されているため、常にrule3_listを検索します。
2番目の競合は、に改行が表示されたときに発生します rule3_list: rule3_list . NEWLINE rule3
。これで、シフトしてrule3の検索を開始するか、を使用してrule1を減らすことができます| rule2 NEWLINE rule3_list
。
その結果、記述されているとおり、端末に「2」と「3」を想定すると、2行の後に3行しか解析できません。優先順位をいじると、「2」行のみを解析でき、「3」行は解析できません。
最後に、yaccで生成されたGLRパーサーを使用することは、ちょっとした悩みの種であることを付け加えておきます。私はそれがうまくいくと思いますが、それは純粋なBFIであり、パーサーは分割し、2つのスタックを保持し、文法に文字列が見つかるまで両方のパスを続行します。悲しいことに、他の修正も問題です。1.文法をLALR(1)として再定式化し、2。スキャナーに先読みを追加し、複合トークンを返します。3 .使用している文法のルールを試してみてください。おそらく、yaccで処理できます。バリエーション。
これが、私が実際にyaccが好きではなく、手書きの再帰下降またはPEGのようなより現代的なものを好む理由です。(Treetopを参照してください。)
改行を単に無視する(推奨される)左再帰ルールで何かを試しました(文法が複雑になり、空白トークンが作成されます...)..そしてこれは「機能」しますが、それがあなたの望むものかどうかはわかりません。 ..
%%
start: stmtList
;
stmtList: /* nothing */
| stmtList '2' threeList;
;
threeList: /* nothing */
| threeList '3'
;
%%
int yylex() { int c; do { c = getchar (); } while (c == '\n'); return c; }