java - ANTLR4:无法匹配 INT 和 BOOLEAN
问题描述
我编写了以下语法来计算 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 的匹配),然后通过选择一个来解决关系这在语法中是第一位的。所以当词法分析器看到一个==
or!=
时,它总是会生成一个类型的标记STRING_RELATIONAL_OPERATORS
。
请注意,词法分析器并不关心解析器现在需要哪些标记 - 词法分析器的功能独立于解析器。它只查看当前输入和定义的词法分析器规则来决定创建哪种标记。因此,相同的字符序列将始终创建相同类型的标记。
要修复您的语法,您应该定义您的词法分析器规则,以便它们不会重叠,然后在解析器规则中按照您的喜好对它们进行分组。因此,您可以为每个运算符设置一个词法分析器规则(可能通过在解析器规则中使用字符串文字来隐式地使用),然后简单地('==' | '!=' | ...)
在解析器中使用。
我还建议只为关系表达式设置一个解析器规则。现在,每种类型都有一个不允许比较不同类型的表达式,但是这种方法无法扩展(例如,当您引入变量时,您将要做什么?)。相反,您应该简单地在解析器中允许错误类型的表达式,然后在您单独编写的类型检查器中拒绝它们。
PS:为了在词法分析器中找到这些类型的问题,打印为给定输入生成的令牌流会有所帮助。您可以通过在 Java 代码中迭代令牌流或grun YourGrammarName tokens -tokens yourInputFile
在命令行中运行来实现。
推荐阅读
- anylogic - 随机服务点
- c# - 我们应该总是使用 PipeWriter.GetMemory > Advance > Flush 吗?我们什么时候使用 WriteAsync?
- r - 如何读取每行末尾有额外分隔符导致的空白列的 CSV?
- java - Kotlin JNA 将声明的字段名称设为空列表
- android - Android:重新安装我的应用程序后无法访问我的应用程序创建的文件
- node.js - 使用 NGINX 在 VPS 服务器(ubuntu 16.04)上部署 React 前端和 Express 后端
- javascript - 让 Puppeteer 同时转到不同的链接
- gremlin - 如何通过in-edge属性值大于out-edge属性值来查询gremlin顶点
- angular - PrimeNG Message & Toast 在组件中工作但不在服务中
- python - 为什么我的 Hashtag python 脚本转换器不起作用?