From 8e57e2da6ba49afff0831583019d046342ca5c5b Mon Sep 17 00:00:00 2001
From: Per <Per Lindgren>
Date: Tue, 10 Sep 2019 10:28:21 +0200
Subject: [PATCH] main4 wip

---
 examples/main4.rs | 240 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 240 insertions(+)
 create mode 100644 examples/main4.rs

diff --git a/examples/main4.rs b/examples/main4.rs
new file mode 100644
index 0000000..b5d0653
--- /dev/null
+++ b/examples/main4.rs
@@ -0,0 +1,240 @@
+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);
+// }
-- 
GitLab