extern crate nom; use nom::combinator::map_res; use nom::{ branch::alt, bytes::complete::tag, character::complete::{digit1, multispace0}, combinator::map, error::{context, VerboseError, VerboseErrorKind}, sequence::{preceded, tuple}, IResult, }; #[derive(Debug, Clone, Copy, PartialEq)] pub enum Op { Add, Sub, Mul, Div, Pow, } #[derive(Debug, Clone, PartialEq)] pub enum Expr { Num(i32), BinOp(Box<Expr>, Op, Box<Expr>), } pub fn parse_i32(i: &str) -> IResult<&str, Expr> { map(digit1, |digit_str: &str| { Expr::Num(digit_str.parse::<i32>().unwrap()) })(i) } fn parse_op(i: &str) -> IResult<&str, Op> { alt(( map(tag("+"), |_| Op::Add), map(tag("-"), |_| Op::Sub), map(tag("*"), |_| Op::Mul), map(tag("/"), |_| Op::Div), map(tag("^"), |_| Op::Pow), ))(i) } fn parse_expr(i: &str) -> IResult<&str, Expr> { preceded( multispace0, alt(( map( tuple((parse_i32, preceded(multispace0, parse_op), parse_expr)), |(l, op, r)| Expr::BinOp(Box::new(l), op, Box::new(r)), ), parse_i32, )), )(i) } fn math_expr(e: &Expr) -> String { match e { Expr::Num(i) => format!("{}", i), Expr::BinOp(l, op, r) => format!("({} {:?} {})", math_expr(l), op, math_expr(r)), } } fn math_eval(e: &Expr) -> i32 { match e { Expr::Num(i) => *i, Expr::BinOp(l, op, r) => { let lv = math_eval(l); let rv = math_eval(r); match op { Op::Add => lv + rv, Op::Sub => lv - rv, Op::Mul => lv * rv, Op::Div => lv / rv, Op::Pow => lv ^ rv, } } } } enum Ass { Left, Right, } fn climb_op(op: &Op) -> (u8, Ass) { match op { Op::Add => (1, Ass::Left), Op::Sub => (1, Ass::Left), Op::Mul => (2, Ass::Left), Op::Div => (2, Ass::Left), Op::Pow => (3, Ass::Right), } } fn test_clone(e: Expr) -> Expr { Expr::BinOp(Box::new(e.clone()), Op::Add, Box::new(e)) } // fn climb(e: Expr) -> Expr { // println!("climb {:?}", &e); // match e.clone() { // Expr::Num(_) => e, // Expr::BinOp(l, op, r) => { // let (prec, ass) = climb_op(&op); // // lookahead // let r_new = climb(*r); // match r_new.clone() { // Expr::Num(_) => Expr::BinOp(Box::new(*l), op, Box::new(r_new)), // Expr::BinOp(r_l, r_op, r_r) => { // let (r_prec, r_ass) = climb_op(&r_op); // println!( // "-- l: {:?}, r: {:?}, r_prec {}, prec {} // ", // r_l, r_r, prec, r_prec // ); // if r_prec // < prec // + match r_ass { // Ass::Left => 1, // Ass::Right => 0, // } // { // // swap // println!("swap"); // let new_l = Expr::BinOp(Box::new(*l), op, Box::new(*r_l)); // let new_top = Expr::BinOp(Box::new(new_l), r_op, Box::new(*r_r)); // new_top // } else { // Expr::BinOp(Box::new(*l), op, Box::new(r_new)) // } // } // } // } // } // } fn climb(e: Expr) -> Expr { println!("climb {:?}", &e); match e.clone() { Expr::Num(_) => e, Expr::BinOp(l, op, r) => { let (prec, ass) = climb_op(&op); // lookahead let e = match *r.clone() { Expr::Num(_) => e, Expr::BinOp(r_l, r_op, r_r) => { let (r_prec, r_ass) = climb_op(&r_op); println!( "-- l: {:?}, r: {:?}, r_prec {}, prec {} ", r_l, r_r, prec, r_prec ); if r_prec < prec + match r_ass { Ass::Left => 1, Ass::Right => 0, } { // swap println!("swap"); let new_l = Expr::BinOp(Box::new(*l), op, Box::new(*r_l)); let new_top = Expr::BinOp(Box::new(new_l), r_op, Box::new(*r_r)); climb(new_top) } else { e } } }; match e { Expr::Num(_) => e, Expr::BinOp(l, op, r) => Expr::BinOp(l, op, Box::new(climb(*r))) } } } } fn test_eq(s:&str, v:i32) { assert_eq!(math_eval(&climb(parse_expr(s).unwrap().1)), v); } #[test] fn climb1() { test_eq("1-2+3", 1-2+3); } #[test] fn climb2() { test_eq("1*2+3", 1*2+3); } #[test] fn climb3() { test_eq("1*2+3*4-5", 1*2+3*4-5); } fn main() { let p = parse_expr("3*2+5").unwrap().1; println!("{:?}", &p); println!("math {}", math_expr(&p)); let r = climb(p); println!("r {:?}", &r); println!("math r {}", math_expr(&r)); println!("eval r {} = {} ", math_eval(&r), 3 * 2 + 5); println!(); let p = parse_expr("3+2*5").unwrap().1; println!("{:?}", &p); println!("math {}", math_expr(&p)); let r = climb(p); println!("r {:?}", &r); println!("math r {}", math_expr(&r)); println!("eval r {} = {} ", math_eval(&r), 3 + 2 * 5); println!(); let p = parse_expr("3+2*5+27").unwrap().1; println!("{:?}", &p); println!("math {}", math_expr(&p)); let r = climb(p); println!("r {:?}", &r); println!("math r {}", math_expr(&r)); println!("eval r {} = {} ", math_eval(&r), 3 + 2 * 5 + 27); println!(); let p = parse_expr("2*5+11*27+13").unwrap().1; println!("{:?}", &p); println!("math {}", math_expr(&p)); let r = climb(p); println!("r {:?}", &r); println!("math r {}", math_expr(&r)); println!("eval r {} = {} ", math_eval(&r), 2 * 5 + 11 * 27 + 13); println!(); let p = parse_expr("1-2-3").unwrap().1; println!("{:?}", &p); println!("math {}", math_expr(&p)); let r = climb(p); println!("r {:?}", &r); println!("math r {}", math_expr(&r)); println!("eval r {} = {} ", math_eval(&r), 1 - 2 - 3); let i = "1-2-3-4"; println!("\n{}", i); let p = parse_expr(i).unwrap().1; println!("{:?}", &p); println!("math {}", math_expr(&p)); println!("eval r {} = {} ", math_eval(&p), 1 - 2 - 3 - 4); let r = climb(p); println!("r {:?}", &r); println!("math r {}", math_expr(&r)); println!("eval r {} = {} ", math_eval(&r), ((1 - 2) - 3) - 4); }