Skip to content

Instantly share code, notes, and snippets.

@akashsoni01
Forked from cordx56/calc.rs
Created September 25, 2023 06:37
Show Gist options
  • Save akashsoni01/436fe071235920d3351523fb7fea2113 to your computer and use it in GitHub Desktop.
Save akashsoni01/436fe071235920d3351523fb7fea2113 to your computer and use it in GitHub Desktop.
calculator written in Rust with parser combinator framework nom
extern crate nom;
use nom::{
IResult,
character::complete::{
multispace0,
char,
digit1,
},
branch::{
alt,
permutation,
},
combinator::{
all_consuming,
map_res,
},
multi::{
many0,
},
sequence::delimited,
};
use std::num::ParseFloatError;
fn addsub(s: &str) -> IResult<&str, f64> {
map_res(
permutation((
muldiv,
many0(
map_res(
permutation((
multispace0,
alt((
char('+'),
char('-'),
)),
multispace0,
muldiv,
)),
|(_, opr, _, rval)| -> Result<f64, &str> {
if opr == '+' {
Ok(rval)
} else {
Ok(-1.0 * rval)
}
}
)
),
)),
|(lval, rvec)| -> Result<f64, &str> {
Ok(lval + rvec.iter().fold(0.0, |acc, x| { acc + x }))
}
)(s)
}
fn muldiv(s: &str) -> IResult<&str, f64> {
map_res(
permutation((
fact,
many0(
map_res(
permutation((
multispace0,
alt((
char('*'),
char('/'),
)),
multispace0,
fact,
)),
|(_, opr, _, rval)| -> Result<f64, &str> {
if opr == '*' {
Ok(rval)
} else {
Ok(1.0 / rval)
}
}
)
),
)),
|(lval, rvec)| -> Result<f64, &str> {
Ok(lval * rvec.iter().fold(1.0, |acc, x| { acc * x }))
}
)(s)
}
fn fact(s: &str) -> IResult<&str, f64> {
alt((
num,
delimited(
char('('),
delimited(multispace0, addsub, multispace0),
char(')'),
),
))(s)
}
fn num(s: &str) -> IResult<&str, f64> {
map_res(
digit1,
|int: &str| -> Result<f64, ParseFloatError> {
int.parse::<f64>()
}
)(s)
}
fn read<T: std::str::FromStr>() -> T {
let mut s = String::new();
std::io::stdin().read_line(&mut s).unwrap();
s.trim_end().parse().ok().unwrap()
}
fn main() {
let parser = all_consuming(addsub);
assert_eq!(parser("1 + 2"), Ok(("", 3.)));
assert_eq!(parser("1 * 2"), Ok(("", 2.)));
loop {
println!("{}", addsub(&read::<String>()).unwrap().1);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment