Javaで論理演算子と関係演算子の組み合わせを計算するために、次の文法を作成しました。
文法では、Equals opertor(=
)はSTRING型にのみ使用でき、INT型とBOOLEAN型には使用できません。誰かが私が何が悪いのかを特定するのを手伝ってもらえますか?
私はできること("a" == "b")
とできないこと("a" == 567)
。左側のオペランドは可変であり、実行時に値を置き換えます。
grammar testGrammar;
/*
* Parser rules
*/
conditionalExpression: leftOperand=conditionalExpression operator=LOGICAL_OPERATORS rightOperand=conditionalExpression #LogicalOperators
| '(' conditionalExpression ')' #ParenthesisExpression
| leftOperand=STRING operator=BOOLEAN_RELATIONAL_OPERATORS rightOperand=BOOLEAN #RelationalBooleanOperators
| leftOperand=STRING operator=STRING_RELATIONAL_OPERATORS rightOperand=STRING #RelationalStringOperators
| leftOperand=STRING operator=INT_RELATIONAL_OPERATORS rightOperand=INT #RelationalIntOperators
;
/*
* Lexer rules
*/
STRING: '"'CHAR(CHAR)*'"';
INT:DIGIT+;
BOOLEAN: BOOLEAN_TRUE | BOOLEAN_FALSE;
LOGICAL_OPERATORS: LOGICAL_OR | LOGICAL_AND | LOGICAL_NOT;
STRING_RELATIONAL_OPERATORS: RELATIONAL_EQUALS | RELATIONAL_NOT_EQUAL;
INT_RELATIONAL_OPERATORS: RELATIONAL_EQUALS | RELATIONAL_NOT_EQUAL | RELATIONAL_GREATER_THEN
| RELATIONAL_GREATER_THEN_OR_EQUAL | RELATIONAL_LESS_THEN | RELATIONAL_LESS_THEN_OR_EQUAL;
BOOLEAN_RELATIONAL_OPERATORS: RELATIONAL_EQUALS | RELATIONAL_NOT_EQUAL;
fragment RELATIONAL_EQUALS: '==';
fragment RELATIONAL_NOT_EQUAL: '!=';
fragment RELATIONAL_GREATER_THEN: '>';
fragment RELATIONAL_LESS_THEN: '<';
fragment RELATIONAL_GREATER_THEN_OR_EQUAL: '>=';
fragment RELATIONAL_LESS_THEN_OR_EQUAL: '<=';
fragment LOGICAL_AND: '&&';
fragment LOGICAL_OR: '||';
fragment LOGICAL_NOT: '!';
fragment CHAR: [a-zA-Z_];
fragment DIGIT: [0-9];
fragment BOOLEAN_TRUE: 'true';
fragment BOOLEAN_FALSE: 'false';
入力==
またはに一致する複数のレクサールールがあります!=
。ANTLR(およびほとんどのレクサージェネレーター)は、最初に最長の一致を生成するものを選択することによって(この場合、すべてのルールが長さ2の一致を生成する)、レクサールールのあいまいさを解決し、次に1つを選択することによって同点を解決します。それは文法の最初に来ます。したがって、レクサーが==
または!=
を検出すると、常にタイプのトークンが生成されますSTRING_RELATIONAL_OPERATORS
。
レクサーは、パーサーが現在どのトークンを必要としているかを気にしないことに注意してください。レクサーはパーサーとは独立して機能します。現在の入力と定義されたレクサールールのみを調べて、作成するトークンの種類を決定します。したがって、同じ文字シーケンスは常に同じ種類のトークンを作成します。
文法を修正するには、字句解析ルールを定義して重複しないようにし、パーサールールで好きなようにグループ化する必要があります。したがって、演算子ごとに1つのレクサールールを作成し(おそらく、パーサールールで文字列リテラルを使用することによって暗黙的に)('==' | '!=' | ...)
、パーサーで単純に使用できます。
また、リレーショナル式には単一のパーサールールを使用することをお勧めします。現在、タイプごとに1つあり、異なるタイプの式の比較を禁止していますが、このアプローチは拡張性がありません(たとえば、変数を導入するときに何をしますか?)。代わりに、パーサーで型が正しくない式を許可してから、個別に作成する型チェッカーでそれらを拒否する必要があります。
PS:レクサーでこれらのタイプの問題を見つけるには、特定の入力に対して生成されたトークンストリームを出力すると便利です。これは、Javaコードでトークンストリームを反復処理するかgrun YourGrammarName tokens -tokens yourInputFile
、コマンドラインで実行することで実現できます。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加