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

JavaCC词法与语法错误恢复语法编写及error_skipto()使用问题

JavaCC错误恢复:连续语法错误捕获不全与TokenMgrError处理问题

我来帮你拆解这两个JavaCC错误恢复里的常见问题:

一、连续语法错误仅捕获第一条的原因与修复

你遇到的连续错误只触发一次捕获的情况,核心问题出在error_skipto的实现和错误恢复后的解析流程上。

当第一个错误被捕获并执行error_skipto(LINE_END, e)时,你的代码会一直跳过token直到找到LINE_END,但这里有个关键细节:跳过到LINE_END后,当前的token指针已经指向了下一个语句的起始(比如下一个syout),但你的imprimir()方法在执行完catch块后就直接结束了,没有回到语法规则的开头去尝试解析下一个语句。

另外,你的error_skipto实现还有个小问题:如果在跳过过程中遇到文件结束(EOF),会进入死循环,最好加上EOF的判断。

修改后的imprimir()规则和error_skipto可以这样写:

void imprimir(): {} {
    (
        try{
            <DATA_OUT><OPEN_PAREN>(<NUM_INT>| <NUM_FLOAT>|<CHAR>|<STRING>|<IDENTIFIER>) <CLOSE_PAREN><LINE_END>
        }catch(ParseException e){
            error_skipto(LINE_END, e);
        }
    )*  // 用循环处理多个syout语句,错误恢复后继续尝试解析下一个
}

JAVACODE
void error_skipto(int kind, ParseException ex){
    System.out.println("语法错误:" + ex.toString());
    Token t;
    do {
        t = getNextToken();
        if (t.kind == EOF) {  // 防止遇到文件结束死循环
            System.out.println("提前遇到文件结束,终止错误恢复");
            return;
        }
    } while (t.kind != kind);
}

这样修改后,每次错误恢复到LINE_END后,循环会让解析器回到imprimir()的开头,尝试解析下一个syout语句,就能捕获所有连续的错误了。

二、TokenMgrError无法在语法规则内捕获的原因

JavaCC里的TokenMgrError是词法分析器抛出的错误,它的抛出时机比语法分析的try-catch更早:词法分析器在生成token的时候就会抛出这个错误,此时还没进入到你写的语法规则(imprimir())的try-catch块中。

要在语法层面处理词法错误,你需要修改词法分析器的错误处理逻辑,而不是在语法规则里加catch。具体做法是:

  1. 在JavaCC的语法文件开头,添加TOKEN_MGR_DECLS块,重写词法分析器的错误处理方法:
TOKEN_MGR_DECLS:
{
    @Override
    public void LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorMsg, String curLex) {
        // 自定义词法错误处理,比如打印错误信息,然后跳过错误的token
        System.out.println("词法错误:行" + errorLine + ",列" + errorColumn + ":" + errorMsg);
        // 这里可以实现跳过当前错误token的逻辑,比如继续读取直到合法token或换行
        try {
            while (true) {
                int ch = input_stream.read();
                if (ch == '\n' || ch == -1) {  // 跳过到行尾或文件结束
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  1. 关闭JavaCC默认的词法错误抛出:在语法文件开头加上OPTIONS设置:
OPTIONS {
    ERROR_REPORTING = false;  // 关闭默认错误报告,用自定义的LexicalError处理
}

这样,词法错误就会被你自定义的LexicalError方法处理,而不会抛到主函数的try-catch里了。

额外提示:错误恢复的最佳实践

  • 尽量在语法规则的循环结构中处理错误恢复,确保错误后能回到正确的解析上下文
  • 处理错误时一定要考虑EOF的情况,避免死循环
  • 词法和语法错误的处理是分开的,词法错误要在词法分析器层面重写方法处理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:43:02