我目前卡住了一个规则,我试图使用boost spirit x3解析。以下是我试图解析的EBNF(使用来自spirit的%操作符):
type ::= class_type | lambda_type
lambda_type ::= more_arg_lambda | one_arg_lambda
more_arg_lambda ::= "(", type%",", ")", "=>", type
one_arg_lambda ::= type, "=>", type <- here is the left recursion
class_type ::= identifier%"::", ["<", type%",", ">"]
使用boost spirit x3,我试图解析为以下结构体/变体:
typedef x3::variant<
nil,
x3::forward_ast<LambdaType>,
x3::forward_ast<ClassType>
> Type;
struct LambdaType {
std::vector<Type> parameters_;
Type return_type_;
};
struct ClassType{
std::vector<std::string> name_;
std::vector<Type> template_args_;
};
我有一个我目前在这里尝试的实例,这是不工作的,我还试图改变变量解析器的顺序,这没有帮助,我得到无尽的递归,或者不是我期望(或希望)的行为。
谁能帮我调试这个解析器?
我认为我在解析器中有某种类型的左递归,是否有机会避免这种情况或没有机会重写语法?这个语法甚至可以用boost spirit x3解析吗?
编辑:我设法消除了这个语法中的左递归。现在语法如下:type ::= class_type | lambda_type
lambda_type ::= more_arg_lambda | one_arg_lambda
more_arg_lambda ::= "(", type%",", ")", "=>", type
one_arg_lambda ::= class_type, "=>" type, A
| "(", type%",", ")", "=>", type, "=>", type, A
class_type ::= identifier%"::", ["<", type%",", ">"]
A::= "=>", type, A | eps
但现在有下一个问题,我如何使boost spirit x3解析这些规则到给定的结构?我无法想象A
或one_arg_lambda
解析器现在返回的是什么,one_arg_lambda
解析器应该解析成LambdaType
结构,但取决于A
解析成什么,现在不一定是真的。所以现在的问题是,如何获得一个非左递归解析器,它使用boost-spirit-x3将上面的语法解析为我的结构?
编辑II:
我希望=>
是右结合的所以foo => bar => baz => baham
表示foo => (bar => (baz => bahama))
我解决了这个问题,而且这个解决方案非常简单。诀窍是改变语法,这样我就没有左递归了,它可以很好地解析到我的结构体中。
所以我改变了
type ::= class_type | lambda_type
lambda_type ::= more_arg_lambda | one_arg_lambda
more_arg_lambda ::= "(", type%",", ")", "=>", type
one_arg_lambda ::= type, "=>", type <- here is the left recursion
class_type ::= identifier%"::", ["<", type%",", ">"]
type ::= class_type | lambda_type
lambda_type ::= more_arg_lambda | one_arg_lambda
more_arg_lambda ::= "(", type%",", ")", "=>", type
one_arg_lambda ::= class_type, "=>", type <- here is the magic trick
class_type ::= identifier%"::", ["<", type%",", ">"]
第二个语法描述了完全相同的语言,但没有左递归,也没有改变语法的结构。这其实是一种运气,显然并不是对所有语法都适用。