diff --git a/examples/climb.rs b/examples/climb.rs
new file mode 100644
index 0000000000000000000000000000000000000000..49ecb09f2ed83266a7ec46cd92cde3e2ee1226d0
--- /dev/null
+++ b/examples/climb.rs
@@ -0,0 +1,205 @@
+extern crate nom;
+
+use std::iter::Peekable;
+use std::slice::Iter;
+
+use nom::{
+    branch::alt,
+    bytes::complete::tag,
+    character::complete::char,
+    character::complete::{digit1, multispace0},
+    combinator::{cut, map},
+    error::ParseError,
+    multi::many1,
+    sequence::{delimited, preceded},
+    IResult,
+};
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum Op {
+    Eq,
+    Neq,
+    And,
+    Or,
+    Add,
+    Sub,
+    Mul,
+    Div,
+    Pow,
+    Not,
+}
+
+#[derive(Debug, Clone, PartialEq)]
+pub enum Expr {
+    Num(i32),
+    Par(Box<Expr>),
+    // Identifier
+    // Function application
+    BinOp(Op, Box<Expr>, Box<Expr>),
+    UnaryOp(Op, Box<Expr>),
+}
+
+pub fn parse_i32(i: &str) -> IResult<&str, i32> {
+    map(digit1, |digit_str: &str| digit_str.parse::<i32>().unwrap())(i)
+}
+
+fn parse_op(i: &str) -> IResult<&str, Op> {
+    alt((
+        map(tag("=="), |_| Op::Eq),
+        map(tag("!="), |_| Op::Neq),
+        map(tag("**"), |_| Op::Pow),
+        map(tag("&&"), |_| Op::And),
+        map(tag("||"), |_| Op::Or),
+        map(tag("+"), |_| Op::Add),
+        map(tag("-"), |_| Op::Sub),
+        map(tag("*"), |_| Op::Mul),
+        map(tag("/"), |_| Op::Div),
+        map(tag("!"), |_| Op::Not),
+    ))(i)
+}
+
+#[derive(Debug, Clone, PartialEq)]
+pub enum Token {
+    Num(i32),
+    Par(Vec<Token>),
+    Op(Op),
+}
+
+fn parse_terminal(i: &str) -> IResult<&str, Token> {
+    alt((
+        map(parse_i32, |v| Token::Num(v)),
+        map(parse_par(parse_tokens), |tokens| Token::Par(tokens)),
+    ))(i)
+}
+
+fn parse_token(i: &str) -> IResult<&str, Token> {
+    preceded(
+        multispace0,
+        alt((map(parse_op, |op| Token::Op(op)), parse_terminal)),
+    )(i)
+}
+
+fn parse_tokens(i: &str) -> IResult<&str, Vec<Token>> {
+    many1(parse_token)(i)
+}
+
+fn compute_atom(t: &mut Peekable<Iter<Token>>) -> Expr {
+    match t.next() {
+        Some(Token::Num(i)) => Expr::Num(*i),
+        Some(Token::Par(v)) => climb(&mut v.iter().peekable(), 0),
+        Some(Token::Op(op)) => Expr::UnaryOp(*op, Box::new(climb(t, 4))), // assume highest precedence
+        _ => panic!("error in compute atom"),
+    }
+}
+
+fn climb(t: &mut Peekable<Iter<Token>>, min_prec: u8) -> Expr {
+    let mut result = compute_atom(t);
+
+    loop {
+        match t.peek() {
+            Some(Token::Op(op)) => {
+                let (prec, ass) = get_prec(op);
+                if prec < min_prec {
+                    break;
+                };
+                let next_prec = prec
+                    + match ass {
+                        Ass::Left => 1,
+                        _ => 0,
+                    };
+                t.next();
+                let rhs = climb(t, next_prec);
+                result = Expr::BinOp(*op, Box::new(result), Box::new(rhs))
+            }
+            _ => {
+                break;
+            }
+        }
+    }
+    result
+}
+
+fn test(s: &str, v: i32) {
+    match parse_tokens(s) {
+        Ok(("", t)) => {
+            let mut t = t.iter().peekable();
+            println!("{:?}", &t);
+            let e = climb(&mut t, 0);
+            println!("{:?}", &e);
+            println!("eval {} {}", math_eval(&e), v);
+            assert_eq!(math_eval(&e), v);
+        }
+        Ok((s, t)) => println!(
+            "parse incomplete, \n parsed tokens \t{:?}, \n remaining \t{:?}",
+            t, s
+        ),
+        Err(err) => println!("{:?}", err),
+    }
+}
+
+fn main() {
+    test("- -1 + + 1", - -1 + 1);  // rust does not allow + as a unary op (I do ;)
+    test("(-1-1)+(-1+3)", (-1 - 1) + (-1) + 3);
+    // just to check that right associative works (you don't need to implement pow)
+    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);
+    test("1*2+3+3*21-a12+2", 1 * 2 + 3 + 3 * 21 - 12 + 2);
+}
+
+// helpers
+fn parse_par<'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 math_eval(e: &Expr) -> i32 {
+    match e {
+        Expr::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::UnaryOp(op, e) => {
+            let e = math_eval(e);
+            match op {
+                Op::Add => e,
+                Op::Sub => -e,
+                _ => unimplemented!(),
+            }
+        }
+        _ => unimplemented!(),
+    }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq)]
+enum Ass {
+    Left,
+    Right,
+}
+
+fn get_prec(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!(),
+    }
+}