use std::io; use regex::Regex; enum Operator { ADD, SUB, MUL, DIV, } // structure to hold an expression in the stack struct Expression { value : f32, } // function to compute a result by popping the stack and // pushing back the result fn get_result (t : &mut Vec, op : Operator) -> Result { // pop the stack for last operand // if nothing - panic with error let n1 = t.pop (); if n1.is_none () { return Err ("Illegal expression".to_string()); } // pop the stack for the first operand // if nothing - panic with error let n2 = t.pop (); if n2.is_none () { return Err ("Illegal expression!".to_string()); } let num1 = n1.unwrap().value; let num2 = n2.unwrap().value; // depending on the operation, set the result match op { Operator::ADD => { t.push (Expression{value: num2 + num1}); Ok (num2 + num1) }, Operator::SUB => { t.push (Expression{value: num2 - num1}); Ok (num2 + num1) }, Operator::MUL => { t.push (Expression{value: num2 * num1}); Ok (num2 * num1) }, Operator::DIV => { t.push (Expression{value: num2 / num1}); Ok (num2 / num1) }, } } // evaluation function fn evaluate (expr : &str, match_num : ®ex::Regex) -> Result { let mut ops = Vec::::new (); // tokenize the individual words by splitting at whitespace let words = expr.split_whitespace (); // iterate over the words for word in words { match word { // if the word matches one of +, -, *, / then push it on the stack // and immediately evaluate the expression by popping the operator // and the last two operands and push the result back on to the stack "+" => { let m = get_result (&mut ops, Operator::ADD); if ! m.is_ok () { return Err (m.unwrap_err().to_string()); } }, "-" => { let m = get_result (&mut ops, Operator::SUB); if ! m.is_ok () { return Err (m.unwrap_err().to_string()); } }, "*" => { let m = get_result (&mut ops, Operator::MUL); if ! m.is_ok () { return Err (m.unwrap_err().to_string()); } }, "/" => { let m = get_result (&mut ops, Operator::DIV); if ! m.is_ok () { return Err (m.unwrap_err().to_string()); } }, // if word matches a number, push it on to the stack _ => if match_num.is_match (word) { let num = word.parse ().unwrap (); ops.push (Expression { value: num }); } // if word doesn't match either operator or number then panic. else { return Err ("Error parsing expression! \ Must be a number or operator (+,-,* or /)".to_string()); } } } if ops.len () > 1 { // if the stack has more than one value, it means that the postfix // expression is not complete - so display the stack status return Err ("Postfix expression incomplete!".to_string()); } else { // stack has only one item which is the result so display it let res = ops[0].value; return Ok (res); } } fn main() { // get a line from input and evaluate it let mut expr = String::new (); // regular expression to match a number let match_num = Regex::new (r"^\d+?.*?\d*?$").unwrap (); // loop until a blank line is received loop { expr.clear (); println!("Enter an expression (postfix) (blank to quit): "); // read a line of text io::stdin().read_line (&mut expr).expect ("Error reading line!"); // trim the text let expr = expr.trim (); // quit if the expression is blank if expr == "" { break; } let res = evaluate (&expr, &match_num); if res.is_ok () { println! ("Result is : {}", res.unwrap()); } else { eprintln! ("Error: {}", res.unwrap_err()); } } }