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

ANTLR创建必填Token问题:Hello World语法报错排查

解决ANTLR Go解析器错误提示不准确的问题

我明白你现在的困扰啦——当输入只有Hello时,ANTLR给出的错误提示有点让人摸不着头脑,明明应该提示缺少world,结果却说是期待另一个Hello。别担心,咱们一步步来搞定这个问题~

问题根源

你的语法规则start : HELLO WORLD EOF本身是正确的,但ANTLR的默认错误提示逻辑有时候会因为解析器的预测回溯机制,给出不够精准的提示。当输入只到HELLO就结束时,解析器在尝试匹配规则的过程中,误判了预期的Token类型。

解决方案:自定义错误监听器

ANTLR允许我们通过自定义错误监听器来捕获并改写错误提示,这样就能输出更符合用户预期的友好信息。下面是修改后的完整代码:

修改后的main.go

package main

import (
    "fmt"
    "test/parser"
    "github.com/antlr/antlr4/runtime/Go/antlr"
)

const rule = `Hello`

type testListener struct { *parser.BasehelloworldListener }

// 自定义错误监听器,用于改写错误提示
type customErrorListener struct {
    *antlr.DefaultErrorListener
}

// 重写SyntaxError方法,实现自定义错误提示逻辑
func (c *customErrorListener) SyntaxError(recognizer antlr.Recognizer, offendingSymbol interface{}, line, column int, msg string, e antlr.RecognitionException) {
    // 尝试将识别器转为我们的解析器类型,以便获取预期Token信息
    if parserInst, ok := recognizer.(*parser.HelloworldParser); ok {
        expectedTokens := parserInst.GetExpectedTokens()
        // 检查是否期望WORLD这个Token
        if expectedTokens.Contains(parserInst.WORLD) {
            fmt.Printf("line %d:%d 错误:hello后需输入world\n", line, column)
            return
        }
    }
    // 其他错误情况,输出默认提示
    fmt.Printf("line %d:%d %s\n", line, column, msg)
}

func main() {
    // 初始化输入流
    is := antlr.NewInputStream(rule)
    // 创建词法分析器
    lexer := parser.NewhelloworldLexer(is)
    
    // 打印所有Token(可选,用于调试)
    for {
        t := lexer.NextToken()
        if t.GetTokenType() == antlr.TokenEOF {
            break
        }
        fmt.Printf("%s (%q)\n", lexer.SymbolicNames[t.GetTokenType()], t.GetText())
    }
    
    // 创建Token流
    stream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel)
    // 创建语法分析器
    p := parser.NewhelloworldParser(stream)
    
    // 移除默认错误监听器,添加我们自定义的
    p.RemoveErrorListeners()
    p.AddErrorListener(&customErrorListener{})
    
    // 开始解析并遍历语法树
    antlr.ParseTreeWalkerDefault.Walk(&testListener{}, p.Start())
}

代码说明

  • 自定义错误监听器:我们创建了customErrorListener结构体,继承自ANTLR的默认错误监听器,并重写了SyntaxError方法。
  • 错误判断逻辑:在方法中,我们检查解析器当前预期的Token是否包含WORLD,如果是的话,就输出自定义的友好提示;其他错误则保留默认提示。
  • 替换错误监听器:在main函数中,我们移除了默认的错误监听器,替换成自己实现的,这样错误提示就会按照我们的逻辑输出。

测试效果

现在重新执行构建和运行命令:

antlr -Dlanguage=Go -o parser helloworld.g4 && go run main.go

输出结果会变成:

HELLO ("Hello")
line 1:5 错误:hello后需输入world

完美!现在的错误提示就完全符合你的预期了~这种自定义错误处理的方式还能扩展到更复杂的语法场景中,根据不同的错误场景输出更精准的提示,提升用户体验。

内容的提问来源于stack exchange,提问作者Dennis van der Veeke

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 17:37:26