aboutsummaryrefslogtreecommitdiffstats
path: root/src/parser.rs
diff options
context:
space:
mode:
authorRose Hogenson <rosehogenson@posteo.net>2024-05-27 16:04:31 -0700
committerRose Hogenson <rosehogenson@posteo.net>2024-05-27 16:04:31 -0700
commit4debd88807c538aa430ce69b83fdb291f687b1b1 (patch)
tree5def99861585367826937c2bdbbfba7f23e07f0b /src/parser.rs
downloadqc-4debd88807c538aa430ce69b83fdb291f687b1b1.tar.zst
Rewrite in Rust.
Diffstat (limited to 'src/parser.rs')
-rw-r--r--src/parser.rs202
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()
+}