【问题标题】:ANTLR4: Unable to match INT and BOOLEANANTLR4:无法匹配 INT 和 BOOLEAN
【发布时间】:2019-04-13 09:01:56
【问题描述】:

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

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



【问题讨论】:

    标签: java antlr antlr4 lexer


    【解决方案1】:

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

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

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

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

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

    【讨论】:

    • 感谢您的回答 :) 就我而言,我不知道变量的数据类型,因此找不到合适的运算符。是否没有办法对不同的数据类型重复使用相同的运算符?
    • @KrishnaM 只需一条规则operand relationalOperator operand,其中relationalOperator 匹配所有关系运算符,operand 匹配所有可能的操作数,无论其类型如何。然后让类型检查器来处理剩下的事情。
    • 如果我们引入类型检查器,那么我们需要维护一个变量类型的映射对吗?在我的例子中,左边的操作数将是变量。
    • @KrishnaM 一旦你将变量引入你的语言,你的类型检查器需要一个变量名到类型的映射,是的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-18
    • 1970-01-01
    • 1970-01-01
    • 2021-05-31
    相关资源
    最近更新 更多