首页 > 解决方案 > ANTLR4:无法匹配 INT 和 BOOLEAN

问题描述

我编写了以下语法来计算 Java 中逻辑运算符和关系运算符的组合。

在语法中,我只能将 Equals opertor( =) 用于STRING类型,而不能用于INTBOOLEAN类型。有人可以帮我找出问题所在吗?

我能够("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';



标签: javaantlrantlr4lexer

解决方案


您有多个词法分析器规则可以匹配输入==!=. ANTLR(以及大多数词法分析器生成器)解决词法分析器规则中的歧义,首先选择产生最长匹配的那些(在这种情况下,所有规则都会产生长度为 2 的匹配),然后通过选择一个来解决关系这在语法中是第一位的。所以当词法分析器看到一个==or!=时,它总是会生成一个类型的标记STRING_RELATIONAL_OPERATORS

请注意,词法分析器并不关心解析器现在需要哪些标记 - 词法分析器的功能独立于解析器。它只查看当前输入和定义的词法分析器规则来决定创建哪种标记。因此,相同的字符序列将始终创建相同类型的标记。

要修复您的语法,您应该定义您的词法分析器规则,以便它们不会重叠,然后在解析器规则中按照您的喜好对它们进行分组。因此,您可以为每个运算符设置一个词法分析器规则(可能通过在解析器规则中使用字符串文字来隐式地使用),然后简单地('==' | '!=' | ...)在解析器中使用。

我还建议只为关系表达式设置一个解析器规则。现在,每种类型都有一个不允许比较不同类型的表达式,但是这种方法无法扩展(例如,当您引入变量时,您将要做什么?)。相反,您应该简单地在解析器中允许错误类型的表达式,然后在您单独编写的类型检查器中拒绝它们。

PS:为了在词法分析器中找到这些类型的问题,打印为给定输入生成的令牌流会有所帮助。您可以通过在 Java 代码中迭代令牌流或grun YourGrammarName tokens -tokens yourInputFile在命令行中运行来实现。


推荐阅读