使用 nom (>5) 和 `alt` 的状态
State with nom (>5) and `alt`
在尝试了一些 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
来进一步表达。
所以,我想到了
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)
}
}
我尝试用 nom
实现对这种 AST
的解析,所以我愿意接受任何正确方向的建议,即使这意味着我必须走另一条路与解析器。不过这里好像还是有状态参与的。
这种副作用是解析器组合器中的反模式。您可能会针对您的代码风格使用错误的工具。它是拥有 ast
的解析器应该改变它,通过与你的子解析器共享 ast
你专门使用 alt
.
请求错误
Nom linked issue,请注意,如果你真的想像 Geal 所说的那样做,你可以使用 Rc<RefCell<AST>>
。
你也可以手动 alt()
它只是一堆 if
.
在尝试了一些 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
来进一步表达。
所以,我想到了
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)
}
}
我尝试用 nom
实现对这种 AST
的解析,所以我愿意接受任何正确方向的建议,即使这意味着我必须走另一条路与解析器。不过这里好像还是有状态参与的。
这种副作用是解析器组合器中的反模式。您可能会针对您的代码风格使用错误的工具。它是拥有 ast
的解析器应该改变它,通过与你的子解析器共享 ast
你专门使用 alt
.
Nom linked issue,请注意,如果你真的想像 Geal 所说的那样做,你可以使用 Rc<RefCell<AST>>
。
你也可以手动 alt()
它只是一堆 if
.