shunting yard works for text

This commit is contained in:
Christoph J. Scherr 2023-02-14 16:05:15 +01:00
parent a518550cf1
commit 87b761b85c
1 changed files with 74 additions and 21 deletions

View File

@ -11,11 +11,13 @@
* expression parser. * expression parser.
*/ */
#[derive(PartialEq)]
enum Associativity { enum Associativity {
Right, Right,
Left Left
} }
#[derive(PartialEq)]
pub struct Operator { pub struct Operator {
character: char, character: char,
precedence: u8, precedence: u8,
@ -29,6 +31,17 @@ impl Operator {
} }
return false; return false;
} }
pub fn get_operator(c: char) -> Option<Operator> {
match c {
'+' => Some(ADDITION),
'-' => Some(SUBTRACTION),
'*' => Some(MULTIPLICATION),
'/' => Some(DIVISION),
'^' => Some(EXPONENTIATION),
_ => None
}
}
} }
const ADDITION: Operator = Operator { const ADDITION: Operator = Operator {
@ -58,7 +71,7 @@ const DIVISION: Operator = Operator {
const EXPONENTIATION: Operator = Operator { const EXPONENTIATION: Operator = Operator {
character: '*', character: '*',
precedence: 2, precedence: 2,
associativity: Associativity::Left associativity: Associativity::Right
}; };
const OPERATORS: [Operator; 5] = [ADDITION, SUBTRACTION, MULTIPLICATION, DIVISION, EXPONENTIATION]; const OPERATORS: [Operator; 5] = [ADDITION, SUBTRACTION, MULTIPLICATION, DIVISION, EXPONENTIATION];
@ -68,38 +81,78 @@ pub fn form_reverse_polish_notation(regular_math: &str) -> Result<String, String
let mut input_queue: Vec<char> = regular_math.chars().rev().collect(); let mut input_queue: Vec<char> = regular_math.chars().rev().collect();
let mut operator_stack: Vec<char> = Vec::new(); let mut operator_stack: Vec<char> = Vec::new();
// process all tokens first. // while there are tokens to br read:
while !(input_queue.is_empty()) { while !(input_queue.is_empty()) {
let token: char = *(input_queue.last().unwrap()); // read a token
input_queue.pop(); let token: char = input_queue.pop().unwrap();
dbg!(&token); dbg!(&token);
// if the token is:
// a number:
if token.is_numeric() { if token.is_numeric() {
println!("number"); // put it into the output_queue
} output_queue.push(token);
else if Operator::is_operator(token) {
println!("operator");
}
// Unnessecary, will be processed by the expression parser
//else if '(' == token {
// println!("(");
//}
//else if ')' == token {
// println!(")");
//}
else {
eprintln!("Unrecognized token: '{token}'");
std::process::exit(1);
} }
// a function
// handled by the expression parser
// a operator o1
else if Operator::is_operator(token) {
// (get the constant Operator (which is a struct) that fits to that token.)
let o1 = match Operator::get_operator(token) {
Some(valid_op) => valid_op,
None => {panic!("Operator '{token}' not found.");},
};
// while there is an operator o2 at the top of the stack
if !operator_stack.is_empty() {
dbg!(&operator_stack);
dbg!(&operator_stack);
let o2 = match Operator::get_operator(*(operator_stack.clone().last().clone().unwrap())) {
Some(valid_op) => valid_op,
None => {panic!("Operator '{token}' not found.");},
};
// and
// (o2 has greater precedence than o1 or (o1 and o2 have the same precedence and o1
// is left associative))
while ((operator_stack.last().is_some()) & ((o2.precedence > o1.precedence) | ((o1.precedence == o2.precedence) & (o1.associativity == Associativity::Left)))) {
dbg!(&operator_stack);
println!("REACHED THE MAGIC WHILE");
// pop o2 from the operator stack into the output queue.
// after this debug statement, the operator_stack is empty for no reason!!!!
// FIXME
let my_c = match operator_stack.pop() {
Some(c) => c,
None => {panic!("weirdly gone!")},
};
output_queue.push(my_c);
}
}
operator_stack.push(o1.character);
}
/*
// Unnessecary, will be processed by the expression parser
else if '(' == token {
println!("(");
}
else if ')' == token {
println!(")");
}
*/
else {
return Err("Unrecognized token: '{token}'".to_string());
}
} }
dbg!(&output_queue);
// afterwards, process any operators still on the operator_stack // afterwards, process any operators still on the operator_stack
while !(operator_stack.is_empty()) { while !(operator_stack.is_empty()) {
todo!(); output_queue.push(operator_stack.pop().unwrap());
} }
Ok("TODO".to_string()) dbg!(&output_queue);
let rpn: String = output_queue.iter().cloned().collect::<String>();
Ok(rpn)
} }
// after we have the rpn, we may want to calculate the values with it. // after we have the rpn, we may want to calculate the values with it.