aboutsummaryrefslogtreecommitdiff
path: root/src/parse.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse.rs')
-rw-r--r--src/parse.rs105
1 files changed, 105 insertions, 0 deletions
diff --git a/src/parse.rs b/src/parse.rs
new file mode 100644
index 0000000..aa8bd4b
--- /dev/null
+++ b/src/parse.rs
@@ -0,0 +1,105 @@
1/* Copyright (C) 2019 Akshay Oppiliappan <[email protected]>
2 * Refer to LICENCE for more information.
3 * */
4
5use crate::error::CalcError;
6use crate::lex::Token;
7
8pub fn to_postfix(tokens: Vec<Token>) -> Result<Vec<Token>, CalcError> {
9 let mut postfixed: Vec<Token> = vec![];
10 let mut op_stack: Vec<Token> = vec![];
11 for token in tokens {
12 match token {
13 Token::Num(_) => {
14 postfixed.push(token);
15 }
16 Token::Function(_) => {
17 op_stack.push(token);
18 }
19 Token::Operator(current_op) => {
20 while let Some(top_op) = op_stack.last() {
21 match top_op {
22 Token::LParen => {
23 break;
24 }
25 Token::Operator(x) => {
26 let tp = x.precedence;
27 let cp = current_op.precedence;
28 if tp > cp || (tp == cp && x.is_left_associative) {
29 postfixed.push(op_stack.pop().unwrap());
30 } else {
31 break;
32 }
33 }
34 Token::Function(_) => {
35 postfixed.push(op_stack.pop().unwrap());
36 }
37 _ => {
38 unreachable!();
39 }
40 }
41 }
42 op_stack.push(token);
43 }
44 Token::LParen => {
45 op_stack.push(token);
46 }
47 Token::RParen => {
48 let mut push_until_paren: bool = false;
49 while let Some(token) = op_stack.pop() {
50 if token == Token::LParen {
51 push_until_paren = true;
52 break;
53 }
54 postfixed.push(token)
55 }
56 if !push_until_paren {
57 return Err(CalcError::Syntax("Mismatched parentheses!".into()));
58 }
59 }
60 }
61 }
62 while let Some(op) = op_stack.pop() {
63 postfixed.push(op);
64 }
65 Ok(postfixed)
66}
67
68pub fn eval_postfix(postfixed: Vec<Token>) -> Result<f64, CalcError> {
69 let mut num_stack: Vec<f64> = vec![];
70 for token in postfixed {
71 match token {
72 Token::Num(n) => {
73 num_stack.push(n);
74 }
75 Token::Operator(op) => {
76 if let Some(n2) = num_stack.pop() {
77 if let Some(n1) = num_stack.pop() {
78 num_stack.push(op.operate(n1, n2)?);
79 } else {
80 return Err(CalcError::Parser(
81 "Too many operators, Too little operands".to_string(),
82 ));
83 }
84 } else {
85 return Err(CalcError::Parser(
86 "Too many operators, Too little operands".to_string(),
87 ));
88 }
89 }
90 Token::Function(funct) => {
91 if let Some(arg) = num_stack.pop() {
92 num_stack.push(funct.apply(arg)?)
93 }
94 }
95 _ => unreachable!("wut"),
96 }
97 }
98 if num_stack.len() == 1 {
99 Ok(num_stack.pop().unwrap())
100 } else {
101 Err(CalcError::Parser(
102 "Too many operators, Too little operands".to_string(),
103 ))
104 }
105}