8 const ILLEGAL_EXP : &'static str = "Illegal Expression";
9 const ERR_PARSING_NOT_MATCH : &'static str = "Error parsing expression! \
10 Must be a number or operator (+,-,* or /)";
11 const ERR_POSTFIX_INCOMPLETE : &'static str = "Postfix expression incomplete!";
12 const ERR_FLUSHING : &'static str = "Error flushing!";
13 const ERR_READING_LINE : &'static str = "Error reading line!";
14 const HELP_TEXT : [&str ; 4] =
15 ["Type an expression in postfix style to evaluate.",
16 "Example: 4 5 + 12 -",
17 "Supported operators: +, -, *, /",
21 const RESULT : &'static str = "Result";
22 const ERROR : &'static str = "Error";
23 const ERROR_HELP : &'static str = "Type ? or h or H for help";
25 // Describe an operator - one of add, subtract, multiply or divide
33 // structure to hold an expression in the stack
38 // function to compute a result by popping the stack and
39 // pushing back the result
40 fn get_result (t : &mut Vec<Expression>, op : Operator) -> Result<f32,String> {
41 // pop the stack for last operand
42 // if nothing - panic with error
45 return Err (ILLEGAL_EXP.to_string());
47 // pop the stack for the first operand
48 // if nothing - panic with error
51 return Err (ILLEGAL_EXP.to_string());
54 let num1 = n1.unwrap().value;
55 let num2 = n2.unwrap().value;
57 // depending on the operation, set the result
60 t.push (Expression{value: num2 + num1});
64 t.push (Expression{value: num2 - num1});
68 t.push (Expression{value: num2 * num1});
72 t.push (Expression{value: num2 / num1});
78 // evaluation function
79 fn evaluate (expr : &str, match_num : ®ex::Regex) -> Result<f32,String> {
80 let mut ops = Vec::<Expression>::new ();
81 // tokenize the individual words by splitting at whitespace
82 let words = expr.split_whitespace ();
84 // iterate over the words
87 // if the word matches one of +, -, *, / then push it on the stack
88 // and immediately evaluate the expression by popping the operator
89 // and the last two operands and push the result back on to the stack
91 let m = get_result (&mut ops, Operator::ADD);
93 return Err (m.unwrap_err().to_string());
97 let m = get_result (&mut ops, Operator::SUB);
99 return Err (m.unwrap_err().to_string());
103 let m = get_result (&mut ops, Operator::MUL);
105 return Err (m.unwrap_err().to_string());
109 let m = get_result (&mut ops, Operator::DIV);
111 return Err (m.unwrap_err().to_string());
114 // if word matches a number, push it on to the stack
115 _ => if match_num.is_match (word) {
116 let num = word.parse ().unwrap ();
117 ops.push (Expression { value: num });
119 // if word doesn't match either operator or number then panic.
121 return Err (ERR_PARSING_NOT_MATCH.to_string());
127 // if the stack has more than one value, it means that the postfix
128 // expression is not complete - so display the stack status
129 return Err (ERR_POSTFIX_INCOMPLETE.to_string());
131 // stack has only one item which is the result so display it
132 let res = ops[0].value;
139 let args : Vec<String> = env::args().collect ();
140 // regular expression to match a number
141 let match_num = Regex::new (r"^\d+?\.*?\d*?$").unwrap ();
144 // if arguments are provided run in command line mode - i.e. print the
146 let mut expr = String::new ();
148 // create the expression string to evaluate
149 for arg in args.iter() {
151 expr.push_str (&arg);
156 // evaluate the result
157 let res = evaluate (&expr, &match_num);
158 // if Result is OK then print the result in green
160 let restxt = format! ("{}: {}", RESULT,
162 println! ("{}", Colour::Green.paint (restxt));
164 // print the error in purple
165 let errtxt = format! ("{}: {}", ERROR,
167 eprintln! ("{}", Colour::Purple.paint (errtxt));
171 // if arguments are not provided run in interactive mode -
172 // display a prompt and get the expression
173 // repeat until the user quits
175 // get a line from input and evaluate it
176 let mut expr = String::new ();
178 // loop until a blank line is received
181 print!("{}", Style::new().bold().paint("evpf>"));
182 io::stdout().flush ().expect (ERR_FLUSHING);
183 // read a line of text
184 io::stdin().read_line (&mut expr).expect (ERR_READING_LINE);
186 let expr = expr.trim ();
188 if expr == "q" || expr == "Q" {
189 // quit if the expression is q or Qs
191 } else if expr == "?" || expr == "h" || expr == "H" {
193 for text in HELP_TEXT.iter() {
194 println! ("{}", Colour::Cyan.paint(*text));
198 } else if expr == "" {
199 // continue without proceeding
204 let res = evaluate (&expr, &match_num);
206 // if Result is OK then print the result in green
208 let restxt = format! ("{}: {}", RESULT,
210 println! ("{}", Colour::Green.paint (restxt));
212 // print the error in purple
213 let errtxt = format! ("{}: {}", ERROR,
215 eprintln! ("{}", Colour::Purple.paint (errtxt));
216 eprintln! ("{}", Colour::Purple.paint (ERROR_HELP));