Skip to content
Snippets Groups Projects
Commit 8e57e2da authored by Per's avatar Per
Browse files

main4 wip

parent 7d6d08c6
No related branches found
No related tags found
No related merge requests found
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);
// }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment