在 Rust 中尝试了一些树结构之后,我最终决定构建一个线性化树,例如
struct AST {
exprs: Vec<Expr>,
}
enum Expr {
LiteralInt(i32),
OpAdd(ExprRef, ExprRef),
}
struct ExprRef(usize);
impl AST {
// ...
fn add_expr(&mut self, expr: Expr) -> ExprRef {
self.exprs.push(expr);
ExprRef(self.exprs.len() - 1)
}
}
因此,在解析表达式(例如"+ + 3 4 1"
)时,解析器需要改变AST
,通过将新表达式推入其中并使用ExprRef
for 进一步的表达式。
所以,我想到了类似的东西
fn literal_int(ast: &mut AST) -> impl FnMut(&str) -> IResult<&str, ExprRef> {
move |input: &str| {
// ...
let expr_ref = ast.add_expr(/* ... */);
// ...
Ok((input, expr_ref))
}
}
这有效,只要我不使用分支组合器,因为,你可能已经猜到了,需要多个可变借用ast
!例如
fn factor(ast: &mut AST) -> impl FnMut(&str) -> IResult<&str, ExprRef> {
move |input: &str| {
alt((
literal_int(ast),
parens(ast, term) // cannot borrow `ast` as mutable again
))(input)
}
}
我尝试用 实现对这种类型的解析AST
,nom
因此我愿意接受任何正确方向的建议,即使这意味着我必须使用解析器走不同的路线。但似乎无论如何都涉及到某些状态。