写点什么

语法分析 之表达式三

作者:Miracle
  • 2025-09-23
    四川
  • 本文字数:2117 字

    阅读完需:约 7 分钟

语法分析 之表达式三

后缀是最难处理的。你们如果是对刚才那一段复杂的递归都能看明白的话,那么加减乘除包括那个 2 元操作符。单元操作服,1 元操作服。以及算术的优先级算符,那就是绝对的小儿科了。我们把刚才的 base_expr 那个算子,把它命名为原子算子,然后我们把它复制给原子,然后再在后面一个个的把按照优先级。1 元操作符,2 元操作符。加上去


let atom = base_expr.then(suffix.repeated().collect::<Vec<Suffix>>()).map_with(|(base, suffixes): (Expr, Vec<Suffix>), _span| {            suffixes.into_iter().fold(base, |acc, s| match s {                ...
let unary_op = choice((just('-').to(UnaryOp::Neg), just('!').to(UnaryOp::Not))).or(atom).labelled("unary operator");let unary = unary_op.padded().then(atom.clone()).map(|(op, value)| Expr::Unary { op, value: Box::new(value) }) .labelled("unary expression");unary
复制代码


现在返回的就是支持 unary 的解析器了简单吧 让我接着加上 算术运算逻辑运算 以及 赋值运算注意必须按照优先级来先乘除 再加减


    let multiplicative = unary.clone().foldl(        choice((just('*').to(BinaryOp::Mul), just('/').to(BinaryOp::Div), just('%').to(BinaryOp::Mod))).padded().then(unary.clone()).repeated(),        |left, (op, right)| Expr::Binary { left: Box::new(left), op, right: Box::new(right) },    ).boxed();
let additive = multiplicative.clone().foldl( choice((just('+').to(BinaryOp::Add), just('-').to(BinaryOp::Sub))).padded().then(multiplicative.clone()).repeated(), |left, (op, right)| Expr::Binary { left: Box::new(left), op, right: Box::new(right) }, ).boxed();
复制代码


注意那个表达式后面的那个 box 还有你看到我们在里面如果引用到其他的那个算子的经常会用到那个 box。就是因为那个这种算子经常会出现循环引用。递归的情况。就是如果说不用 box 把它装起来的话,递归一定会造成堆栈溢出的。你可以如果你自己有空可以去试一下。你把 box 去掉,看看你的编译器多长时间会把你的机器给弄崩掉。


移位和位操作


let shift = additive.clone().foldl(            choice((just("<<").to(BinaryOp::Shl), just(">>").to(BinaryOp::Shr))).padded().then(additive.clone()).repeated(),            |left, (op, right)| Expr::Binary { left: Box::new(left), op, right: Box::new(right) },        ).boxed();
let bitand = shift.clone().foldl(just('&').to(BinaryOp::BitAnd).padded().then(shift.clone()).repeated(), |left, (op, right)| Expr::Binary { left: Box::new(left), op, right: Box::new(right) }).boxed();
let bitxor = bitand.clone().foldl(just('^').to(BinaryOp::BitXor).padded().then(bitand.clone()).repeated(), |left, (op, right)| Expr::Binary { left: Box::new(left), op, right: Box::new(right) }).boxed();
let bitor = bitxor.clone().foldl(just('|').to(BinaryOp::BitOr).padded().then(bitxor.clone()).repeated(), |left, (op, right)| Expr::Binary { left: Box::new(left), op, right: Box::new(right) }).boxed();
复制代码


然后是比较和逻辑操作

      let comparison_op = choice((just("==").to(BinaryOp::Eq), just("!=").to(BinaryOp::Ne), just('<').to(BinaryOp::Lt), just('>')            .to(BinaryOp::Gt), just("<=").to(BinaryOp::Le), just(">=").to(BinaryOp::Ge))).labelled("comparison operator");
let comparison = bitor.clone().foldl(comparison_op.padded().then(bitor.clone()).repeated(), |left, (op, right)| Expr::Binary { left: Box::new(left), op, right: Box::new(right) }).boxed();
let logical_op = choice((just("&&").to(BinaryOp::And), just("||").to(BinaryOp::Or))).labelled("logical operator"); let logical = comparison.clone().foldl(logical_op.padded().then(comparison).repeated(), |left, (op, right)| Expr::Binary { left: Box::new(left), op, right: Box::new(right) }).boxed();
复制代码

最后是 赋值

        let assignment = logical.clone().then(            choice((just("+=").to(BinaryOp::AddAssign), just("-=").to(BinaryOp::SubAssign), just("*=").to(BinaryOp::MulAssign), just("/=")                .to(BinaryOp::DivAssign), just("%=").to(BinaryOp::ModAssign))).padded().then(logical).or_not()).map_with(                    |(left, rest), _| if let Some((op, right)) = rest { Expr::Binary { left: Box::new(left), op, right: Box::new(right) } } else { left }).boxed();        assignment.padded()
复制代码


大功告成 让我们做一个简单的测试 似乎这是个不简单的表达式

const EXPR: &str = r#"[1, "Hello World", 10.2].aaaa(10 + 1 -100 * 7 + 1000) + 1023 + f(a)"#;
复制代码

解析结果如下



完美!


完美!

用户头像

Miracle

关注

三十年资深码农 2019-10-25 加入

还未添加个人简介

评论

发布
暂无评论
语法分析 之表达式三_Miracle_InfoQ写作社区