From 145084b88fba64c2be6df10fdc6cd251df48b9b2 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 20 Mar 2023 11:36:43 -0700 Subject: [PATCH] Added word replacement Added more operators Cleaned up code --- src/main.rs | 6 +- src/parser.rs | 14 +++- src/parser/fold_operators.rs | 150 +++++++++++++++++++++++++++++++++++ src/parser/replace_words.rs | 39 +++++++++ src/parser/tokenize.rs | 58 +++++++------- src/parser/treefold.rs | 145 --------------------------------- 6 files changed, 236 insertions(+), 176 deletions(-) create mode 100644 src/parser/fold_operators.rs create mode 100644 src/parser/replace_words.rs delete mode 100644 src/parser/treefold.rs diff --git a/src/main.rs b/src/main.rs index a8362cc..e83614b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -79,7 +79,7 @@ fn main() -> Result<(), std::io::Error> { // Tokenize input. // Fail if we encounter invalid characters. - let mut exp = match parser::tokenize::tokenize(&input) { + let mut g = match parser::tokenize::tokenize(&input) { Ok(v) => v, Err(_) => { continue; @@ -92,9 +92,9 @@ fn main() -> Result<(), std::io::Error> { stdout.reset()?; write!(stdout, "Got {input}\n\n\n")?; - parser::treefold::treefold(&mut exp).expect("Could not fold"); + parser::parse(&mut g).expect("Could not fold"); - writeln!(stdout, "Tokenized: {exp:#?}")?; + writeln!(stdout, "Tokenized: {g:#?}")?; } writeln!(stdout, "Exiting.")?; diff --git a/src/parser.rs b/src/parser.rs index 26e9e57..c6ac76c 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,2 +1,14 @@ pub mod tokenize; -pub mod treefold; \ No newline at end of file +mod replace_words; +mod fold_operators; + +use crate::parser::tokenize::Token; +use crate::parser::replace_words::replace_words; +use crate::parser::fold_operators::fold_operators; + +pub fn parse(g: &mut Token) -> Result<(), ()> { + replace_words(g)?; + fold_operators(g)?; + + return Ok(()); +} \ No newline at end of file diff --git a/src/parser/fold_operators.rs b/src/parser/fold_operators.rs new file mode 100644 index 0000000..3e00a6c --- /dev/null +++ b/src/parser/fold_operators.rs @@ -0,0 +1,150 @@ +use std::collections::VecDeque; +use crate::parser::tokenize::Token; + +enum OperatorType { + Binary, // A binary operator, like a + b + UnaryLeft, // A left operator, like a! + UnaryRight // A right operator, like -a +} + +fn fold_operators_once( + g_main: &mut Token, // Must be a group + op_type: &OperatorType, + check: fn(&str) -> bool, + new_token: fn(&str, VecDeque) -> Token, +) -> Result<(), ()> { + + // Groups to process + let mut t_vec: VecDeque<&mut Token> = VecDeque::with_capacity(32); + t_vec.push_back(g_main); + + while t_vec.len() > 0 { + + // The group we're currently working with + let g: &mut Token = t_vec.pop_front().unwrap(); + let g_inner: &mut VecDeque = match g { + Token::PreGroup(ref mut x) => x, + _ => panic!() + }; + + let mut new: VecDeque = VecDeque::with_capacity(8); + + // Build new group array + while g_inner.len() > 0 { + let t: Token = match g_inner.pop_front() { + Some(o) => o, + None => break + }; + + let s: &str; + if let Token::PreOperator(ref x) = t { + s = x; + } else { + new.push_back(t); + continue; + } + + if check(s) { + match op_type { + OperatorType::UnaryLeft => { + let mut last: Token = new.pop_back().unwrap(); + + if let Token::PreGroup(_) = last { + fold_operators_once(&mut last, op_type, check, new_token).unwrap(); + } + + let mut new_token_args: VecDeque = VecDeque::with_capacity(1); + new_token_args.push_back(last); + new.push_back(new_token(s, new_token_args)); + }, + OperatorType::UnaryRight => { + let mut next: Token = g_inner.pop_front().unwrap(); + + if let Token::PreGroup(_) = next { + fold_operators_once(&mut next, op_type, check, new_token).unwrap(); + } + + let mut new_token_args: VecDeque = VecDeque::with_capacity(1); + new_token_args.push_back(next); + new.push_back(new_token(s, new_token_args)); + }, + OperatorType::Binary => { + let mut last: Token = new.pop_back().unwrap(); + let mut next: Token = g_inner.pop_front().unwrap(); + + // TODO: append to t_vec and do this without recursion. + if let Token::PreGroup(_) = last { + fold_operators_once(&mut last, op_type, check, new_token).unwrap(); + } + if let Token::PreGroup(_) = next { + fold_operators_once(&mut next, op_type, check, new_token).unwrap(); + } + + let mut new_token_args: VecDeque = VecDeque::with_capacity(2); + new_token_args.push_back(last); + new_token_args.push_back(next); + new.push_back(new_token(s, new_token_args)); + } + }; + } else { + new.push_back(t); + } + } + + *g_inner = new; + } + + return Ok(()); +} + +pub fn fold_operators(exp: &mut Token) -> Result<(), ()> { + fold_operators_once( + exp, &OperatorType::UnaryLeft, + |s| s=="!", + |_s, x| Token::Factorial(x) + )?; + fold_operators_once( + exp, &OperatorType::UnaryRight, + |s| s=="neg", + |_s, x| Token::Negative(x) + )?; + + fold_operators_once( + exp, &OperatorType::Binary, + |s| s=="^", + |_s, x| Token::Power(x) + )?; + fold_operators_once( + exp, &OperatorType::Binary, + |s| s=="%", + |_s, x| Token::Modulo(x) + )?; + + fold_operators_once( + exp, &OperatorType::Binary, + |s| s=="*" || s == "/", + |s, x| match s { + "*" => Token::Multiply(x), + "/" => Token::Divide(x), + _=>panic!() + } + )?; + fold_operators_once( + exp, &OperatorType::Binary, + |s| s=="+" || s == "-", + |s, x| match s { + "+" => Token::Add(x), + "-" => Token::Subtract(x), + _=>panic!() + } + )?; + + + fold_operators_once( + exp, &OperatorType::Binary, + |s| s=="mod", + |_s, x| Token::Modulo(x) + )?; + + return Ok(()); +} \ No newline at end of file diff --git a/src/parser/replace_words.rs b/src/parser/replace_words.rs new file mode 100644 index 0000000..12c77bb --- /dev/null +++ b/src/parser/replace_words.rs @@ -0,0 +1,39 @@ +use std::collections::VecDeque; +use crate::parser::tokenize::Token; + +pub fn replace_words(g: &mut Token) -> Result<(), ()> { + let g_inner: &mut VecDeque = match g { + Token::PreGroup(ref mut x) => x, + _ => panic!() + }; + + let mut new: VecDeque = VecDeque::with_capacity(8); + + while g_inner.len() > 0 { + let mut t: Token = match g_inner.pop_front() { + Some(o) => o, + None => break + }; + + match t { + Token::PreGroup(_) => { + replace_words(&mut t)?; + new.push_back(t); + }, + Token::PreWord(ref s) => { + if s == "to" { + new.push_back(Token::PreOperator(String::from("to"))); + } else if s == "mod" { + new.push_back(Token::PreOperator(String::from("mod"))); + } else { + new.push_back(t); + } + }, + _ => { new.push_back(t); } + }; + } + + *g_inner = new; + + return Ok(()); +} \ No newline at end of file diff --git a/src/parser/tokenize.rs b/src/parser/tokenize.rs index 4b57833..928c7c9 100644 --- a/src/parser/tokenize.rs +++ b/src/parser/tokenize.rs @@ -6,22 +6,22 @@ use std::collections::VecDeque; pub enum Token { // Only used after tokenizing - Negative, - Factorial, - Group(VecDeque), // Will be expanded during tree folding - Operator(String), // Will become Ops during tree folding - - // Used in both - Number(String), - Word(String), + PreGroup(VecDeque), + PreOperator(String), + PreNumber(String), + PreWord(String), // Only used in tree Multiply(VecDeque), Divide(VecDeque), Add(VecDeque), Subtract(VecDeque), - Fac(VecDeque), - Neg(VecDeque) + Factorial(VecDeque), + Negative(VecDeque), + Power(VecDeque), + Modulo(VecDeque), + + //Function(String, VecDeque), } @@ -37,21 +37,21 @@ pub enum Token { pub fn tokenize(input: &String) -> Result { let mut t: Option = None; // The current token we're reading let mut g: Vec = Vec::with_capacity(8); // Vector of "grouping levels" - g.push(Token::Group(VecDeque::with_capacity(8))); + g.push(Token::PreGroup(VecDeque::with_capacity(8))); for c in input.chars() { // The grouping level we're on now let g_now: &mut VecDeque = match g.last_mut().unwrap() { - Token::Group(ref mut x) => x, + Token::PreGroup(ref mut x) => x, _ => panic!() }; match c { '!' => { if t.is_some() { g_now.push_back(t.unwrap()); t = None; } - g_now.push_back(Token::Factorial); + g_now.push_back(Token::PreOperator(String::from("!"))); }, // Minus sign can be both a Negative and an Operator. @@ -61,14 +61,14 @@ pub fn tokenize(input: &String) -> Result { match g_now.back() { // If previous token was any of the following, // this is the "minus" operator - Some(Token::Number(_)) | - Some(Token::Group(_)) | - Some(Token::Word(_)) => { - g_now.push_back(Token::Operator(String::from(c))); + Some(Token::PreNumber(_)) | + Some(Token::PreGroup(_)) | + Some(Token::PreWord(_)) => { + g_now.push_back(Token::PreOperator(String::from(c))); }, // Otherwise, this is a negative sign. - _ => { g_now.push_back(Token::Negative); } + _ => { g_now.push_back(Token::PreOperator(String::from("neg"))); } }; }, @@ -78,7 +78,7 @@ pub fn tokenize(input: &String) -> Result { match &mut t { // If we're already building a number, // append. - Some(Token::Number(val)) => { + Some(Token::PreNumber(val)) => { val.push(if c == ',' {'.'} else {c}); }, @@ -86,7 +86,7 @@ pub fn tokenize(input: &String) -> Result { // previous token and start one. _ => { if t.is_some() { g_now.push_back(t.unwrap()); } - t = Some(Token::Number(String::from(c))); + t = Some(Token::PreNumber(String::from(c))); } }; }, @@ -97,7 +97,7 @@ pub fn tokenize(input: &String) -> Result { match &mut t { // If we're already building a number, // append. - Some(Token::Word(val)) => { + Some(Token::PreWord(val)) => { val.push(c); }, @@ -105,7 +105,7 @@ pub fn tokenize(input: &String) -> Result { // previous token and start one. _ => { if t.is_some() { g_now.push_back(t.unwrap()); } - t = Some(Token::Word(String::from(c))); + t = Some(Token::PreWord(String::from(c))); } }; }, @@ -113,24 +113,28 @@ pub fn tokenize(input: &String) -> Result { // Operation // Always one character - '+' | '*' | '/' | '^' => { + '+' | + '*' | + '/' | + '^' | + '%' => { // Finalize previous token if t.is_some() { g_now.push_back(t.unwrap()); t = None; } - g_now.push_back(Token::Operator(String::from(c))); + g_now.push_back(Token::PreOperator(String::from(c))); } // Groups // Always one character '(' => { if t.is_some() { g_now.push_back(t.unwrap()); t = None; } - g.push(Token::Group(VecDeque::with_capacity(8))); + g.push(Token::PreGroup(VecDeque::with_capacity(8))); }, ')' => { if t.is_some() { g_now.push_back(t.unwrap()); t = None; } let new_group: Token = g.pop().unwrap(); let g_now: &mut VecDeque = match g.last_mut().unwrap() { - Token::Group(ref mut x) => x, + Token::PreGroup(ref mut x) => x, _ => panic!() }; @@ -149,7 +153,7 @@ pub fn tokenize(input: &String) -> Result { let g_now: &mut VecDeque = match g.last_mut().unwrap() { - Token::Group(ref mut x) => x, + Token::PreGroup(ref mut x) => x, _ => panic!() }; if t.is_some() { g_now.push_back(t.unwrap()); } diff --git a/src/parser/treefold.rs b/src/parser/treefold.rs deleted file mode 100644 index f926a4b..0000000 --- a/src/parser/treefold.rs +++ /dev/null @@ -1,145 +0,0 @@ -use std::collections::VecDeque; - -use crate::parser::tokenize::Token; - -fn treefold_one( - exp: &mut Token, // Must be a group - check: fn(&Token) -> bool, - op_type: u8, - new_token: fn(VecDeque) -> Token, -) -> Result<(), ()> { - - // Groups to process - let mut t_vec: VecDeque<&mut Token> = VecDeque::with_capacity(32); - t_vec.push_back(exp); - - while t_vec.len() > 0 { - - // The group we're currently working with - let g: &mut Token = t_vec.pop_front().unwrap(); - let g_inner: &mut VecDeque = match g { - Token::Group(ref mut x) => x, - _ => panic!() - }; - - let mut new: VecDeque = VecDeque::with_capacity(8); - - // Build new group array - while g_inner.len() > 0 { - let t: Token = match g_inner.pop_front() { - Some(o) => o, - None => break - }; - - if check(&t) { - match op_type { - 0 => { - let mut last: Token = new.pop_back().unwrap(); - - if let Token::Group(_) = last { - treefold_one(&mut last, check, op_type, new_token).unwrap(); - } - - let mut new_token_args: VecDeque = VecDeque::with_capacity(1); - new_token_args.push_back(last); - new.push_back(new_token(new_token_args)); - }, - 1 => { - let mut next: Token = g_inner.pop_front().unwrap().clone(); - - if let Token::Group(_) = next { - treefold_one(&mut next, check, op_type, new_token).unwrap(); - } - - let mut new_token_args: VecDeque = VecDeque::with_capacity(1); - new_token_args.push_back(next); - new.push_back(new_token(new_token_args)); - }, - 2 => { - let mut last: Token = new.pop_back().unwrap(); - let mut next: Token = g_inner.pop_front().unwrap().clone(); - - // TODO: append to t_vec, do this without recursion. - if let Token::Group(_) = last { - treefold_one(&mut last, check, op_type, new_token).unwrap(); - } - if let Token::Group(_) = next { - treefold_one(&mut next, check, op_type, new_token).unwrap(); - } - - let mut new_token_args: VecDeque = VecDeque::with_capacity(2); - new_token_args.push_back(last); - new_token_args.push_back(next); - new.push_back(new_token(new_token_args)); - }, - _ => panic!() - }; - } else { - new.push_back(t.clone()); - } - } - - *g_inner = new; - } - - Ok(()) -} - - -fn is_mult(t: &Token) -> bool { - match t { - Token::Operator(s) => {s == "*"}, - _ => false - } -} -fn new_mult(v: VecDeque) -> Token { Token::Multiply(v) } - -fn is_add(t: &Token) -> bool { - match t { - Token::Operator(s) => {s == "+"}, - _ => false - } -} -fn new_add(v: VecDeque) -> Token { Token::Add(v) } - -fn is_div(t: &Token) -> bool { - match t { - Token::Operator(s) => {s == "/"}, - _ => false - } -} -fn new_div(v: VecDeque) -> Token { Token::Divide(v) } - -fn is_sub(t: &Token) -> bool { - match t { - Token::Operator(s) => {s == "-"}, - _ => false - } -} -fn new_sub(v: VecDeque) -> Token { Token::Subtract(v) } - -fn is_fac(t: &Token) -> bool { - match t { - Token::Factorial => true, - _ => false - } -} -fn new_fac(v: VecDeque) -> Token { Token::Fac(v) } - -fn is_neg(t: &Token) -> bool { - match t { - Token::Negative => true, - _ => false - } -} -fn new_neg(v: VecDeque) -> Token { Token::Neg(v) } - -pub fn treefold(exp: &mut Token) -> Result<(), ()> { - treefold_one(exp, is_fac, 0, new_fac)?; - treefold_one(exp, is_neg, 1, new_neg)?; - treefold_one(exp, is_mult, 2, new_mult)?; - treefold_one(exp, is_div, 2, new_div)?; - treefold_one(exp, is_add, 2, new_add)?; - treefold_one(exp, is_sub, 2, new_sub)?; - Ok(()) -} \ No newline at end of file