Added word replacement

Added more operators

Cleaned up code
pull/2/head
Mark 2023-03-20 11:36:43 -07:00
parent 579f7f2ece
commit 145084b88f
Signed by: Mark
GPG Key ID: AD62BB059C2AAEE4
6 changed files with 236 additions and 176 deletions

View File

@ -79,7 +79,7 @@ fn main() -> Result<(), std::io::Error> {
// Tokenize input. // Tokenize input.
// Fail if we encounter invalid characters. // 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, Ok(v) => v,
Err(_) => { Err(_) => {
continue; continue;
@ -92,9 +92,9 @@ fn main() -> Result<(), std::io::Error> {
stdout.reset()?; stdout.reset()?;
write!(stdout, "Got {input}\n\n\n")?; 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.")?; writeln!(stdout, "Exiting.")?;

View File

@ -1,2 +1,14 @@
pub mod tokenize; pub mod tokenize;
pub mod treefold; 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(());
}

View File

@ -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>) -> 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<Token> = match g {
Token::PreGroup(ref mut x) => x,
_ => panic!()
};
let mut new: VecDeque<Token> = 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<Token> = 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<Token> = 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<Token> = 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(());
}

View File

@ -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<Token> = match g {
Token::PreGroup(ref mut x) => x,
_ => panic!()
};
let mut new: VecDeque<Token> = 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(());
}

View File

