aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNerdyPepper <[email protected]>2019-03-21 05:24:29 +0000
committerNerdyPepper <[email protected]>2019-03-21 05:24:29 +0000
commita050178c692c59861cb0fb9666321fbef7578039 (patch)
tree9747261773daa52075fe4befa841e0c261eecc1e
parent38c23d8102ffcdc7763da51a17fbc39296e127c7 (diff)
refactor into modules
-rw-r--r--src/lex/mod.rs145
-rw-r--r--src/main.rs241
-rw-r--r--src/parse/mod.rs96
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 @@
1use std::f64;
2#[derive(Debug, Copy, Clone, PartialEq)]
3pub struct Operator {
4 token: char,
5 pub operation: fn(f64, f64) -> f64,
6 pub precedence: u8,
7 pub is_left_associative: bool,
8}
9
10impl 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)]
27pub struct Function {
28 token: String,
29 relation: fn(f64) -> f64,
30}
31
32impl 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)]
48pub enum Token {
49 Operator(Operator),
50 Num(f64),
51 Function(Function),
52 LParen,
53 RParen
54}
55
56pub 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 @@
1use std::io::{ stdin };
1use std::f64; 2use std::f64;
2 3
3#[derive(Debug, Copy, Clone, PartialEq)] 4mod lex;
4pub struct Operator { 5use 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)]
12pub struct Function {
13 token: String,
14 relation: fn(f64) -> f64,
15}
16
17#[derive(Debug, Clone, PartialEq)]
18pub enum Token {
19 Operator(Operator),
20 Num(f64),
21 Function(Function),
22 LParen,
23 RParen
24}
25
26impl 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
42impl Function { 7mod parse;
43 fn token_from_fn(token: String, relation: fn(f64) -> f64) -> Token { 8use 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
56fn main() { 10fn 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
75fn 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
165fn 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
226fn 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 @@
1use crate::lex::Token;
2
3pub 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
63pub 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}