Skip to content
Snippets Groups Projects
Select Git revision
  • b9f50e432eb2fe0f1276bb69c053bb9a7368675a
  • master default protected
  • exam
  • exper
  • klee
  • simple
  • v0.3.2
  • v0.3.1
  • v0.3.0
  • v0.2.2
  • v0.2.1
  • v0.2.0
  • v0.1.1
  • v0.1.0
14 results

check.rs

Blame
  • main4.rs 5.74 KiB
    extern crate nom;
    
    use nom::{
        branch::alt,
        bytes::complete::tag,
        character::complete::{digit1, multispace0},
        combinator::map,
        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>),
    }
    
    #[derive(Debug, Clone, Copy, PartialEq)]
    pub enum Token {
        Num(i32),
        Op(Op),
    }
    
    pub fn parse_i32(i: &str) -> IResult<&str, Token> {
        map(digit1, |digit_str: &str| {
            Token::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, Vec<Token>> {
        preceded(
            multispace0,
            alt((
                map(
                    tuple((parse_i32, preceded(multispace0, parse_op), parse_expr)),
                    |(l, op, r)| {
                        let mut v = Vec::new();
                        v.push(l);
                        v.push(Token::Op(op));
                        v.extend(r);
                        v
                    },
                ),
                map(parse_i32, |i| {
                    let mut v = Vec::new();
                    v.push(i);
                    v
                }),
            )),
        )(i)
    }
    
    fn math_expr(e: &Expr) -> String {
        match e {
            Expr::Num(i) => format!("{}", i),
            Expr::BinOp(l, op, r) => {
                format!("({:?}, {}, {})", op, math_expr(l), 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.pow(rv as u32),
                }
            }
        }
    }
    
    #[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),
        }
    }
    
    // boilerplate
    // compute_expr(min_prec):
    //   result = compute_atom()
    
    //   while cur token is a binary operator with precedence >= min_prec:
    //     prec, assoc = precedence and associativity of current token
    //     if assoc is left:
    //       next_min_prec = prec + 1
    //     else:
    //       next_min_prec = prec
    //     rhs = compute_expr(next_min_prec)
    //     result = compute operator(result, rhs)
    
    //   return result
    
    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.pop().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);
    // // }
    
    // // #[test]
    // // fn climb_err() {
    // //     test_eq("2 + 2 ^ 5 -3", 2 + 2i32.pow(5 - 3));
    // // }
    
    // 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);
    // }