diff options
Diffstat (limited to 'src/parser.rs')
| -rw-r--r-- | src/parser.rs | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/src/parser.rs b/src/parser.rs new file mode 100644 index 0000000..fda744d --- /dev/null +++ b/src/parser.rs @@ -0,0 +1,202 @@ +use crate::lexer::Lexer; +use crate::num; +use crate::num::Num; +use num_bigint::BigInt; +use std::str::FromStr; + +struct Parser<'a> { + r: Lexer<'a>, + first_token: Option<&'a str>, +} + +impl<'a> Parser<'a> { + fn peek(&mut self) -> Option<&'a str> { + if let Some(t) = self.first_token { + return Some(t); + } + self.first_token = self.r.next(); + self.first_token + } + + fn next(&mut self) -> Option<&'a str> { + if let Some(t) = std::mem::take(&mut self.first_token) { + return Some(t); + } + self.r.next() + } + + fn symbol(&mut self, s: &str) -> bool { + let Some(t) = self.peek() else { + return false; + }; + if t != s { + return false; + } + self.next(); + true + } + + fn parse_num(&mut self) -> Option<Num> { + let negative = self.symbol("-"); + let t = self.next()?; + if t.contains('.') || t.contains('e') || t.contains('E') { + let f = f64::from_str(t).ok()?; + if negative { + return Some(num::float(-f)); + } + return Some(num::float(f)); + } + let i = BigInt::from_str(t).ok()?; + if negative { + return Some(num::int(-i)); + } + Some(num::int(i)) + } + + fn paren_expr(&mut self) -> Option<Num> { + if !self.symbol("(") { + return None; + } + let n = self.expr()?; + if !self.symbol(")") { + return None; + } + Some(n) + } + + fn parse_const(&mut self) -> Option<Num> { + if self.symbol("e") { + return Some(num::float(std::f64::consts::E)); + } + if self.symbol("pi") { + return Some(num::float(std::f64::consts::PI)); + } + None + } + + fn atom(&mut self) -> Option<Num> { + if let Some(n) = self.paren_expr() { + return Some(n); + } + if let Some(n) = self.parse_const() { + return Some(n); + } + self.parse_num() + } + + fn parse_fun(&mut self) -> Option<Num> { + if self.symbol("sin") { + return Some(self.atom()?.sin()); + } + if self.symbol("cos") { + return Some(self.atom()?.cos()); + } + if self.symbol("tan") { + return Some(self.atom()?.tan()); + } + if self.symbol("sqrt") { + return Some(self.atom()?.sqrt()); + } + if self.symbol("log") || self.symbol("ln") { + return Some(self.atom()?.log()); + } + if self.symbol("floor") { + return Some(self.atom()?.floor()); + } + if self.symbol("ceil") || self.symbol("ceiling") { + return Some(self.atom()?.ceil()); + } + if self.symbol("round") { + return Some(self.atom()?.round()); + } + None + } + + fn app_expr_fold(&mut self, e1: Num) -> Option<Num> { + if let Some(e2) = self.paren_expr() { + return self.app_expr_fold(e1.mul(e2)); + } + if let Some(e2) = self.parse_const() { + return self.app_expr_fold(e1.mul(e2)); + } + if let Some(e2) = self.parse_fun() { + return Some(e1.mul(e2)); + } + Some(e1) + } + + fn app_expr(&mut self) -> Option<Num> { + if let Some(e) = self.parse_fun() { + return Some(e); + } + let e1 = self.atom()?; + self.app_expr_fold(e1) + } + + fn expt_expr_fold(&mut self, e1: Num) -> Option<Num> { + if !self.symbol("^") { + return Some(e1); + } + let e2 = self.app_expr()?; + if let Some(e2) = self.expt_expr_fold(e2) { + return Some(e1.pow(e2)); + } + None + } + + fn expt_expr(&mut self) -> Option<Num> { + let n = self.app_expr()?; + self.expt_expr_fold(n) + } + + fn mul_expr_fold(&mut self, e1: Num) -> Option<Num> { + if self.symbol("*") { + let e2 = self.expt_expr()?; + let e = e1.mul(e2); + return self.mul_expr_fold(e); + } + if self.symbol("/") { + let e2 = self.expt_expr()?; + let e = e1.div(e2); + return self.mul_expr_fold(e); + } + if self.symbol("//") { + let e2 = self.expt_expr()?; + let e = e1.int_div(e2); + return self.mul_expr_fold(e); + } + Some(e1) + } + + fn mul_expr(&mut self) -> Option<Num> { + let n = self.expt_expr()?; + self.mul_expr_fold(n) + } + + fn add_expr_fold(&mut self, e1: Num) -> Option<Num> { + if self.symbol("+") { + let e2 = self.mul_expr()?; + let e = e1.add(e2); + return self.add_expr_fold(e); + } + if self.symbol("-") { + let e2 = self.mul_expr()?; + let e = e1.sub(e2); + return self.add_expr_fold(e); + } + Some(e1) + } + + fn expr(&mut self) -> Option<Num> { + let n = self.mul_expr()?; + self.add_expr_fold(n) + } +} + +pub fn parse(expr: &str) -> Option<Num> { + let mut p = Parser { + r: Lexer { buf: expr }, + first_token: None, + }; + p.expr() +} |
