ANTLR4中用TokenStreamRewriter修改多通道(含HIDDEN注释)的最优方案
VB6代码改写:高效处理ANTLR4隐藏通道注释的方案
需求背景
我用ANTLR4生成了VB6解析器,通过自定义Listener改写VB6代码,当前效果尚可。注释被归类到HIDDEN通道,现在需要:
- 修改部分注释内容(例:给每个注释末尾添加"X")
- 确保注释仍保留在HIDDEN通道,不进入默认输出通道
之前尝试用EnterEveryRule实现,但遍历所有规则的方式过于繁琐,想找更优的方案。
当前核心代码
string input = "some input"; var stream = new AntlrInputStream(input); var lexer = new VisualBasic6Lexer(stream); var tokens = new CommonTokenStream(lexer); var parser = new VisualBasic6Parser(tokens); parser.Interpreter.PredictionMode = PredictionMode.LL_EXACT_AMBIG_DETECTION; var tree = parser.startRule(); var rwr = new TokenStreamRewriter(tokens); var lstnr = new MyListener(lexer, parser, rwr); ParseTreeWalker.Default.Walk(lstnr, tree); var output = rwr.GetText();
原Listener修改方式(示例)
public override void EnterModuleConfig([NotNull] VisualBasic6Parser.ModuleConfigContext context) { base.EnterModuleConfig(context); Rewriter.InsertBefore(context.Start, "'"); Rewriter.InsertBefore(context.Stop.TokenIndex - 1, "'"); }
原EnterEveryRule实现方案
public override void EnterEveryRule([NotNull] ParserRuleContext context) { base.EnterEveryRule(context); var tokIx = context.Start.TokenIndex - 1; var tokBefore = Rewriter.TokenStream.Get(tokIx); if (tokBefore.Type == VisualBasic6Lexer.COMMENT) { Rewriter.Replace(tokIx, tokBefore.Text + "X"); } }
最优实现方案
直接遍历令牌流,精准处理HIDDEN通道的注释令牌,无需依赖Listener的规则遍历,效率更高且能覆盖所有注释场景:
实现代码
在创建TokenStreamRewriter后,添加以下遍历逻辑:
// 遍历所有令牌,处理HIDDEN通道的注释 for (int i = 0; i < tokens.Size; i++) { var token = tokens.Get(i); // 筛选HIDDEN通道中的COMMENT令牌 if (token.Channel == Lexer.HIDDEN && token.Type == VisualBasic6Lexer.COMMENT) { // 修改注释文本,添加"X" rwr.Replace(i, token.Text + "X"); } }
方案优势
- 高效直接:跳过解析规则的遍历,直接操作令牌流,减少不必要的规则回调开销
- 覆盖全面:能处理所有位置的注释(包括文件首尾、规则之间的独立注释),不会像
EnterEveryRule那样仅能处理规则前的注释 - 逻辑清晰:直接针对HIDDEN通道的注释令牌处理,需求匹配度更高,代码更易维护
内容的提问来源于stack exchange,提问作者Timur Kelman
相关产品推荐
相关产品推荐

