├── .gitignore ├── Cargo.toml ├── Cargo.lock └── src ├── tests.rs └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mini-parser" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "mini-parser" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /src/tests.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | use crate::Expression; 3 | 4 | #[test] 5 | fn test_1(){ 6 | let s = Expression::from_str("1"); 7 | assert_eq!(s.to_string(), "1"); 8 | } 9 | 10 | #[test] 11 | fn test_2(){ 12 | let s = Expression::from_str("1 + 2 * 3"); 13 | assert_eq!(s.to_string(), "(+ 1 (* 2 3))") 14 | } 15 | 16 | #[test] 17 | fn test_3(){ 18 | let s = Expression::from_str("a * 2 * b"); 19 | assert_eq!(s.to_string(), "(* (* a 2) b)") 20 | } 21 | 22 | #[test] 23 | fn test_4(){ 24 | let s = Expression::from_str("a + b * 2 * c + a / 4"); 25 | assert_eq!(s.to_string(), "(+ (+ a (* (* b 2) c)) (/ a 4))"); 26 | } 27 | 28 | 29 | #[test] 30 | fn test_5(){ 31 | let s = Expression::from_str("2 + b * 5 - 3 / 5 + 5 -3"); 32 | assert_eq!(s.to_string(), "(- (+ (- (+ 2 (* b 5)) (/ 3 5)) 5) 3)"); 33 | } 34 | 35 | 36 | #[test] 37 | fn test_6(){ 38 | let s = Expression::from_str("(2 + b) * 5 "); 39 | assert_eq!(s.to_string(), "(* (+ 2 b) 5)"); 40 | } 41 | 42 | #[test] 43 | fn test_7(){ 44 | let s = Expression::from_str("(((a)))"); 45 | assert_eq!(s.to_string(), "a"); 46 | } 47 | 48 | /* 49 | #[test] 50 | fn test_8(){ 51 | let s = Expression::from_str("a + b * 2 * (c + a) / 4"); 52 | assert_eq!(s.to_string(), "(+ a (/ (* (* b 2) (+ c a)) 4))"); 53 | } 54 | 55 | 56 | #[test] 57 | fn test_9(){ 58 | let s = Expression::from_str("a + b * c ^ 4"); 59 | println!("{}", s.to_string()); 60 | assert_eq!(s.to_string(), "(+ a (* b (^ c 4)))"); 61 | } 62 | 63 | #[test] 64 | fn test_10(){ 65 | let s = Expression::from_str("a + 2 √ 4 * b"); 66 | println!("{}", s.to_string()); 67 | assert_eq!(s.to_string(), "(+ a (* (√ 2 4) b))"); 68 | } 69 | 70 | #[test] 71 | fn test_11(){ 72 | let s = Expression::from_str("a + 2 √ (4 * b)"); 73 | println!("{}", s.to_string()); 74 | assert_eq!(s.to_string(), "(+ a (√ 2 (* 4 b)))"); 75 | } 76 | 77 | #[test] 78 | fn test_12(){ 79 | let s = Expression::from_str("a ^ b ^ 2"); 80 | println!("{}", s.to_string()); 81 | assert_eq!(s.to_string(), "(^ a (^ b 2))"); 82 | } 83 | 84 | 85 | #[test] 86 | fn test_13(){ 87 | let s = Expression::from_str("a.b.c.d"); 88 | println!("{}", s.to_string()); 89 | assert_eq!(s.to_string(), "(. (. (. a b) c) d)"); 90 | }*/ -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::HashMap, fmt, io::{self, Write}}; 2 | pub mod tests; 3 | 4 | fn main() { 5 | let mut variables: HashMap = HashMap::new(); 6 | loop{ 7 | print!(">> "); 8 | io::stdout().flush().unwrap(); 9 | let input = { 10 | let mut buf = String::new(); 11 | std::io::stdin().read_line(&mut buf).unwrap(); 12 | buf 13 | }; 14 | if input.trim() == "exit" { 15 | break; 16 | } 17 | let expr = Expression::from_str(&input); 18 | if let Some((var_name, lhs)) = expr.is_asign(){ 19 | let value = lhs.eval(&variables); 20 | variables.insert(var_name, value); 21 | continue; 22 | } 23 | let value = expr.eval(&variables); 24 | println!("{}", value); 25 | } 26 | } 27 | 28 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 29 | enum Token { 30 | Atom(char), 31 | Op(char), 32 | Eof, 33 | } 34 | 35 | #[derive(Debug)] 36 | struct Lexer { 37 | tokens: Vec, 38 | } 39 | 40 | impl Lexer { 41 | fn new(input: &str) -> Lexer { 42 | let mut tokens = input 43 | .chars() 44 | .filter(|it| !it.is_ascii_whitespace()) 45 | .map(|c| match c { 46 | '0'..='9' | 'a'..='z' | 'A'..='Z' => Token::Atom(c), 47 | _ => Token::Op(c), 48 | }) 49 | .collect::>(); 50 | tokens.reverse(); 51 | Lexer { tokens } 52 | } 53 | 54 | fn next(&mut self) -> Token { 55 | self.tokens.pop().unwrap_or(Token::Eof) 56 | } 57 | 58 | fn peek(&mut self) -> Token { 59 | self.tokens.last().copied().unwrap_or(Token::Eof) 60 | } 61 | } 62 | 63 | #[derive(Clone)] 64 | enum Expression { 65 | Atom(char), 66 | Operation(char, Vec), 67 | } 68 | impl fmt::Display for Expression { 69 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 70 | match self { 71 | Expression::Atom(i) => write!(f, "{}", i), 72 | Expression::Operation(head, rest) => { 73 | write!(f, "({}", head)?; 74 | for s in rest { 75 | write!(f, " {}", s)? 76 | } 77 | write!(f, ")") 78 | } 79 | } 80 | } 81 | } 82 | 83 | impl Expression { 84 | fn from_str(input: &str) -> Expression { 85 | let mut lexer = Lexer::new(input); 86 | parse_expression(&mut lexer, 0.0) 87 | } 88 | #[allow(unused)] 89 | fn is_asign(&self) -> Option<(char, &Expression)>{ 90 | match self{ 91 | Expression::Atom(_) => return None, 92 | Expression::Operation(c, operands) => { 93 | if *c == '=' { 94 | let var_name = match operands.first().unwrap(){ 95 | Expression::Atom(c) => { 96 | if *c >= 'a' && *c <= 'z' || *c >= 'A' && *c <= 'Z' { 97 | *c 98 | }else { 99 | panic!("Not a variable name: {}", c) 100 | } 101 | } 102 | _ => unreachable!() 103 | }; 104 | return Some((var_name, operands.last().unwrap())); 105 | } 106 | return None; 107 | } 108 | } 109 | } 110 | #[allow(unused)] 111 | fn eval(&self, variables: &HashMap) -> f32{ 112 | match self{ 113 | Expression::Atom(c) => { 114 | match c { 115 | '0'..='9' => return c.to_digit(10).unwrap() as f32, 116 | 'a'..='z' | 'A'..='Z' => { 117 | *variables.get(c).expect(&format!("Undefined variable {}", c)) 118 | }, 119 | _ => unreachable!() 120 | } 121 | } 122 | Expression::Operation(operator, operands) => { 123 | let lhs = operands.first().unwrap().eval(variables); 124 | let rhs = operands.last().unwrap().eval(variables); 125 | match operator{ 126 | '+' => return lhs + rhs, 127 | '-' => return lhs - rhs, 128 | '*' => return lhs * rhs, 129 | '/' => return lhs / rhs, 130 | '^' => return lhs.powf(rhs), 131 | '√' => return lhs.powf(1.0/(rhs)), 132 | op => panic!("Bad operator: {}", op) 133 | } 134 | }, 135 | } 136 | } 137 | } 138 | 139 | fn parse_expression(lexer: &mut Lexer, min_bp: f32) -> Expression { 140 | let mut lhs = match lexer.next() { 141 | Token::Atom(it) => Expression::Atom(it), 142 | Token::Op('(') => { 143 | let lhs = parse_expression(lexer, 0.0); 144 | assert_eq!(lexer.next(), Token::Op(')')); 145 | lhs 146 | } 147 | t => panic!("bad token: {:?}", t), 148 | }; 149 | loop { 150 | let op = match lexer.peek() { 151 | Token::Eof => break, 152 | Token::Op(')') => break, 153 | Token::Op(op) => op, 154 | t => panic!("bad token: {:?}", t), 155 | }; 156 | //My mistake: DO NOT call `lexer.next()` here 157 | let (l_bp, r_bp) = infix_binding_power(op); 158 | if l_bp < min_bp { 159 | break; 160 | } 161 | //In the video, `lexer.next()` is called BEFORE the if statement. 162 | //It must be called AFTER the precedence check, because calling it too early 163 | //would consume a token that shouldn't be parsed yet—leading to incorrect parse trees. 164 | lexer.next(); 165 | let rhs = parse_expression(lexer, r_bp); 166 | lhs = Expression::Operation(op, vec![lhs, rhs]); 167 | } 168 | lhs 169 | } 170 | 171 | fn infix_binding_power(op: char) -> (f32, f32) { 172 | match op { 173 | '=' => (0.2, 0.1), 174 | '+' | '-' => (1.0, 1.1), 175 | '*' | '/' => (2.0, 2.1), 176 | '^' | '√' => (3.1, 3.0), 177 | '.' => (4.0, 4.1), 178 | _ => panic!("bad op: {:?}", op), 179 | } 180 | } 181 | --------------------------------------------------------------------------------