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

ANTLR4如何在词法分析器子规则/片段中覆盖文本

ANTLR续行标记处理问题与解决方案

问题描述

我要解析的语法规定第71列是续行指示符,标识符、字面量等几乎所有内容都支持跨行续写。我的需求是移除续行标记相关字符,只保留标识符本身,但使用当前ANTLR语法时,LINE_CONTINUATION规则里的setText("")完全不起作用,导致最终生成的IDENTIFIER token被续行的注释、换行等内容污染。

当前使用的ANTLR代码如下:

IDENTIFIER 
    : 
    {getCharPositionInLine() < 71 }? IDENTIFIER_PART
    (
            {getCharPositionInLine() < 71 }? IDENTIFIER_PART  
        |   LINE_CONTINUATION 
    )*
;
fragment IDENTIFIER_PART: (LETTER|DIGIT|'_');
fragment DIGIT: [0-9];
fragment LETTER options { caseInsensitive=true; } : [A-Z];

// 续行规则:第72列(即第71索引位)非空白,后续内容直到行尾,下一行从第16列开始的内容
LINE_CONTINUATION
    : 
    {getCharPositionInLine() == 71 }? 
    ~[ ] 
    ~[\r\n]* EOL
    ({getCharPositionInLine() <= 15 }? [ ] )+  
    {setText("");}
; 

我还想确认:是否可以像修改根规则文本那样,覆盖子规则(或片段)的文本值?

示例对比

输入文本

AAAAAAAAAAAA,BBBBBBBBBBB,CCCCCCCCCCCCCCCCC,DDDDDDDDDDD,EEEEEEEEEE,FFFF* Some comment
FFFF,GGGGGGGG

期望的Token文本

AAAAAAAAAAAA
BBBBBBBBBBB
CCCCCCCCCCCCCCCCC
DDDDDDDDDDD
EEEEEEEEEE
FFFFFFFF
GGGGGGGG

实际得到的Token文本

AAAAAAAAAAAA
BBBBBBBBBBB
CCCCCCCCCCCCCCCCC
DDDDDDDDDDD
EEEEEEEEEE
FFFF* Some comment\nFFFF
GGGGGGGG

原因分析与解决方案

问题根源

ANTLR中,子规则的setText()仅会修改自身Token的文本,但当子规则被嵌套在父规则中时,父规则的最终文本是直接拼接所有匹配到的字符序列,不会继承子规则的文本修改。因此LINE_CONTINUATION里的setText("")对IDENTIFIER的最终文本完全没有影响。

可行方案

方案1:直接在IDENTIFIER规则中忽略续行标记字符

把续行的匹配逻辑直接嵌入IDENTIFIER规则,匹配到续行标记时不将其加入Token文本:

IDENTIFIER 
    : 
    {getCharPositionInLine() < 71 }? IDENTIFIER_PART
    (
            {getCharPositionInLine() < 71 }? IDENTIFIER_PART  
        |   {getCharPositionInLine() == 71}? ~[ ] ~[\r\n]* EOL ({getCharPositionInLine() <= 15}? [ ] )+ 
    )*
;
fragment IDENTIFIER_PART: (LETTER|DIGIT|'_');
fragment DIGIT: [0-9];
fragment LETTER options { caseInsensitive=true; } : [A-Z];

方案2:保留LINE_CONTINUATION规则,手动清理IDENTIFIER文本

如果想保留LINE_CONTINUATION的独立定义,可以在匹配到它时,手动从IDENTIFIER的文本中移除续行部分:

IDENTIFIER 
    : 
    {getCharPositionInLine() < 71 }? IDENTIFIER_PART
    (
            {getCharPositionInLine() < 71 }? IDENTIFIER_PART  
        |   lc=LINE_CONTINUATION { setText(getText().replace(lc.getText(), "")); }
    )*
;
fragment IDENTIFIER_PART: (LETTER|DIGIT|'_');
fragment DIGIT: [0-9];
fragment LETTER options { caseInsensitive=true; } : [A-Z];

LINE_CONTINUATION
    : 
    {getCharPositionInLine() == 71 }? 
    ~[ ] 
    ~[\r\n]* EOL
    ({getCharPositionInLine() <= 15 }? [ ] )+  
; 

两种方案都能实现需求,最终生成的IDENTIFIER Token文本会自动移除续行标记内容,只保留原始标识符字符。

内容的提问来源于stack exchange,提问作者Alistair McLennan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 05:33:13