0

在 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,通过将新表达式推入其中并使用ExprReffor 进一步的表达式。

所以,我想到了类似的东西

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)
   }
}

我尝试用 实现对这种类型的解析ASTnom因此我愿意接受任何正确方向的建议,即使这意味着我必须使用解析器走不同的路线。但似乎无论如何都涉及到某些状态。

4

1 回答 1

2

这种副作用是解析器组合器中的反模式。您可能为您的代码风格使用了错误的工具。它是拥有ast应该改变它的解析器,通过ast与您的子解析器共享您特别使用alt.

与 Nom 相关的问题,请注意,如果您真的想按照 Geal 所说的那样做,您可以使用Rc<RefCell<AST>>

您也可以alt()手动进行,这只是一堆if.

于 2022-01-12T18:40:39.607 回答