diff options
author | NerdyPepper <[email protected]> | 2019-03-21 05:24:29 +0000 |
---|---|---|
committer | NerdyPepper <[email protected]> | 2019-03-21 05:24:29 +0000 |
commit | a050178c692c59861cb0fb9666321fbef7578039 (patch) | |
tree | 9747261773daa52075fe4befa841e0c261eecc1e /src | |
parent | 38c23d8102ffcdc7763da51a17fbc39296e127c7 (diff) |
refactor into modules
Diffstat (limited to 'src')
-rw-r--r-- | src/lex/mod.rs | 145 | ||||
-rw-r--r-- | src/main.rs | 241 | ||||
-rw-r--r-- | src/parse/mod.rs | 96 |
3 files changed, 247 insertions, 235 deletions
diff --git a/src/lex/mod.rs b/src/lex/mod.rs new file mode 100644 index 0000000..af5ff06 --- /dev/null +++ b/src/lex/mod.rs | |||
@@ -0,0 +1,145 @@ | |||
1 | use std::f64; | ||
2 | #[derive(Debug, Copy, Clone, PartialEq)] | ||
3 | pub struct Operator { | ||
4 | token: char, | ||
5 | pub operation: fn(f64, f64) -> f64, | ||
6 | pub precedence: u8, | ||
7 | pub is_left_associative: bool, | ||
8 | } | ||
9 | |||
10 | impl Operator { | ||
11 | fn token_from_op(token: char, operation: fn(f64, f64) -> f64, precedence: u8, is_left_associative: bool) -> Token { | ||
12 | Token::Operator( | ||
13 | Operator { | ||
14 | token, | ||
15 | operation, | ||
16 | precedence, | ||
17 | is_left_associative | ||
18 | } | ||
19 | ) | ||
20 | } | ||
21 | pub fn operate(self, x: f64, y: f64) -> f64 { | ||
22 | (self.operation)(x, y) | ||
23 | } | ||
24 | } | ||
25 | |||
26 | #[derive(Debug, Clone, PartialEq)] | ||
27 | pub struct Function { | ||
28 | token: String, | ||
29 | relation: fn(f64) -> f64, | ||
30 | } | ||
31 | |||
32 | impl Function { | ||
33 | fn token_from_fn(token: String, relation: fn(f64) -> f64) -> Token { | ||
34 | Token::Function( | ||
35 | Function { | ||
36 | token, | ||
37 | relation | ||
38 | } | ||
39 | ) | ||
40 | } | ||
41 | pub fn apply(self, arg: f64) -> f64 { | ||
42 | (self.relation)(arg) | ||
43 | } | ||
44 | } | ||
45 | |||
46 | |||
47 | #[derive(Debug, Clone, PartialEq)] | ||
48 | pub enum Token { | ||
49 | Operator(Operator), | ||
50 | Num(f64), | ||
51 | Function(Function), | ||
52 | LParen, | ||
53 | RParen | ||
54 | } | ||
55 | |||
56 | pub fn lexer(input: &str) -> Result<Vec<Token>, String> { | ||
57 | let mut num_vec: String = String::new(); | ||
58 | let mut char_vec: String = String::new(); | ||
59 | let mut result: Vec<Token> = vec![]; | ||
60 | for letter in input.chars() { | ||
61 | match letter { | ||
62 | '0'...'9' | '.' => { | ||
63 | num_vec.push(letter); | ||
64 | }, | ||
65 | 'a'...'z' | 'A'...'Z' => { | ||
66 | let parse_num = num_vec.parse::<f64>().ok(); | ||
67 | if let Some(x) = parse_num { | ||
68 | result.push(Token::Num(x)); | ||
69 | result.push(Operator::token_from_op('*', |x, y| x * y, 3, true)); | ||
70 | num_vec.clear(); | ||
71 | } | ||
72 | char_vec.push(letter); | ||
73 | }, | ||
74 | '+' | '-' | '/' | '*' | '^' => { | ||
75 | let parse_num = num_vec.parse::<f64>().ok(); | ||
76 | if let Some(x) = parse_num { | ||
77 | result.push(Token::Num(x)); | ||
78 | num_vec.clear(); | ||
79 | } | ||
80 | let operator_token: Token = match letter { | ||
81 | '+' => Operator::token_from_op('+', |x, y| x + y, 2, true), | ||
82 | '-' => Operator::token_from_op('-', |x, y| x - y, 2, true), | ||
83 | '/' => Operator::token_from_op('/', |x, y| x / y, 3, true), | ||
84 | '*' => Operator::token_from_op('*', |x, y| x * y, 3, true), | ||
85 | '^' => Operator::token_from_op('^', |x, y| x.powf(y), 4, false), | ||
86 | _ => panic!("unexpected op whuuu"), | ||
87 | }; | ||
88 | result.push(operator_token); | ||
89 | }, | ||
90 | '(' => { | ||
91 | if char_vec.len() > 0 { | ||
92 | let funct = char_vec.clone(); | ||
93 | match &funct[..] { | ||
94 | "sin" | "sine" => result.push(Function::token_from_fn("sin".into(), |x| x.to_radians().sin())), | ||
95 | "cos" | "cosine" => result.push(Function::token_from_fn("cos".into(), |x| x.to_radians().cos())), | ||
96 | "tan" | "tangent" => result.push(Function::token_from_fn("tan".into(), |x| x.to_radians().tan())), | ||
97 | "csc" | "cosec" => result.push(Function::token_from_fn("csc".into(), |x| 1f64 / x.to_radians().sin())), | ||
98 | "sec" | "secant" => result.push(Function::token_from_fn("sec".into(), |x| 1f64 / x.to_radians().cos())), | ||
99 | "cot" | "cotangent" => result.push(Function::token_from_fn("cot".into(), |x| 1f64 / x.to_radians().tan())), | ||
100 | "ln" => result.push(Function::token_from_fn("ln".into(), |x| x.ln())), | ||
101 | "log" => result.push(Function::token_from_fn("log".into(), |x| x.log10())), | ||
102 | "sqrt" => result.push(Function::token_from_fn("sqrt".into(), |x| x.sqrt())), | ||
103 | _ => return Err(format!("Unexpected function {}", funct)) | ||
104 | } | ||
105 | char_vec.clear(); | ||
106 | } else { | ||
107 | let parse_num = num_vec.parse::<f64>().ok(); | ||
108 | if let Some(x) = parse_num { | ||
109 | result.push(Token::Num(x)); | ||
110 | result.push(Operator::token_from_op('*', |x, y| x * y, 3, true)); | ||
111 | num_vec.clear(); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | if let Some(x) = result.last() { | ||
116 | match x { | ||
117 | Token::RParen => { | ||
118 | result.push(Operator::token_from_op('*', |x, y| x * y, 3, true)); | ||
119 | }, | ||
120 | _ => {} | ||
121 | }; | ||
122 | } | ||
123 | result.push(Token::LParen); | ||
124 | }, | ||
125 | ')' => { | ||
126 | let parse_num = num_vec.parse::<f64>().ok(); | ||
127 | if let Some(x) = parse_num { | ||
128 | result.push(Token::Num(x)); | ||
129 | num_vec.clear(); | ||
130 | } | ||
131 | result.push(Token::RParen); | ||
132 | } | ||
133 | ' ' => {} | ||
134 | _ => { | ||
135 | return Err(format!("Unexpected character: {}", letter)) | ||
136 | } | ||
137 | } | ||
138 | } | ||
139 | let parse_num = num_vec.parse::<f64>().ok(); | ||
140 | if let Some(x) = parse_num { | ||
141 | result.push(Token::Num(x)); | ||
142 | num_vec.clear(); | ||
143 | } | ||
144 | Ok(result) | ||
145 | } | ||
diff --git a/src/main.rs b/src/main.rs index 71251e2..63d0eb2 100644 --- a/src/main.rs +++ b/src/main.rs | |||
@@ -1,57 +1,11 @@ | |||
1 | use std::io::{ stdin }; | ||
1 | use std::f64; | 2 | use std::f64; |
2 | 3 | ||
3 | #[derive(Debug, Copy, Clone, PartialEq)] | 4 | mod lex; |
4 | pub struct Operator { | 5 | use crate::lex::*; |
5 | token: char, | ||
6 | operation: fn(f64, f64) -> f64, | ||
7 | precedence: u8, | ||
8 | is_left_associative: bool, | ||
9 | } | ||
10 | |||
11 | #[derive(Debug, Clone, PartialEq)] | ||
12 | pub struct Function { | ||
13 | token: String, | ||
14 | relation: fn(f64) -> f64, | ||
15 | } | ||
16 | |||
17 | #[derive(Debug, Clone, PartialEq)] | ||
18 | pub enum Token { | ||
19 | Operator(Operator), | ||
20 | Num(f64), | ||
21 | Function(Function), | ||
22 | LParen, | ||
23 | RParen | ||
24 | } | ||
25 | |||
26 | impl Operator { | ||
27 | fn token_from_op(token: char, operation: fn(f64, f64) -> f64, precedence: u8, is_left_associative: bool) -> Token { | ||
28 | Token::Operator( | ||
29 | Operator { | ||
30 | token, | ||
31 | operation, | ||
32 | precedence, | ||
33 | is_left_associative | ||
34 | } | ||
35 | ) | ||
36 | } | ||
37 | fn operate(self, x: f64, y: f64) -> f64 { | ||
38 | (self.operation)(x, y) | ||
39 | } | ||
40 | } | ||
41 | 6 | ||
42 | impl Function { | 7 | mod parse; |
43 | fn token_from_fn(token: String, relation: fn(f64) -> f64) -> Token { | 8 | use crate::parse::*; |
44 | Token::Function( | ||
45 | Function { | ||
46 | token, | ||
47 | relation | ||
48 | } | ||
49 | ) | ||
50 | } | ||
51 | fn apply(self, arg: f64) -> f64 { | ||
52 | (self.relation)(arg) | ||
53 | } | ||
54 | } | ||
55 | 9 | ||
56 | fn main() { | 10 | fn main() { |
57 | loop { | 11 | loop { |
@@ -69,191 +23,8 @@ fn main() { | |||
69 | let postfixed = to_postfix(lexed.unwrap()); | 23 | let postfixed = to_postfix(lexed.unwrap()); |
70 | let evaled = eval_postfix(postfixed.unwrap()); | 24 | let evaled = eval_postfix(postfixed.unwrap()); |
71 | println!("ans: {}", evaled.unwrap()); | 25 | println!("ans: {}", evaled.unwrap()); |
26 | println!(); | ||
72 | } | 27 | } |
73 | } | 28 | } |
74 | 29 | ||
75 | fn lexer(input: &str) -> Result<Vec<Token>, String> { | ||
76 | let mut num_vec: String = String::new(); | ||
77 | let mut char_vec: String = String::new(); | ||
78 | let mut result: Vec<Token> = vec![]; | ||
79 | for letter in input.chars() { | ||
80 | match letter { | ||
81 | '0'...'9' | '.' => { | ||
82 | num_vec.push(letter); | ||
83 | }, | ||
84 | 'a'...'z' | 'A'...'Z' => { | ||
85 | let parse_num = num_vec.parse::<f64>().ok(); | ||
86 | if let Some(x) = parse_num { | ||
87 | result.push(Token::Num(x)); | ||
88 | result.push(Operator::token_from_op('*', |x, y| x * y, 3, true)); | ||
89 | num_vec.clear(); | ||
90 | } | ||
91 | char_vec.push(letter); | ||
92 | }, | ||
93 | '+' | '-' | '/' | '*' | '^' => { | ||
94 | let parse_num = num_vec.parse::<f64>().ok(); | ||
95 | if let Some(x) = parse_num { | ||
96 | result.push(Token::Num(x)); | ||
97 | num_vec.clear(); | ||
98 | } | ||
99 | let operator_token: Token = match letter { | ||
100 | '+' => Operator::token_from_op('+', |x, y| x + y, 2, true), | ||
101 | '-' => Operator::token_from_op('-', |x, y| x - y, 2, true), | ||
102 | '/' => Operator::token_from_op('/', |x, y| x / y, 3, true), | ||
103 | '*' => Operator::token_from_op('*', |x, y| x * y, 3, true), | ||
104 | '^' => Operator::token_from_op('^', |x, y| x.powf(y), 4, false), | ||
105 | _ => panic!("unexpected op whuuu"), | ||
106 | }; | ||
107 | result.push(operator_token); | ||
108 | }, | ||
109 | '(' => { | ||
110 | if char_vec.len() > 0 { | ||
111 | let funct = char_vec.clone(); | ||
112 | match &funct[..] { | ||
113 | "sin" | "sine" => result.push(Function::token_from_fn("sin".into(), |x| x.to_radians().sin())), | ||
114 | "cos" | "cosine" => result.push(Function::token_from_fn("cos".into(), |x| x.to_radians().cos())), | ||
115 | "tan" | "tangent" => result.push(Function::token_from_fn("tan".into(), |x| x.to_radians().tan())), | ||
116 | "csc" | "cosec" => result.push(Function::token_from_fn("csc".into(), |x| 1f64 / x.to_radians().sin())), | ||
117 | "sec" | "secant" => result.push(Function::token_from_fn("sec".into(), |x| 1f64 / x.to_radians().cos())), | ||
118 | "cot" | "cotangent" => result.push(Function::token_from_fn("cot".into(), |x| 1f64 / x.to_radians().tan())), | ||
119 | "ln" => result.push(Function::token_from_fn("ln".into(), |x| x.ln())), | ||
120 | "log" => result.push(Function::token_from_fn("log".into(), |x| x.log10())), | ||
121 | _ => {} | ||
122 | } | ||
123 | char_vec.clear(); | ||
124 | } else { | ||
125 | let parse_num = num_vec.parse::<f64>().ok(); | ||
126 | if let Some(x) = parse_num { | ||
127 | result.push(Token::Num(x)); | ||
128 | result.push(Operator::token_from_op('*', |x, y| x * y, 3, true)); | ||
129 | num_vec.clear(); | ||
130 | } | ||
131 | } | ||
132 | 30 | ||
133 | if let Some(x) = result.last() { | ||
134 | match x { | ||
135 | Token::RParen => { | ||
136 | result.push(Operator::token_from_op('*', |x, y| x * y, 3, true)); | ||
137 | }, | ||
138 | _ => {} | ||
139 | }; | ||
140 | } | ||
141 | result.push(Token::LParen); | ||
142 | }, | ||
143 | ')' => { | ||
144 | let parse_num = num_vec.parse::<f64>().ok(); | ||
145 | if let Some(x) = parse_num { | ||
146 | result.push(Token::Num(x)); | ||
147 | num_vec.clear(); | ||
148 | } | ||
149 | result.push(Token::RParen); | ||
150 | } | ||
151 | ' ' => {} | ||
152 | _ => { | ||
153 | return Err(format!("Unexpected character: {}", letter)) | ||
154 | } | ||
155 | } | ||
156 | } | ||
157 | let parse_num = num_vec.parse::<f64>().ok(); | ||
158 | if let Some(x) = parse_num { | ||
159 | result.push(Token::Num(x)); | ||
160 | num_vec.clear(); | ||
161 | } | ||
162 | Ok(result) | ||
163 | } | ||
164 | |||
165 | fn to_postfix(tokens: Vec<Token>) -> Result<Vec<Token>, String> { | ||
166 | let mut postfixed: Vec<Token> = vec![]; | ||
167 | let mut op_stack: Vec<Token> = vec![]; | ||
168 | for token in tokens { | ||
169 | match token { | ||
170 | Token::Num(_) => { | ||
171 | postfixed.push(token); | ||
172 | }, | ||
173 | Token::Function(_) => { | ||
174 | op_stack.push(token); | ||
175 | } | ||
176 | Token::Operator(current_op) => { | ||
177 | while let Some(top_op) = op_stack.last() { | ||
178 | match top_op { | ||
179 | Token::LParen => { | ||
180 | break; | ||
181 | } | ||
182 | Token::Operator(x) => { | ||
183 | let tp = x.precedence; | ||
184 | let cp = current_op.precedence; | ||
185 | if tp > cp || (tp == cp && x.is_left_associative) { | ||
186 | postfixed.push(op_stack.pop().unwrap()); | ||
187 | } else { | ||
188 | break; | ||
189 | } | ||
190 | } | ||
191 | Token::Function(_) => { | ||
192 | postfixed.push(op_stack.pop().unwrap()); | ||
193 | } | ||
194 | _ => { | ||
195 | return Err(format!("{:?} must not be on operator stack", top_op)) | ||
196 | } | ||
197 | } | ||
198 | } | ||
199 | op_stack.push(token); | ||
200 | }, | ||
201 | Token::LParen => { | ||
202 | op_stack.push(token); | ||
203 | }, | ||
204 | Token::RParen => { | ||
205 | let mut push_until_paren: bool = false; | ||
206 | while let Some(token) = op_stack.pop() { | ||
207 | if token == Token::LParen { | ||
208 | push_until_paren = true; | ||
209 | break; | ||
210 | } | ||
211 | postfixed.push(token) | ||
212 | } | ||
213 | if !push_until_paren { | ||
214 | return Err(String::from("Mismatched ')'")); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | } | ||
219 | } | ||
220 | while let Some(op) = op_stack.pop() { | ||
221 | postfixed.push(op); | ||
222 | } | ||
223 | Ok(postfixed) | ||
224 | } | ||
225 | |||
226 | fn eval_postfix(postfixed: Vec<Token>) -> Result<f64, String> { | ||
227 | let mut num_stack: Vec<f64> = vec![]; | ||
228 | for token in postfixed { | ||
229 | match token { | ||
230 | Token::Num(n) => { | ||
231 | num_stack.push(n); | ||
232 | }, | ||
233 | Token::Operator(op) => { | ||
234 | if let Some(n2) = num_stack.pop() { | ||
235 | if let Some(n1) = num_stack.pop() { | ||
236 | num_stack.push(op.operate(n1, n2)) | ||
237 | } else { | ||
238 | return Err(format!("Too many operators, Too little operands")) | ||
239 | } | ||
240 | } else { | ||
241 | return Err(format!("Too many operators, Too little operands")) | ||
242 | } | ||
243 | }, | ||
244 | Token::Function(funct) => { | ||
245 | if let Some(arg) = num_stack.pop() { | ||
246 | num_stack.push(funct.apply(arg)) | ||
247 | } | ||
248 | } | ||
249 | _ => { | ||
250 | return Err(format!("Yo nibba how did this get here")) | ||
251 | } | ||
252 | } | ||
253 | } | ||
254 | if num_stack.len() == 1 { | ||
255 | Ok(num_stack.pop().unwrap()) | ||
256 | } else { | ||
257 | Err(format!("Parser Error")) | ||
258 | } | ||
259 | } | ||
diff --git a/src/parse/mod.rs b/src/parse/mod.rs new file mode 100644 index 0000000..e5c28e6 --- /dev/null +++ b/src/parse/mod.rs | |||
@@ -0,0 +1,96 @@ | |||
1 | use crate::lex::Token; | ||
2 | |||
3 | pub fn to_postfix(tokens: Vec<Token>) -> Result<Vec<Token>, String> { | ||
4 | let mut postfixed: Vec<Token> = vec![]; | ||
5 | let mut op_stack: Vec<Token> = vec![]; | ||
6 | for token in tokens { | ||
7 | match token { | ||
8 | Token::Num(_) => { | ||
9 | postfixed.push(token); | ||
10 | }, | ||
11 | Token::Function(_) => { | ||
12 | op_stack.push(token); | ||
13 | } | ||
14 | Token::Operator(current_op) => { | ||
15 | while let Some(top_op) = op_stack.last() { | ||
16 | match top_op { | ||
17 | Token::LParen => { | ||
18 | break; | ||
19 | } | ||
20 | Token::Operator(x) => { | ||
21 | let tp = x.precedence; | ||
22 | let cp = current_op.precedence; | ||
23 | if tp > cp || (tp == cp && x.is_left_associative) { | ||
24 | postfixed.push(op_stack.pop().unwrap()); | ||
25 | } else { | ||
26 | break; | ||
27 | } | ||
28 | } | ||
29 | Token::Function(_) => { | ||
30 | postfixed.push(op_stack.pop().unwrap()); | ||
31 | } | ||
32 | _ => { | ||
33 | return Err(format!("{:?} must not be on operator stack", top_op)) | ||
34 | } | ||
35 | } | ||
36 | } | ||
37 | op_stack.push(token); | ||
38 | }, | ||
39 | Token::LParen => { | ||
40 | op_stack.push(token); | ||
41 | }, | ||
42 | Token::RParen => { | ||
43 | let mut push_until_paren: bool = false; | ||
44 | while let Some(token) = op_stack.pop() { | ||
45 | if token == Token::LParen { | ||
46 | push_until_paren = true; | ||
47 | break; | ||
48 | } | ||
49 | postfixed.push(token) | ||
50 | } | ||
51 | if !push_until_paren { | ||
52 | return Err(String::from("Mismatched ')'")); | ||
53 | } | ||
54 | } | ||
55 | } | ||
56 | } | ||
57 | while let Some(op) = op_stack.pop() { | ||
58 | postfixed.push(op); | ||
59 | } | ||
60 | Ok(postfixed) | ||
61 | } | ||
62 | |||
63 | pub fn eval_postfix(postfixed: Vec<Token>) -> Result<f64, String> { | ||
64 | let mut num_stack: Vec<f64> = vec![]; | ||
65 | for token in postfixed { | ||
66 | match token { | ||
67 | Token::Num(n) => { | ||
68 | num_stack.push(n); | ||
69 | }, | ||
70 | Token::Operator(op) => { | ||
71 | if let Some(n2) = num_stack.pop() { | ||
72 | if let Some(n1) = num_stack.pop() { | ||
73 | num_stack.push(op.operate(n1, n2)) | ||
74 | } else { | ||
75 | return Err(format!("Too many operators, Too little operands")) | ||
76 | } | ||
77 | } else { | ||
78 | return Err(format!("Too many operators, Too little operands")) | ||
79 | } | ||
80 | }, | ||
81 | Token::Function(funct) => { | ||
82 | if let Some(arg) = num_stack.pop() { | ||
83 | num_stack.push(funct.apply(arg)) | ||
84 | } | ||
85 | } | ||
86 | _ => { | ||
87 | return Err(format!("Yo nibba how did this get here")) | ||
88 | } | ||
89 | } | ||
90 | } | ||
91 | if num_stack.len() == 1 { | ||
92 | Ok(num_stack.pop().unwrap()) | ||
93 | } else { | ||
94 | Err(format!("Parser Error")) | ||
95 | } | ||
96 | } | ||