所以我正在使用 ANTLR 在 Java 中编写一个编译器,我对它如何处理错误感到有些困惑。
默认行为似乎是打印一条错误消息,然后尝试通过令牌插入等方式从错误中恢复并继续解析。我原则上喜欢这个;这意味着(在最好的情况下)如果用户提交了多个语法错误,他们将在每个错误中收到一条消息,但它会提及所有错误,而不是强制他们重新编译以发现下一个错误。默认错误消息对我来说很好。当它完成读取所有令牌时,麻烦就来了。
当然,我正在使用 ANTLR 的树构造函数来构建抽象语法树。虽然通过语法错误继续解析很不错,这样用户就可以看到所有错误,但一旦完成解析,我希望得到一个异常或某种指示输入在语法上无效的指示;这样我就可以停止编译并告诉用户“对不起,修复你的语法错误,然后再试一次”。我不希望它根据它认为用户试图说的内容吐出不完整的 AST,并继续进行下一阶段的编译,没有任何迹象表明出现任何问题(除了出现的错误消息)到控制台,我看不到)。然而,默认情况下,它正是这样做的。
Definitive ANTLR Reference提供了一种在检测到语法错误后立即停止解析的技术:覆盖mismatch
andrecoverFromMismatchedSet
方法来 throw RecognitionException
s,并添加一个@rulecatch
动作来做同样的事情。这似乎失去了从解析错误中恢复的好处,但更重要的是,它只是部分起作用。如果缺少必要的标记(例如,如果二元运算符的一侧只有一个表达式),它会按预期抛出异常,但如果添加了无关的标记,ANTLR 会插入它认为属于那里的标记并继续其愉快的方式,产生一个除了控制台消息之外没有任何语法错误指示的 AST。(更糟糕的是,它插入的令牌是EOF
,所以文件的其余部分甚至没有被解析。)
我确信我可以解决这个问题,例如,向isValid
解析器添加类似字段的内容并覆盖方法并添加操作,以便在解析结束时,如果有任何错误,它会引发异常。但是有更好的方法吗?我无法想象我正在尝试做的事情在 ANTLR 用户中是不寻常的。