-
Notifications
You must be signed in to change notification settings - Fork 7
/
rpn.rl
112 lines (100 loc) · 2.72 KB
/
rpn.rl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// -*-rust-*-
//
// Reverse Polish Notation Calculator
// Copyright (c) 2010 J.A. Roberts Tunney
// MIT License
//
// To compile:
//
// ragel --host-lang=rust -o rpn.rs rpn.rl
// rust -o rpn rpn.rs
// ./rpn
//
// To show a diagram of your state machine:
//
// ragel -V -p -o rpn.dot rpn.rl
// dot -Tpng -o rpn.png rpn.dot
// chrome rpn.png
//
%% machine rpn;
%% write data;
fn rpn(data: &str) -> Result<int, ~str> {
let mut cs: int;
let mut p = 0;
let pe = data.len();
let mut mark = 0;
let mut st = ~[];
%%{
action mark { mark = p; }
action push {
let s = data.slice(mark, p);
match from_str::<int>(s) {
None => return Err(format!("invalid integer {}", s)),
Some(i) => st.push(i),
}
}
action add { let y = st.pop().unwrap(); let x = st.pop().unwrap(); st.push(x + y); }
action sub { let y = st.pop().unwrap(); let x = st.pop().unwrap(); st.push(x - y); }
action mul { let y = st.pop().unwrap(); let x = st.pop().unwrap(); st.push(x * y); }
action div { let y = st.pop().unwrap(); let x = st.pop().unwrap(); st.push(x / y); }
action abs { let x = st.pop().unwrap(); st.push(x.abs()); }
action abba { st.push(666); }
stuff = digit+ >mark %push
| '+' @add
| '-' @sub
| '*' @mul
| '/' @div
| 'abs' %abs
| 'add' %add
| 'abba' %abba
;
main := ( space | stuff space )* ;
write init;
write exec;
}%%
if cs < rpn_first_final {
if p == pe {
Err(~"unexpected eof")
} else {
Err(format!("error at position {}", p))
}
} else if st.is_empty() {
Err(~"rpn stack empty on result")
} else {
Ok(st.pop().unwrap())
}
}
//////////////////////////////////////////////////////////////////////
#[test]
fn test_success() {
let rpnTests = [
(~"666\n", 666),
(~"666 111\n", 111),
(~"4 3 add\n", 7),
(~"4 3 +\n", 7),
(~"4 3 -\n", 1),
(~"4 3 *\n", 12),
(~"6 2 /\n", 3),
(~"0 3 -\n", -3),
(~"0 3 - abs\n", 3),
(~" 2 2 + 3 - \n", 1),
(~"10 7 3 2 * - +\n", 11),
(~"abba abba add\n", 1332),
];
for sx in rpnTests.iter() {
match *sx {
(ref s, x) => assert_eq!(rpn(*s).unwrap(), x),
}
}
}
#[test]
fn test_failure() {
let rpnFailTests = [
(~"\n", ~"rpn stack empty on result")
];
for sx in rpnFailTests.iter() {
match *sx {
(ref s, ref x) => assert_eq!(&rpn(*s).unwrap_err(), x),
}
}
}