You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改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、Number
  • foo.bar被识别为 Identifier、Punctuation、Identifier
修改方案

ANTLR Lexer的匹配逻辑是「最长优先」+「规则定义顺序优先」。原规则的问题在于:

  • Number规则包含可选前置-,导致-2会被匹配成单个Number
  • Identifier规则包含可选前置.,导致.bar会被匹配成单个Identifier

调整思路:

  1. 优先定义Punctuation规则,让单独的-和.先被识别
  2. 移除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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 17:55:19