在尝试了一些锈蚀的树结构后,我最终决定建立一棵线性化的树,例如
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")时,解析器需要通过将新表达式推入其中并使用ExprRef对进一步的表达式进行变异来改变AST。
所以,我想到了
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的解析,因此我愿意接受任何正确方向的建议,即使这意味着我必须使用解析器走一条不同的路线。但似乎有些州参与了这件事。
发布于 2022-01-12 18:40:39
这种副作用是解析器组合器中的反模式。您可能对代码样式使用了错误的工具。拥有ast的解析器应该对其进行变异,通过与您的子解析器共享ast,您会特别使用alt来请求bug。
Nom关联问题,请注意,如果您真的想这样做,正如Geal所说的,您可以使用Rc<RefCell<AST>>。
您也可以手动执行alt(),这只是一堆if。
https://stackoverflow.com/questions/70686144
复制相似问题