Last active
May 5, 2016 09:50
-
-
Save dermesser/61ff0b43d9498ae91e4e7484a067d7be to your computer and use it in GitHub Desktop.
A simple arithmetic parser in Rust, based on the excellent `combine` crate. Use by giving an expression as argument: $ target/debug/test-combine "a+4*b/c"
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// use with | |
// [dependencies] | |
// combine = "1.3.0" | |
extern crate combine; | |
use combine::*; | |
#[derive(Debug)] | |
enum Expr { | |
Scalar(f64), | |
Var(char), | |
Prod(Box<Expr>, Box<Expr>), | |
Div(Box<Expr>, Box<Expr>), | |
Sum(Box<Expr>, Box<Expr>), | |
Diff(Box<Expr>, Box<Expr>), | |
} | |
fn parse_expr(inp: State<&str>) -> ParseResult<Expr, &str> { | |
let tok = choice([char('-'), char('+')]).map(|op| { | |
move |a, b| { | |
if op == '+' { | |
Expr::Sum(Box::new(a), Box::new(b)) | |
} else if op == '-' { | |
Expr::Diff(Box::new(a), Box::new(b)) | |
} else { | |
unimplemented!() | |
} | |
} | |
}); | |
let mut sum = chainl1(parser(parse_term), tok); | |
sum.parse_state(inp) | |
} | |
fn parse_term(inp: State<&str>) -> ParseResult<Expr, &str> { | |
let tok = choice([char('*'), char('/')]).map(|op| { | |
move |a, b| { | |
if op == '*' { | |
Expr::Prod(Box::new(a), Box::new(b)) | |
} else if op == '/' { | |
Expr::Div(Box::new(a), Box::new(b)) | |
} else { | |
unimplemented!() | |
} | |
} | |
}); | |
let mut prod = chainl1(parser(parse_factor), tok); | |
prod.parse_state(inp) | |
} | |
fn parse_factor(inp: State<&str>) -> ParseResult<Expr, &str> { | |
let scalar = many1(digit()).map(|t: String| Expr::Scalar(t.parse().unwrap())); | |
let var = letter().map(Expr::Var); | |
let parens = between(char('('), char(')'), parser(parse_expr)); | |
spaces().with(scalar.or(var).or(parens)).skip(spaces()).parse_state(inp) | |
} | |
fn main() { | |
use std::env; | |
let mut a = env::args(); | |
let s = a.nth(1).unwrap(); | |
let result = parser(parse_expr).parse(s.as_str()); | |
println!("{:?}", result); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment