我正在开发自己的编译器,我遇到了错误恢复设计的问题 在Java语法的恐慌模式下。
我考虑过多种解决方案,但真正的问题是:
我怎么能用bison c ++做到这一点?
我做到了:
包2
import java.lang。*;
错误必须消耗到第一个半冒号,并且使用规则
正确运行package_rule:PACKAGE错误';'
但如果我写了这段代码:
包2
import java.lang。*
class y {void method(){int m}
}
我需要像标准编译器一样从解析器中报告错误:
预期在包裹行的标识符。 失踪 ';'在导入指令行报告一个包。 mssing';'在int m line。
我的意思是我需要在包错误之后使用令牌直到第一个分号或者在声明它们之前在最后一行找到类或接口声明时停止!并报告在行之后发现的任何其他错误:
请帮助我,在我看来有多种解决方案,但是如何用bison c ++进行java语法?int m // missing';'
答案 0 :(得分:1)
好吧,你的基本问题是你希望它如何尝试从语法错误中恢复。当你有一个像
这样的输入序列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 */
然而,这种事情可能会给你很难解决的语法冲突。
答案 1 :(得分:0)
您不介意用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); }
;