Skip to content
Snippets Groups Projects
Commit 411611a6 authored by Per Lindgren's avatar Per Lindgren
Browse files

cleanup

parent 7f2de6c9
No related branches found
No related tags found
No related merge requests found
File moved
......@@ -144,6 +144,7 @@ fn main() {
test("2+3**2**3*5+1", 2 + 3i32.pow(2u32.pow(3)) * 5 + 1);
test("(12*2)/3-4", (12 * 2) / 3 - 4);
test("1*2+3", 1 * 2 + 3);
// just to check that we get a parse error
test("1*2+3+3*21-a12+2", 1 * 2 + 3 + 3 * 21 - 12 + 2);
}
......
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>),
}
// // deep cloning (is it necessary)
// impl Clone for Expr {
// fn clone(&self) -> Expr {
// match self {
// Expr::BinOp(l, op, r) => Expr::BinOp (
// l.clone(), *op, r.clone()
// ),
// Expr::Num(i) => Expr::Num(*i)
// }
// }
// }
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!("({:?}, {}, {})", 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),
}
}
}
}
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 build_expr(l:&Expr, op:&Op, r:&Expr) -> Expr {
// Expr::BinOp(Box::new(*l), *op, Box::new(*r))
// }
fn climb(e: Expr, min_prec: u8) -> Expr {
println!("in climb {}, {}", math_expr(&e), min_prec);
match e.clone() {
Expr::Num(_) => e,
Expr::BinOp(l, op, r) => {
let (prec, ass) = climb_op(&op);
let mut res = e.clone();
let mut cur = e.clone();
while let Expr::BinOp(l, op, r) = cur {
cur = *r.clone();
let rhs = climb(
cur.clone(),
prec + match ass {
Ass::Left => 1,
Ass::Right => 0,
},
);
println!("rhs {}", math_expr(&rhs));
res = Expr::BinOp(Box::new(res), op, Box::new(rhs))
}
res
}
}
}
// fn test_eq(s: &str, v: i32) {
// assert_eq!(math_eval(&climb(parse_expr(s).unwrap().1), 0), 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);
// }
// #[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 {}", math_expr(&p));
let r = climb(p, 0);
println!("r {:?}", &r);
println!("math r {}", math_expr(&r));
println!("eval r {} = {} ", math_eval(&r), v);
}
fn main() {
// 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);
}
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);
// }
extern crate nom;
use nom::{
branch::alt,
bytes::complete::tag,
character::complete::char,
character::complete::{digit1, multispace0},
combinator::{cut, map, opt},
error::ParseError,
multi::{fold_many0, many0, separated_list},
sequence::{delimited, preceded, tuple},
IResult,
};
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Op {
Eq,
Neq,
Add,
Sub,
Mul,
Div,
Pow,
Minus,
Not,
Par
}
#[derive(Debug, Clone, PartialEq)]
pub enum Expr {
Atom(Atom),
BinOp(Op, Box<Expr>, 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::Atom(Atom::Num(digit_str.parse::<i32>().unwrap()))
})(i)
}
fn parse_uop(i: &str) -> IResult<&str, Op> {
preceded(
multispace0,
alt((map(tag("-"), |_| Op::Minus), map(tag("!"), |_| Op::Not))),
)(i)
}
fn parse_mulop(i: &str) -> IResult<&str, Op> {
preceded(
multispace0,
alt((map(tag("*"), |_| Op::Mul), map(tag("/"), |_| Op::Div))),
)(i)
}
fn parse_addop(i: &str) -> IResult<&str, Op> {
preceded(
multispace0,
alt((map(tag("+"), |_| Op::Add), map(tag("-"), |_| Op::Sub))),
)(i)
}
// expr ::= eq-expr
// eq-expr ::= add-expr ( ( '==' | '!=' ) add-expr ) *
// add-expr ::= mul-expr ( ( '+' | '-' ) mul-expression ) *
// mul-expr ::= primary ( ( '*' | '/' ) terminal ) *
// terminal ::= '(' expr ')' | NUMBER | VARIABLE | '-' primary
fn parse_expr(i: &str) -> IResult<&str, Expr> {
parse_additative(i)
}
fn parse_additative(i: &str) -> IResult<&str, Expr> {
//map(tuple((parse_terminal, opt(parse_rhs)), |((_,t), _)| t))(i)
map(
tuple((
parse_multiplicative,
many0(tuple((parse_addop, parse_multiplicative))),
)),
|(t, m)| {
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,
many0(tuple((parse_mulop, parse_multiplicative))),
)),
|(t, m)| {
m.iter()
.fold(t, |l, (op, r)| climb(l, op.clone(), r.clone()))
},
)(i)
}
fn parse_terminal(i: &str) -> IResult<&str, Expr> {
preceded(
multispace0,
alt((
parse_i32,
map(tuple((parse_uop, parse_terminal)), |(uop, e)| {
Expr::Unary(uop, Box::new(e))
}),
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>
where
F: Fn(&'a str) -> IResult<&'a str, O, E>,
E: ParseError<&'a str>,
{
// delimited allows us to split up the input
// cut allwos us to consume the input (and prevent backtracking)
delimited(char('('), preceded(multispace0, inner), cut(char(')')))
}
fn main() {
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);
}
fn math_expr(e: &Expr) -> String {
match e {
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::Atom(Atom::Num(i)) => *i,
Expr::BinOp(op, l, 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),
_ => 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),
_ => unimplemented!(),
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment