ANTLR 词法分析器规则似乎只作为解析器规则的一部分工作,而不是另一个词法分析器规则的一部分

ANTLR Lexer rule only seems to work as part of parser rule, and not part of another lexer rule

如果我有以下语法来解析由空格分隔的整数列表:

grammar TEST;

test
    : expression* EOF
    ;

expression
    : integerLiteral
    ;

integerLiteral
    : INTLITERAL
    ;

PLUS: '+';
MINUS: '-';

DIGIT: '0'..'9';
DIGITS: DIGIT+;
INTLITERAL: (PLUS|MINUS)? DIGITS;

WS: [ \t\r\n] -> skip;

不行!如果我通过“100”我得到:

line 1:0 extraneous input '100' expecting {<EOF>, INTLITERAL}

但是,如果像这样删除词法分析器 INTLITERAL 规则并将其放在解析器规则 integerLiteral 之下

integerLiteral
    : (PLUS|MINUS)? DIGITS
    ;

现在看来效果不错!

我觉得如果我能够理解这是为什么,我就会开始理解我正在经历的一些特质。

词法分析器以下列方式创建标记:

  1. 尝试为单个令牌匹配尽可能多的字符
  2. 如果两个标记匹配相同的字符,让定义的第一个"win"

根据上述 2 条规则的信息,您将看到您的规则:

DIGITS: DIGIT+;
INTLITERAL: (PLUS|MINUS)? DIGITS;

是问题所在。对于输入 100 创建了一个 DIGITS 标记:此处适用规则 2:两个规则都匹配 100,但是由于 DIGITSINTLITERAL 之前定义,所以 DIGITS 令牌已创建。

解决方案 1

INTLITERAL 移到 DIGITS 上方:

INTLITERAL: (PLUS|MINUS)? DIGITS;
DIGIT: '0'..'9';
DIGITS: DIGIT+;

但是现在请注意 DIGITDIGITS 永远不会自己成为标记,因为 INTLITERAL 总是先被匹配。在这种情况下,您可以将这两个规则都设为 fragments,然后将它们放在哪里并不重要,因为 fragment 规则仅在其他词法分析器规则中使用(不在解析器规则中)

解决方案 2

制作DIGITDIGITS个片段

fragment DIGIT: '0'..'9';
fragment DIGITS: DIGIT+;
INTLITERAL: (PLUS|MINUS)? DIGITS;

解决方案 3

或者更好的是,不要将运算符粘贴到 INTLITERAL 上,而是将其匹配到一元表达式中:

expression
    : (MINUS | PLUS) expression
    | expression (MINUS | PLUS) expression
    | integerLiteral
    ;

integerLiteral
    : INTLITERAL
    ;

PLUS: '+';
MINUS: '-';

fragment DIGIT: '0'..'9';

INTLITERAL: DIGIT+;