yacc で条件付きコンパイルを行う方法。ifdef を使用して C で行うのと同様です。
条件に基づいてルールを作成したい。yaccで可能ですか?例。条件ルール A に基づいて、次のように定義されます。
ruleA : A | B, /* For condition 1 */
ruleA : C /* If condition 1 is not satisfied */
yacc で条件付きコンパイルを行う方法。ifdef を使用して C で行うのと同様です。
条件に基づいてルールを作成したい。yaccで可能ですか?例。条件ルール A に基づいて、次のように定義されます。
ruleA : A | B, /* For condition 1 */
ruleA : C /* If condition 1 is not satisfied */
btyaccには、C プリプロセッサと同様に、定義されたフラグに基づく条件付きコンパイルがあります。あなたは言うことができます:
%ifdef VERSION_A
ruleA: A | B ;
%endif
%ifdef VERSION_B
ruleA: C ;
%endif
次に、-DVERSION_A
または-DVERSION_B
コマンド ライン引数を使用して、いずれかのバージョンを取得します。それはかなり原始的です( ごとに単一のフラグしかテスト%ifdef
できず、 をネストできず、 も%ifdef
ありません%else
)、単純なことには十分です。
私の提案は、条件付きフラグをターミナル シンボルとして公開することです。これをモード ターミナルと呼ぶことができます。(つまり、技術的には、これはコンパイル時ではなく実行時の条件です。)
解析に違いが生じるたびに、モード ターミナルを返す必要があります。余分なものを受け取ると、文法はそれを無視できます。モード端子は「条件1」の場合のみ、「条件1でない」の場合のみ、または両方の場合で別のものを返すことができます。つまり、各モードに 1 つずつ、2 つのトークン C1 と C2 があるとします。
既存の文法を解析している場合、これはうまくいかないかもしれませんが、文法とパーサーを一緒に設計している場合、すべての問題は解決可能です。
次に、次のようになります。
ruleA : C1 A | C1 B | C2 C ;
Yacc 文法を適切なプリプロセッサで前処理できない場合は、アクションに基づくソリューションを使用できます。
ruleA : A { if (condition1) { process OK; } else YYERROR; }
| B { if (condition1) { process OK; } else YYERROR; }
| C { if (!condition1) { process OK; } else YYERROR; }
;
YYERROR アクションは、Yacc の通常のエラー処理メカニズムをトリガーします。これは、Yacc に関する限り、文法が動作中の両方のルール セットで「機能する」必要があることを意味します。これがシフト/リデュース (またはリデュース/リデュース) の競合のために複雑になる場合は、前処理が最適です。結果の文法はより小さくなり、より焦点が絞られます。