求一个parser grammar,用boost spirit qi比较好
ask for a parser grammar, using boost spirit qi is better
我正在尝试使用 boost::spirit::qi
来解析表达式。
表达式简单,可以
- id,喜欢
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]()
boost::spirit::qi
is a descending parser;你的语法 一定不能 保留递归。
见this question。
这里肯定有left-recursive语法: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 % ",")
EDIT 2 如果你想强制优先——例如带括号:
expression = prefix_expr >> *cont_expr;
prefix_expr = id | par_expr
par_expr = "(" >> expression >> ")"
这样你甚至可以写出像 x.(y[3].foo)[5](fun(), foo(bar))
这样的表达式——如果这有意义的话。
编辑 3 我在这里回答你的评论。
您需要赋值的左侧不是函数。这意味着您有 left-hand 表达式的特定后缀。让我们在您的评论中称该规则为 ref_exp
。
ref_exp = id >> -( *cont_expr >> cont_ref );
cont_ref = elem_expr | member_expr;
最后我想我解决了这个问题,但是这个解决方案有一个side-effects,它会改变运算符的结合性。
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
我正在尝试使用 boost::spirit::qi
来解析表达式。
表达式简单,可以
- id,喜欢
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]()
boost::spirit::qi
is a descending parser;你的语法 一定不能 保留递归。
见this question。
这里肯定有left-recursive语法: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 % ",")
EDIT 2 如果你想强制优先——例如带括号:
expression = prefix_expr >> *cont_expr;
prefix_expr = id | par_expr
par_expr = "(" >> expression >> ")"
这样你甚至可以写出像 x.(y[3].foo)[5](fun(), foo(bar))
这样的表达式——如果这有意义的话。
编辑 3 我在这里回答你的评论。
您需要赋值的左侧不是函数。这意味着您有 left-hand 表达式的特定后缀。让我们在您的评论中称该规则为 ref_exp
。
ref_exp = id >> -( *cont_expr >> cont_ref );
cont_ref = elem_expr | member_expr;
最后我想我解决了这个问题,但是这个解决方案有一个side-effects,它会改变运算符的结合性。
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