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
;
现在看来效果不错!
我觉得如果我能够理解这是为什么,我就会开始理解我正在经历的一些特质。
词法分析器以下列方式创建标记:
- 尝试为单个令牌匹配尽可能多的字符
- 如果两个标记匹配相同的字符,让定义的第一个"win"
根据上述 2 条规则的信息,您将看到您的规则:
DIGITS: DIGIT+;
INTLITERAL: (PLUS|MINUS)? DIGITS;
是问题所在。对于输入 100
创建了一个 DIGITS
标记:此处适用规则 2:两个规则都匹配 100
,但是由于 DIGITS
在 INTLITERAL
之前定义,所以 DIGITS
令牌已创建。
解决方案 1
将 INTLITERAL
移到 DIGITS
上方:
INTLITERAL: (PLUS|MINUS)? DIGITS;
DIGIT: '0'..'9';
DIGITS: DIGIT+;
但是现在请注意 DIGIT
和 DIGITS
永远不会自己成为标记,因为 INTLITERAL
总是先被匹配。在这种情况下,您可以将这两个规则都设为 fragment
s,然后将它们放在哪里并不重要,因为 fragment
规则仅在其他词法分析器规则中使用(不在解析器规则中)
解决方案 2
制作DIGIT
和DIGITS
个片段
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+;
如果我有以下语法来解析由空格分隔的整数列表:
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
;
现在看来效果不错!
我觉得如果我能够理解这是为什么,我就会开始理解我正在经历的一些特质。
词法分析器以下列方式创建标记:
- 尝试为单个令牌匹配尽可能多的字符
- 如果两个标记匹配相同的字符,让定义的第一个"win"
根据上述 2 条规则的信息,您将看到您的规则:
DIGITS: DIGIT+;
INTLITERAL: (PLUS|MINUS)? DIGITS;
是问题所在。对于输入 100
创建了一个 DIGITS
标记:此处适用规则 2:两个规则都匹配 100
,但是由于 DIGITS
在 INTLITERAL
之前定义,所以 DIGITS
令牌已创建。
解决方案 1
将 INTLITERAL
移到 DIGITS
上方:
INTLITERAL: (PLUS|MINUS)? DIGITS;
DIGIT: '0'..'9';
DIGITS: DIGIT+;
但是现在请注意 DIGIT
和 DIGITS
永远不会自己成为标记,因为 INTLITERAL
总是先被匹配。在这种情况下,您可以将这两个规则都设为 fragment
s,然后将它们放在哪里并不重要,因为 fragment
规则仅在其他词法分析器规则中使用(不在解析器规则中)
解决方案 2
制作DIGIT
和DIGITS
个片段
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+;