@ -6,22 +6,22 @@ use std::collections::VecDeque;
pub enum Token { pub enum Token {
// Only used after tokenizing // Only used after tokenizing
Negative, PreGroup(VecDeque<Token>),
Factorial, PreOperator(String),
Group(VecDeque<Token>), // Will be expanded during tree folding PreNumber(String),
Operator(String), // Will become Ops during tree folding PreWord(String),
// Used in both
Number(String),
Word(String),
// Only used in tree // Only used in tree
Multiply(VecDeque<Token>), Multiply(VecDeque<Token>),
Divide(VecDeque<Token>), Divide(VecDeque<Token>),
Add(VecDeque<Token>), Add(VecDeque<Token>),
Subtract(VecDeque<Token>), Subtract(VecDeque<Token>),
Fac(VecDeque<Token>), Factorial(VecDeque<Token>),
Neg(VecDeque<Token>) Negative(VecDeque<Token>),
Power(VecDeque<Token>),
Modulo(VecDeque<Token>),
//Function(String, VecDeque<Token>),
} }
@ -37,21 +37,21 @@ pub enum Token {
pub fn tokenize(input: &String) -> Result<Token, ()> { pub fn tokenize(input: &String) -> Result<Token, ()> {
let mut t: Option<Token> = None; // The current token we're reading let mut t: Option<Token> = None; // The current token we're reading
let mut g: Vec<Token> = Vec::with_capacity(8); // Vector of "grouping levels" let mut g: Vec<Token> = 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() { for c in input.chars() {
// The grouping level we're on now // The grouping level we're on now
let g_now: &mut VecDeque<Token> = match g.last_mut().unwrap() { let g_now: &mut VecDeque<Token> = match g.last_mut().unwrap() {
Token::Group(ref mut x) => x, Token::PreGroup(ref mut x) => x,
_ => panic!() _ => panic!()
}; };
match c { match c {
'!' => { '!' => {
if t.is_some() { g_now.push_back(t.unwrap()); t = None; } 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. // Minus sign can be both a Negative and an Operator.
@ -61,14 +61,14 @@ pub fn tokenize(input: &String) -> Result<Token, ()> {
match g_now.back() { match g_now.back() {
// If previous token was any of the following, // If previous token was any of the following,
// this is the "minus" operator // this is the "minus" operator
Some(Token::Number(_)) | Some(Token::PreNumber(_)) |
Some(Token::Group(_)) | Some(Token::PreGroup(_)) |
Some(Token::Word(_)) => { Some(Token::PreWord(_)) => {
g_now.push_back(Token::Operator(String::from(c))); g_now.push_back(Token::PreOperator(String::from(c)));
}, },
// Otherwise, this is a negative sign. // 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<Token, ()> {
match &mut t { match &mut t {
// If we're already building a number, // If we're already building a number,
// append. // append.
Some(Token::Number(val)) => { Some(Token::PreNumber(val)) => {
val.push(if c == ',' {'.'} else {c}); val.push(if c == ',' {'.'} else {c});
}, },
@ -86,7 +86,7 @@ pub fn tokenize(input: &String) -> Result<Token, ()> {
// previous token and start one. // previous token and start one.
_ => { _ => {
if t.is_some() { g_now.push_back(t.unwrap()); } 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<Token, ()> {
match &mut t { match &mut t {
// If we're already building a number, // If we're already building a number,
// append. // append.
Some(Token::Word(val)) => { Some(Token::PreWord(val)) => {
val.push(c); val.push(c);
}, },
@ -105,7 +105,7 @@ pub fn tokenize(input: &String) -> Result<Token, ()> {
// previous token and start one. // previous token and start one.
_ => { _ => {
if t.is_some() { g_now.push_back(t.unwrap()); } 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<Token, ()> {
// Operation // Operation
// Always one character // Always one character
'+' | '*' | '/' | '^' => { '+' |
'*' |
'/' |
'^' |
'%' => {
// Finalize previous token // Finalize previous token
if t.is_some() { g_now.push_back(t.unwrap()); t = None; } 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 // Groups
// Always one character // Always one character
'(' => { '(' => {
if t.is_some() { g_now.push_back(t.unwrap()); t = None; } 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; } if t.is_some() { g_now.push_back(t.unwrap()); t = None; }
let new_group: Token = g.pop().unwrap(); let new_group: Token = g.pop().unwrap();
let g_now: &mut VecDeque<Token> = match g.last_mut().unwrap() { let g_now: &mut VecDeque<Token> = match g.last_mut().unwrap() {
Token::Group(ref mut x) => x, Token::PreGroup(ref mut x) => x,
_ => panic!() _ => panic!()
}; };
@ -149,7 +153,7 @@ pub fn tokenize(input: &String) -> Result<Token, ()> {
let g_now: &mut VecDeque<Token> = match g.last_mut().unwrap() { let g_now: &mut VecDeque<Token> = match g.last_mut().unwrap() {
Token::Group(ref mut x) => x, Token::PreGroup(ref mut x) => x,
_ => panic!() _ => panic!()
}; };
if t.is_some() { g_now.push_back(t.unwrap()); } if t.is_some() { g_now.push_back(t.unwrap()); }

View File

@ -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>) -> 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<Token> = match g {
Token::Group(ref mut x) => x,
_ => panic!()
};
let mut new: VecDeque<Token> = 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<Token> = 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<Token> = 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<Token> = 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 { Token::Multiply(v) }
fn is_add(t: &Token) -> bool {
match t {
Token::Operator(s) => {s == "+"},
_ => false
}
}
fn new_add(v: VecDeque<Token>) -> Token { Token::Add(v) }
fn is_div(t: &Token) -> bool {
match t {
Token::Operator(s) => {s == "/"},
_ => false
}
}
fn new_div(v: VecDeque<Token>) -> Token { Token::Divide(v) }
fn is_sub(t: &Token) -> bool {
match t {
Token::Operator(s) => {s == "-"},
_ => false
}
}
fn new_sub(v: VecDeque<Token>) -> Token { Token::Subtract(v) }
fn is_fac(t: &Token) -> bool {
match t {
Token::Factorial => true,
_ => false
}
}
fn new_fac(v: VecDeque<Token>) -> Token { Token::Fac(v) }
fn is_neg(t: &Token) -> bool {
match t {
Token::Negative => true,
_ => false
}
}
fn new_neg(v: VecDeque<Token>) -> 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(())
}