• javacc之路4---错误恢复


    异常类
    JavaCC 支持两种异常类型:

    异常类型 描述
    TokenMgrError 每当令牌管理器检测到问题时,它都会抛出异常TokenMgrError。
    ParseException 每当解析器检测到问题时,它都会抛出异常ParseException。
    TokenMgrError是 的子类ErrorwhileParseException是 的子类Exception。

    这里的原因是令牌管理器永远不会抛出异常 - 您必须小心定义令牌规范,以便涵盖所有情况。因此后缀Error在TokenMgrError. 你不必担心这个异常 - 如果你设计的令牌很好,它永远不会被抛出。

    相反,通常尝试从Parser错误中恢复。如果您仍想从令牌管理器错误中恢复,您可以这样做——只是您没有被迫捕获它们。

    JavaCC 语法规范包括一种语法,用于指定可能由对应于非终端的方法抛出的其他异常。此语法与 Javathrows …语法相同。

    以下是如何使用它的示例:

    void VariableDeclaration() throws SymbolTableException, IOException :
    {…}
    {

    }
    VariableDeclaration被定义为抛出异常SymbolTableException,IOException除了ParseException.

    错误报告
    错误报告的方案很简单——只需ParseException.java根据您的目的修改文件。通常,您应该修改该getMessage()方法以执行您自己的自定义错误报告。有关这些方法的所有信息都可以从生成的文件ParseException.java和TokenMgrError.java. 它还有助于理解该类的标准 Java 功能Throwable。

    生成的解析器中有一个方法叫做generateParseException(). 您可以随时调用此方法来生成 类型的对象ParseException。该对象将包含自上次成功使用令牌以来解析器尝试过的所有选择。

    错误恢复
    JavaCC 提供了两种错误恢复——浅层恢复和深度恢复。

    如果当前的选择都没有成功被选中,那么浅恢复将恢复,而深度恢复是选择选择的时候,但是在此选择的解析期间某个时候发生错误。

    浅层错误恢复
    考虑以下示例:

    void Stm() :
    {}
    {
    IfStm()
    |
    WhileStm()
    }
    让我们假设IfStmstarts with the reserved wordif并WhileStm以 reserved word 开头while。IfStm假设当norWhileStm都不能与下一个输入标记匹配时(假设是LOOKAHEAD),您希望通过一直跳到下一个分号来恢复1。也就是说,下一个标记既不是if也不是while。

    您可以指定以下内容:

    void Stm() :
    {}
    {
    IfStm()
    |
    WhileStm()
    |
    error_skipto(SEMICOLON)
    }
    但是你必须先定义error_skipto。就 JavaCC 而言,error_skipto就像任何其他非终端一样。

    下面是一种定义方式error_skipto(这里我们使用标准JAVACODE制作):

    JAVACODE
    void error_skipto(int kind) {
    ParseException e = generateParseException(); // generate the exception object
    System.out.println(e.toString()); // print the error message
    Token t;
    // consume tokens all the way up to a token of “kind” - use a do-while loop
    // rather than a while because the current token is the one immediately before
    // the erroneous token (in our case the token immediately before what should
    // have been “if”/“while”.
    do {
    t = getNextToken();
    }
    while (t.kind != kind);
    }
    这就是浅层错误恢复。在 JavaCC 的未来版本中,我们将支持语法的模块化组合。发生这种情况时,可以将所有这些错误恢复例程放入一个单独的模块中,该模块可以导入到主语法模块中。我们打算在实现此功能时提供一个有用例程库(用于错误恢复和其他)。

    深度错误恢复
    使用与浅层恢复相同的示例:

    void Stm() :
    {}
    {
    IfStm()
    |
    WhileStm()
    }
    在这种情况下,我们希望以相同的方式恢复,但是我们希望即使在解析更深层次上存在错误时也能恢复。

    例如,假设下一个记号是while- 因此做出了选择WhileStm。但是假设在解析过程中WhileStm遇到了一些错误——比如说我们while (foo { stm; }已经错过了右括号。浅恢复不适用于这种情况,我们需要深度恢复来实现这一点。为此,我们在 JavaCC 中提供了一个新的语法实体——try-catch-finally块。

    首先,让我们重构上面的深度错误恢复示例,然后try-catch-finally更详细地解释该块:

    void Stm() :
    {}
    {
    try {
    (
    IfStm()
    |
    WhileStm()
    )
    }
    catch (ParseException e) {
    error_skipto(SEMICOLON);
    }
    }
    而已。IfStm如果在or的解析过程中有任何未恢复的错误WhileStm,则 catch 块接管。您可以有任意数量的catch块和可选的finally块(就像 Java 错误一样)。进入catch块的是Java 代码,而不是 JavaCC 扩展。

    例如,上面的例子可以改写为:

    void Stm() :
    {}
    {
    try {
    (
    IfStm()
    |
    WhileStm()
    )
    }
    catch (ParseException e) {
    System.out.println(e.toString());
    Token t;
    do {
    t = getNextToken();
    } while (t.kind != SEMICOLON);
    }
    }
    catch最好避免在和块中放置过多的 Java 代码,finally因为它会使语法读者不知所措 - 最好定义您可以从catch块中获取的方法。

    请注意,在示例的第二个版本中,我们基本上将代码从error_skipto. 但是我们省略了第一条语句——调用generateParseException(). 在这种情况下,该catch块已经为我们提供了异常。即使你确实调用了这个方法,你也会得到一个相同的对象。

  • 相关阅读:
    mysql 开启binlog日志,恢复误删的表、数据、mysql库
    蓝桥等考Python组别十一级008
    基于STM32_DHT11单总线温湿度传感器驱动
    C++对多继承的理解
    django —— 搭建项目及简单测试
    Leetcode 349.两个数组的交集
    CentOs程序环境准备
    阿里分布式开发小册Github新开源 原理实践双飞
    【uniapp】使用扫码插件,解决uni.scanCode扫码效率低的问题
    Cpp创建桌面快捷方式lnk
  • 原文地址:https://blog.csdn.net/u013257767/article/details/128054266