ANTLR4:无法匹配INT和BOOLEAN

时间:2019-04-13 09:01:56

标签: java antlr antlr4 lexer

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

在语法中,我只能将Equals运算符(=)用于 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';



1 个答案:

答案 0 :(得分:0)

您具有多个与输入==!=匹配的词法分析器规则。 ANTLR(以及大多数词法生成器)通过首先选择产生最长匹配项的规则(在这种情况下,所有规则都将产生长度为2的匹配项)来解决词法规则中的歧义,然后通过选择一个来解决联系在语法上是第一位的。因此,当词法分析器看到==!=时,它将始终生成STRING_RELATIONAL_OPERATORS类型的令牌。

请注意,词法分析器不在乎解析器现在需要哪个令牌-词法分析器独立于解析器运行。它仅查看当前输入和定义的词法分析器规则来确定要创建的令牌类型。因此,相同的字符序列将始终创建相同的令牌。

要修复语法,应定义词法分析器规则,以使它们不重叠,然后根据需要在解析器规则中对它们进行分组。因此,您可以为每个运算符使用一个词法分析器规则(也许通过在解析器规则中使用字符串文字来隐式),然后在解析器中简单地使用('==' | '!=' | ...)

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

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