我正在尝试使用boost::spirit::qi
来解析表达式。
表达式很简单,可以是
x
obj.x
arr[2]
func(x, y)
对象的成员可以是数组或函数类型
x.y[2]
,x.y()
是合法的。
函数结果可能是数组或对象
所以func(x,y).value
,func(x)[4]
也是合法的。
数组元素可能是对象或函数类型
因此arr[5].y
,arr[3](x, y)
是合法的。
结合在一起,以下表达式应该是合法的:
x[1]().y(x, y, x.z, z[4].y)().q[2][3].fun()[5].x.y.z
所有这些[...]
(...)
和.
具有相同的优先顺序,从左到右。
我的语法就像这样
expression
= postfix_expr
| member_expr
;
postfix_expr = elem_expr | call_expr | id;
elem_expr = postfix_expr >> "[" >> qi::int_ >> "]";
call_expr = postfix_expr >> "(" >> expression_list >> ")";
member_expr = id >> *("." >> member_expr);
expression_list
= -(expression % ",")
但它总是崩溃,我想也许某个地方有无限循环。
请给我一些关于如何解析这个语法的建议。
修改 关注问题: 谢谢干部,它有效!
现在表达式可以正确解析,但我想引入一个新的ref_exp
这也是一个表达式,但不以()
结尾,因为函数结果不能放在赋值的左边。
我的定义是:
ref_exp
= id
| (id >> *postfix_exp >> (memb_exp | elem_exp))
;
postfix_exp
= memb_exp
| elem_exp
| call_exp
;
memb_exp = "." >> id;
elem_exp = "[" >> qi::uint_ >> "]";
call_exp = ("(" >> expression_list >> ")");
但boost::spirit::qi
无法解析此问题,
我认为原因是(memb_exp | elem_exp)
是postfix_exp
的一部分,如何使其不解析所有内容,并留下最后一部分以匹配(memb_exp | elem_exp)
ref_exp
示例:x
,x.y
,x()[12][21]
,f(x, y, z).x[2]
不是ref_exp
:f()
,x.y()
,x[12]()
答案 0 :(得分:3)
boost::spirit::qi
is a descending parser;你的语法一定不能保持递归。
请参阅this question。
这里你肯定有一个左递归语法:postfix_expr -> elem_expr -> postfix_expr
编辑解决此问题的一种方法。
在我看来,你的表达式是一串带有可能后缀的ID:[]
,()
,.
。
expression = id >> *cont_expr;
cont_expr = elem_expr | call_expr | member_expr
elem_expr = "[" >> qi::int_ >> "]";
call_expr = "(" >> expression_list >> ")";
member_expr = "." >> expression;
expression_list = -(expression % ",")
编辑2 如果您希望能够强制优先 - 例如使用括号:
expression = prefix_expr >> *cont_expr;
prefix_expr = id | par_expr
par_expr = "(" >> expression >> ")"
这样你甚至可以编写像x.(y[3].foo)[5](fun(), foo(bar))
这样的表达式 - 如果这是有道理的。
编辑3 我在这里回答您的评论。
您需要分配的左侧不是功能。这意味着你有一个特定的左手表达式后缀。我们在您的评论中调用该规则ref_exp
。
ref_exp = id >> -( *cont_expr >> cont_ref );
cont_ref = elem_expr | member_expr;
答案 1 :(得分:2)
最后我认为我解决了这个问题,但这个解决方案有副作用,它会改变运营商的关联性。
lvalue_exp
= id >> -(ref_exp);
;
ref_exp
= (postfix_exp >> ref_exp)
| memb_exp
| elem_exp
;
postfix_exp
= call_exp
| memb_exp
| elem_exp
;
memb_exp
= ("." >> id)
;
elem_exp
= ("[" >> qi::uint_ >> "]")
;
call_exp
= ("(" >> expression_list >> ")")
;
因此表达式f().y()[0]
将解析为:
f
和ref_exp
- ().y()[0]
().y()[0]
已解析为().y()
和[0]
().y()
已解析为()
和.y()
.y()
已解析为.y
和()
如果我不区分左值
f().y()[0]
将解析为:
f
和().y()[0]
()
和.y()[0]
.y
和()[0]
()
和[0]
所以我将使用第二个并在生成ast时检查参考。
谢谢@cadrian