如何修改Lexer规则避免连续相同Token?实现指定词法识别效果
问题说明
现有Lexer语法如下:
lexer grammar TestLexer; Number : '-'? [0-9]+ ; Punctuation : [\-.] ; Identifier : '.'? [a-zA-Z]+ ; Whitespace : [ \t]+ -> skip ; Newline : ( '\r' '\n'? | '\n' ) -> skip ;
输入内容:
1-2 1 -2 .foo foo.bar
当前生成的Token结果:
[@0,0:0='1',<Number>,1:0] [@1,1:2='-2',<Number>,1:1] [@2,5:5='1',<Number>,2:0] [@3,7:8='-2',<Number>,2:2] [@4,13:16='.foo',<Identifier>,4:0] [@5,19:21='foo',<Identifier>,5:0] [@6,22:25='.bar',<Identifier>,5:3] [@7,28:27='<EOF>',<EOF>,6:0]
需要调整规则,实现:
1-2被识别为 Number、Punctuation、Numberfoo.bar被识别为 Identifier、Punctuation、Identifier
修改方案
ANTLR Lexer的匹配逻辑是「最长优先」+「规则定义顺序优先」。原规则的问题在于:
Number规则包含可选前置-,导致-2会被匹配成单个NumberIdentifier规则包含可选前置.,导致.bar会被匹配成单个Identifier
调整思路:
- 优先定义
Punctuation规则,让单独的-和.先被识别 - 移除
Number和Identifier规则中的可选前置符号,只匹配纯数字或纯字母序列
修改后的Lexer语法:
lexer grammar TestLexer; // 优先匹配单独的标点符号 Punctuation : '-' | '.' ; // 仅匹配纯数字序列 Number : [0-9]+ ; // 仅匹配纯字母序列 Identifier : [a-zA-Z]+ ; Whitespace : [ \t]+ -> skip ; Newline : ( '\r' '\n'? | '\n' ) -> skip ;
验证效果
修改后对应的Token结果会变为:
1-2→1(Number)、-(Punctuation)、2(Number)1 -2→1(Number)、-(Punctuation)、2(Number).foo→.(Punctuation)、foo(Identifier)foo.bar→foo(Identifier)、.(Punctuation)、bar(Identifier)
完全符合需求。
内容的提问来源于stack exchange,提问作者Thomas S.
相关产品推荐
相关产品推荐

