kyj_rpn_calc/
lib.rs

1// 설명 작성 --- (*1)
2//! # RPN Calc
3//! Reverse Polish notation (RPN) Calc.
4//! # Example
5//! ```
6//! let src = String::from("1 2 + 3 * ");
7//! let a = rust_lib::eval(src).unwrap();
8//! println!("{}", a); // →9
9//! ```
10
11pub fn eval(src: String) -> Result<f64, String> {
12    // 인수를 공백으로 구분
13    let tokens = src.split_whitespace();
14    let mut stack: Vec<f64> = vec![];
15    // 반복문으로 요소를 계산 --- (*2)
16    for tok in tokens {
17        let t = tok.trim();
18        if t == "" {
19            continue;
20        }
21        // 숫자 값이라면 스택에 PUSH
22        match t.parse::<f64>() {
23            Ok(v) => {
24                stack.push(v);
25                continue;
26            }
27            Err(_) => 0.0,
28        };
29        // 연산자라면 2번 POP 한 뒤 계산 결과를 PUSH
30        let b = stack.pop().unwrap_or(0.0);
31        let a = stack.pop().unwrap_or(0.0);
32        match t {
33            "+" => stack.push(a + b),
34            "-" => stack.push(a - b),
35            "*" => stack.push(a * b),
36            "/" => stack.push(a / b),
37            "%" => stack.push(a % b),
38            _ => return Err(format!("invalid operator: {}", t)),
39        }
40    }
41    // 결과 반환 --- (*3)
42    if stack.len() == 0 {
43        return Err(format!("no result"));
44    }
45    if stack.len() > 1 {
46        return Err(format!("too many value in stack"));
47    }
48    Ok(stack.pop().unwrap_or(0.0))
49}
50
51// 테스트 --- (*4)
52#[cfg(test)]
53mod tests {
54    use super::*;
55    #[test]
56    fn it_works() {
57        assert_eq!(eval("1 3 +".to_string()), Ok(4.0));
58        assert_eq!(eval("2 3 *".to_string()), Ok(6.0));
59        assert_eq!(eval("6 3 /".to_string()), Ok(2.0));
60        assert_eq!(eval("6 3 - 1 -".to_string()), Ok(2.0));
61    }
62}