use std::f64; #[derive(Debug, Copy, Clone, PartialEq)] pub struct Operator { token: char, operation: fn(f64, f64) -> f64, precedence: u8, is_left_associative: bool, } #[derive(Debug, Clone, PartialEq)] pub struct Function { token: String, relation: fn(f64) -> f64, } #[derive(Debug, Clone, PartialEq)] pub enum Token { Operator(Operator), Num(f64), Function(Function), LParen, RParen } impl Operator { fn token_from_op(token: char, operation: fn(f64, f64) -> f64, precedence: u8, is_left_associative: bool) -> Token { Token::Operator( Operator { token, operation, precedence, is_left_associative } ) } fn operate(self, x: f64, y: f64) -> f64 { (self.operation)(x, y) } } impl Function { fn token_from_fn(token: String, relation: fn(f64) -> f64) -> Token { Token::Function( Function { token, relation } ) } fn apply(self, arg: f64) -> f64 { (self.relation)(arg) } } fn main() { loop { let mut input = String::new(); stdin().read_line(&mut input).unwrap(); let input = input.trim(); let input = input.replace(" ", ""); if input == "exit" { return } let lexed = lexer(&input[..]); let postfixed = to_postfix(lexed.unwrap()); let evaled = eval_postfix(postfixed.unwrap()); println!("ans: {}", evaled.unwrap()); } } fn lexer(input: &str) -> Result, String> { let mut num_vec: String = String::new(); let mut char_vec: String = String::new(); let mut result: Vec = vec![]; for letter in input.chars() { match letter { '0'...'9' | '.' => { num_vec.push(letter); }, 'a'...'z' | 'A'...'Z' => { let parse_num = num_vec.parse::().ok(); if let Some(x) = parse_num { result.push(Token::Num(x)); result.push(Operator::token_from_op('*', |x, y| x * y, 3, true)); num_vec.clear(); } char_vec.push(letter); }, '+' | '-' | '/' | '*' | '^' => { let parse_num = num_vec.parse::().ok(); if let Some(x) = parse_num { result.push(Token::Num(x)); num_vec.clear(); } let operator_token: Token = match letter { '+' => Operator::token_from_op('+', |x, y| x + y, 2, true), '-' => Operator::token_from_op('-', |x, y| x - y, 2, true), '/' => Operator::token_from_op('/', |x, y| x / y, 3, true), '*' => Operator::token_from_op('*', |x, y| x * y, 3, true), '^' => Operator::token_from_op('^', |x, y| x.powf(y), 4, false), _ => panic!("unexpected op whuuu"), }; result.push(operator_token); }, '(' => { if char_vec.len() > 0 { let funct = char_vec.clone(); match &funct[..] { "sin" | "sine" => result.push(Function::token_from_fn("sin".into(), |x| x.to_radians().sin())), "cos" | "cosine" => result.push(Function::token_from_fn("cos".into(), |x| x.to_radians().cos())), "tan" | "tangent" => result.push(Function::token_from_fn("tan".into(), |x| x.to_radians().tan())), "csc" | "cosec" => result.push(Function::token_from_fn("csc".into(), |x| 1f64 / x.to_radians().sin())), "sec" | "secant" => result.push(Function::token_from_fn("sec".into(), |x| 1f64 / x.to_radians().cos())), "cot" | "cotangent" => result.push(Function::token_from_fn("cot".into(), |x| 1f64 / x.to_radians().tan())), "ln" => result.push(Function::token_from_fn("ln".into(), |x| x.ln())), "log" => result.push(Function::token_from_fn("log".into(), |x| x.log10())), _ => {} } char_vec.clear(); } else { let parse_num = num_vec.parse::().ok(); if let Some(x) = parse_num { result.push(Token::Num(x)); result.push(Operator::token_from_op('*', |x, y| x * y, 3, true)); num_vec.clear(); } } if let Some(x) = result.last() { match x { Token::RParen => { result.push(Operator::token_from_op('*', |x, y| x * y, 3, true)); }, _ => {} }; } result.push(Token::LParen); }, ')' => { let parse_num = num_vec.parse::().ok(); if let Some(x) = parse_num { result.push(Token::Num(x)); num_vec.clear(); } result.push(Token::RParen); } ' ' => {} _ => { return Err(format!("Unexpected character: {}", letter)) } } } let parse_num = num_vec.parse::().ok(); if let Some(x) = parse_num { result.push(Token::Num(x)); num_vec.clear(); } Ok(result) } fn to_postfix(tokens: Vec) -> Result, String> { let mut postfixed: Vec = vec![]; let mut op_stack: Vec = vec![]; for token in tokens { match token { Token::Num(_) => { postfixed.push(token); }, Token::Function(_) => { op_stack.push(token); } Token::Operator(current_op) => { while let Some(top_op) = op_stack.last() { match top_op { Token::LParen => { break; } Token::Operator(x) => { let tp = x.precedence; let cp = current_op.precedence; if tp > cp || (tp == cp && x.is_left_associative) { postfixed.push(op_stack.pop().unwrap()); } else { break; } } Token::Function(_) => { postfixed.push(op_stack.pop().unwrap()); } _ => { return Err(format!("{:?} must not be on operator stack", top_op)) } } } op_stack.push(token); }, Token::LParen => { op_stack.push(token); }, Token::RParen => { let mut push_until_paren: bool = false; while let Some(token) = op_stack.pop() { if token == Token::LParen { push_until_paren = true; break; } postfixed.push(token) } if !push_until_paren { return Err(String::from("Mismatched ')'")); } } } } while let Some(op) = op_stack.pop() { postfixed.push(op); } Ok(postfixed) } fn eval_postfix(postfixed: Vec) -> Result { let mut num_stack: Vec = vec![]; for token in postfixed { match token { Token::Num(n) => { num_stack.push(n); }, Token::Operator(op) => { if let Some(n2) = num_stack.pop() { if let Some(n1) = num_stack.pop() { num_stack.push(op.operate(n1, n2)) } else { return Err(format!("Too many operators, Too little operands")) } } else { return Err(format!("Too many operators, Too little operands")) } }, Token::Function(funct) => { if let Some(arg) = num_stack.pop() { num_stack.push(funct.apply(arg)) } } _ => { return Err(format!("Yo nibba how did this get here")) } } } if num_stack.len() == 1 { Ok(num_stack.pop().unwrap()) } else { Err(format!("Parser Error")) } }