野牛C++缺少分号的多个错误恢复

Bison C++ multiple error recovery with missing semi colon

本文关键字:错误 恢复 C++ 野牛      更新时间:2023-10-16

我正在开发自己的编译器,我在错误恢复设计方面遇到了问题在 Java 语法的恐慌模式下。

我想过多种解决方案,但真正的问题是:

我如何使用野牛 c++ 做到这一点?

我做到了:

套餐 2

导入 java.lang.*;

错误必须消耗到第一个分号,并且这使用规则正确运行

package_rule:包错误";"

但是如果我写了这段代码:

套餐 2

导入 java.lang.*

类 y { void method() { int m }

}

我需要像标准编译器一样从解析器中报告错误:

标识符应位于包装行。 缺少";"在导入说明行中报告包的";"。 在 int m 行上键入";"。

我的意思是我需要在包错误后使用令牌,直到第一个分号或在最后一行找到类或接口声明时停止,然后再声明它们! 并报告在行后发现的任何其他错误:

int m//缺少 ';'

请帮助我,在我看来有多种解决方案,但是如何使用 Bison C++ for Java 语法做到这一点?

你不会介意用C++ OOP的方式解决这个问题,而不是用野牛的方式,对吧?

假设您定义了这些类型的 AST 节点

struct BaseExpression {
    virtual std::string toIdentifier() = 0;
    // other member. remember to declare a virtual destructor
};
struct IntLiteral : BaseExpression {
    std::string toIdentifier() {
        error::toAnIdentifier();
        return "";
    }
};
struct Identifier: BaseExpression {
    std::string ident;
    explicit Identifier(std::string id) : ident(id) {}
    std::string toIdentifer() {
        return ident;
    }
};

定义这样的规则

%union {
    BaseExpression* expr_type;
}
%type <expr_type> simple_expr
package_expr: simple_expr
{
    $1->toIdentifer(); // thus integers or float numbers would generate errors
    // do sth with that identifer
}
;
package_expr: package_rule '.' simple_expr
{
    $3->toIdentifer(); // same trick
    // do sth with that identifer
}
;

simple_expr在哪里

simple_expr: int_literal { return new IntLiteral; }
           | ...
           | identifier { return new Identifier(yytext); }
;

好吧,您的基本问题是您希望它如何尝试从语法错误中恢复。 当你有一个输入序列,如

package x import
你希望它假设那里应该有一个分号,

还是希望它假设在分号之前有其他东西卡住了,它应该扔掉东西,直到它到达分号?

后者就是你所拥有的 - 规则package: PACKAGE error ';'正是这样做的 - 每当它看到关键字PACKAGE但它后面的内容与package规则的其余部分不匹配时,它应该丢弃输入,直到它看到一个';'并尝试从那里继续。

如果你想要前者,你可以使用像package: PACKAGE name error这样的规则——如果它看到PACKAGE看起来像一个有效的包名称但没有分号的东西,把它当作那里有一个分号,然后尝试继续。

让它能够同时完成上述两件事是非常困难的。 最接近的是让语法看起来像这样:

package: PACKAGE name ';'  /* normal package decl */
       | PACKAGE name      /* missing semicolon -- treat this as a semantic error */
       | PACKAGE error ';' /* no name -- skip up to the next semicolon to recover */

但是,这种事情可能会给您带来难以解决的语法冲突。