diff --git a/examples/main5.rs b/examples/main5.rs index ca37cd4133b59570e0c82785b3ca31b2e6dcb987..7b41a4bbcd6b96c32c53a8f79f1cb25bbe21306c 100644 --- a/examples/main5.rs +++ b/examples/main5.rs @@ -21,41 +21,36 @@ pub enum Op { Mul, Div, Pow, -} - -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum UOp { Minus, Not, + Par } #[derive(Debug, Clone, PartialEq)] pub enum Expr { - Num(i32), + Atom(Atom), BinOp(Op, Box<Expr>, Box<Expr>), - Unary(UOp, Box<Expr>), + Unary(Op, Box<Expr>), } +#[derive(Debug, Clone, PartialEq)] +pub enum Atom { + Num(i32), + // Identifier + // Function application +} + + pub fn parse_i32(i: &str) -> IResult<&str, Expr> { map(digit1, |digit_str: &str| { - Expr::Num(digit_str.parse::<i32>().unwrap()) + Expr::Atom(Atom::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_uop(i: &str) -> IResult<&str, UOp> { +fn parse_uop(i: &str) -> IResult<&str, Op> { preceded( multispace0, - alt((map(tag("-"), |_| UOp::Minus), map(tag("!"), |_| UOp::Not))), + alt((map(tag("-"), |_| Op::Minus), map(tag("!"), |_| Op::Not))), )(i) } @@ -91,30 +86,46 @@ fn parse_additative(i: &str) -> IResult<&str, Expr> { many0(tuple((parse_addop, parse_multiplicative))), )), |(t, m)| { - println!("add: t {:?}, m {:?}", t, m); - let r = m.iter().fold(t, |l, (op, r)| { - println!("l {:?}, r {:?}", l, r); - Expr::BinOp(*op, Box::new(l), Box::new(r.clone())) - }); - r + m.iter() + .fold(t, |l, (op, r)| climb(l, op.clone(), r.clone())) }, )(i) } +fn binop(op: Op, l: Expr, r: Expr) -> Expr { + Expr::BinOp(op, Box::new(l), Box::new(r)) +} + +fn climb(l: Expr, op: Op, r: Expr) -> Expr { + match r.clone() { + Expr::BinOp(r_op, r_l, r_r) => { + let (prec, ass) = climb_op(&op); + let (r_prec, _) = climb_op(&r_op); + if r_prec + < prec + + match ass { + Ass::Left => 1, + _ => 0, + } + { + binop(r_op, binop(op, l, *r_l), *r_r) + } else { + binop(op, l, r) + } + } + _ => binop(op, l, r), + } +} + fn parse_multiplicative(i: &str) -> IResult<&str, Expr> { - //map(tuple((parse_terminal, opt(parse_rhs)), |((_,t), _)| t))(i) map( tuple(( parse_terminal, many0(tuple((parse_mulop, parse_multiplicative))), )), |(t, m)| { - println!("mul: t {:?}, m {:?}", t, m); - let r = m.iter().fold(t, |l, (op, r)| { - println!("l {:?}, r {:?}", l, r); - Expr::BinOp(*op, Box::new(l), Box::new(r.clone())) - }); - r + m.iter() + .fold(t, |l, (op, r)| climb(l, op.clone(), r.clone())) }, )(i) } @@ -127,15 +138,13 @@ fn parse_terminal(i: &str) -> IResult<&str, Expr> { map(tuple((parse_uop, parse_terminal)), |(uop, e)| { Expr::Unary(uop, Box::new(e)) }), - parse_parenthesis(parse_expr), + map(parse_parenthesis(parse_expr), |e| Expr::Unary(Op::Par, Box::new(e))) )), )(i) } // helpers -fn parse_parenthesis<'a, O, F, E>( - inner: F, -) -> impl Fn(&'a str) -> IResult<&'a str, O, E> +fn parse_parenthesis<'a, O, F, E>(inner: F) -> impl Fn(&'a str) -> IResult<&'a str, O, E> where F: Fn(&'a str) -> IResult<&'a str, O, E>, E: ParseError<&'a str>, @@ -146,26 +155,24 @@ where } fn main() { - let p = parse_additative("(1+2)*(5-1-1)").unwrap().1; - println!("{:?} {} {}", p, math_eval(&p), (1 + 2) * (5 - 1 - 1)); + let p = parse_additative("1-(1+1)-1)").unwrap().1; + println!("{:?} {} {}", p, math_eval(&p), 1-(1+1)-1); - let p = parse_additative("5*(20+2)/4").unwrap().1; - println!("{:?} {} {}", p, math_eval(&p), 5 * (20 + 2) / 4); + // let p = parse_additative("5*(20+2)/4").unwrap().1; + // println!("{:?} {} {}", p, math_eval(&p), 5 * (20 + 2) / 4); } fn math_expr(e: &Expr) -> String { match e { - Expr::Num(i) => format!("{}", i), - Expr::BinOp(op, l, r) => { - format!("({:?}, {}, {})", op, math_expr(l), math_expr(r)) - } + Expr::Atom(Atom::Num(i)) => format!("{}", i), + Expr::BinOp(op, l, r) => format!("({:?}, {}, {})", op, math_expr(l), math_expr(r)), Expr::Unary(op, e) => format!("({:?}, {})", op, math_expr(e)), } } fn math_eval(e: &Expr) -> i32 { match e { - Expr::Num(i) => *i, + Expr::Atom(Atom::Num(i)) => *i, Expr::BinOp(op, l, r) => { let lv = math_eval(l); let rv = math_eval(r); @@ -177,156 +184,34 @@ fn math_eval(e: &Expr) -> i32 { Op::Pow => lv.pow(rv as u32), _ => unimplemented!(), } + }, + Expr::Unary(op, e) => { + let e = math_eval(e); + match op { + Op::Par => e, + Op::Mul => -e, + _ => unimplemented!(), + } } + _ => unimplemented!(), } } -// #[derive(Debug, Copy, Clone, PartialEq)] -// 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), -// } -// } - -// operator precedence parser -// https://en.wikipedia.org/wiki/Operator-precedence_parser -// parse_expression () -// return parse_expression_1 (parse_primary (), 0) - -// parse_expression_1 (lhs, min_precedence) -// lookahead := peek next token -// while lookahead is a binary operator whose precedence is >= min_precedence -// op := lookahead -// advance to next token -// rhs := parse_primary () -// lookahead := peek next token -// while lookahead is a binary operator whose precedence is greater -// than op's, or a right-associative operator -// whose precedence is equal to op's -// rhs := parse_expression_1 (rhs, lookahead's precedence) -// lookahead := peek next token -// lhs := the result of applying op with operands lhs and rhs -// return lhs - -// fn token_to_expr(t: Token) -> Expr { -// match t { -// Token::Num(i) => Expr::Num(i), -// _ => panic!(), -// } -// } - -// fn climb(mut v: Vec<Token>, min_prec: u8) -> (Expr, Vec<Token>) { -// println!("in climb {:?}, {}", v, min_prec); -// let t = v.last().unwrap(); -// let mut result = token_to_expr(*t); -// // loop { -// // match v.pop() { -// // Some(Token::Num(_)) => { -// // println!("break num"); -// // break; -// // } -// // Some(Token::Op(op)) => { -// // println!("result {:?}, op {:?}, v:{:?}", result, op, v); -// // let (prec, assoc) = climb_op(&op); -// // if prec < min_prec { -// // println!("break prec"); -// // break; -// // } else { -// // println!("push"); -// // let next_min_prec = -// // if assoc == Ass::Left { 1 + prec } else { prec }; -// // let (rhs, v_rest) = climb(v.clone(), next_min_prec); -// // v = v_rest; -// // println!("return from call, rhs {:?}, v {:?}", rhs, v); -// // println!("current result {:?}", result); -// // result = Expr::BinOp(Box::new(result), op, Box::new(rhs)); -// // println!("new result {:?}", result); -// // } -// // } - -// // _ => { -// // println!("reaced end"); -// // break; -// // } // reached end -// // } -// // } -// (result, v) -// } - -// fn test_eq(s: &str, v: i32) { -// let mut p = parse_expr(s).unwrap().1; -// println!("{:?}", p); -// p.reverse(); -// let e = climb(p, 0); -// println!("{:?}", e); - -// println!("e = {}, v = {}", math_eval(&e.0), v); -// } - -// fn main() { -// test_eq("1 + 2", 1 + 2); -// // test_eq("1 + 2 * 3", 1 + 2 * 3); -// // test_eq("3 * 4 + 5", 3 * 4 + 5); - -// // // climb_test("2*5+10+10", 2*5+10+10); -// // // climb_test("2*5+10*11-1", 2*5+10*11-1); -// // // climb_test("2*5+10*11-2+12", 2*5+10*11-1+12); -// // // climb_test("1+2*3-4+5", 1 + 2 * 3 - 4 + 5); -// // climb_test("1", 1); -// // climb_test("1+2", 1 + 2); -// } - -// // // #[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); -// // // } - -// // // #[test] -// // // fn climb4() { -// // // test_eq("2^5", 2i32.pow(5)); -// // // } - -// // // #[test] -// // // fn climb5() { -// // // test_eq("2*3+4+5", 2 * 3 + 4 + 5); -// // // } - -// // // #[test] -// // // fn climb6() { -// // // test_eq("2*3-4*5-2", 2 * 3 - 4 * 5 - 2); -// // // } +#[derive(Debug, Copy, Clone, PartialEq)] +enum Ass { + Left, + Right, +} -// // // #[test] -// // // fn climb_err() { -// // // test_eq("2 + 2 ^ 5 -3", 2 + 2i32.pow(5 - 3)); -// // // } +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), + _ => unimplemented!(), + } +} -// // fn climb_test(s: &str, v: i32) { -// // let p = parse_expr(s).unwrap().1; -// // println!("{:?}", &p); -// // println!("math {}\n", math_expr(&p)); -// // let r = climb(p, 0); -// // println!("r {:?}", &r); -// // println!("math r {}", math_expr(&r)); -// // println!("eval r {} = {} ", math_eval(&r), v); -// // }