leetcode/
parse_lisp.rs

1//! # 736. Lisp 语法解析
2//!
3//! 难度 困难
4//!
5//! 给定一个类似 Lisp 语句的表达式 expression,求出其计算结果。
6//!
7//! 表达式语法如下所示:
8//!
9//! * 表达式可以为整数,let 语法,add 语法,mult 语法,或赋值的变量。表达式的结果总是一个整数。
10//! * (整数可以是正整数、负整数、0)
11//! * **let** 语法表示为 `(let v1 e1 v2 e2 ... vn en expr)`, 其中 let语法总是以字符串 `"let"` 来表示,接下来会跟随一个或多个交替变量或表达式,也就是说,第一个变量 `v1` 被分配为表达式 `e1` 的值,第二个变量 `v2` 被分配为表达式 `e2` 的值,以此类推;最终 `let` 语法的值为 `expr` 表达式的值。
12//! * `add` 语法表示为 `(add e1 e2)`,其中 `add` 语法总是以字符串 `"add"` 来表示,该语法总是有两个表达式`e1`、`e2`, 该语法的最终结果是 `e1` 表达式的值与 `e2` 表达式的值之和。
13//! * `mult` 语法表示为 `(mult e1 e2)` ,其中 `mult` 语法总是以字符串 `"mult"` 表示, 该语法总是有两个表达式 `e1`、`e2`,该语法的最终结果是 `e1` 表达式的值与 `e2` 表达式的值之积。
14//! * 在该题目中,变量的命名以小写字符开始,之后跟随 `0` 个或多个小写字符或数字。为了方便,`"add"`,`"let"`,`"mult"` 会被定义为 "关键字",不会在表达式的变量命名中出现。
15//! * 最后,要说一下作用域的概念。计算变量名所对应的表达式时,在计算上下文中,首先检查最内层作用域(按括号计),然后按顺序依次检查外部作用域。我们将保证每一个测试的表达式都是合法的。有关作用域的更多详细信息,请参阅示例。
16//!
17//!
18//! ## 示例:
19//!
20//! ```text
21//! 输入: (add 1 2)
22//! 输出: 3
23//!
24//! 输入: (mult 3 (add 2 3))
25//! 输出: 15
26//!
27//! 输入: (let x 2 (mult x 5))
28//! 输出: 10
29//!
30//! 输入: (let x 2 (mult x (let x 3 y 4 (add x y))))
31//! 输出: 14
32//! 解释:
33//! 表达式 (add x y), 在获取 x 值时, 我们应当由最内层依次向外计算, 首先遇到了 x=3, 所以此处的 x 值是 3.
34//!
35//!
36//! 输入: (let x 3 x 2 x)
37//! 输出: 2
38//! 解释: let 语句中的赋值运算按顺序处理即可
39//!
40//! 输入: (let x 1 y 2 x (add x y) (add x y))
41//! 输出: 5
42//! 解释:
43//! 第一个 (add x y) 计算结果是 3,并且将此值赋给了 x 。
44//! 第二个 (add x y) 计算结果就是 3+2 = 5 。
45//!
46//! 输入: (let x 2 (add (let x 3 (let x 4 x)) x))
47//! 输出: 6
48//! 解释:
49//! (let x 4 x) 中的 x 的作用域仅在()之内。所以最终做加法操作时,x 的值是 2 。
50//!
51//! 输入: (let a1 3 b2 (add a1 1) b2)
52//! 输出: 4
53//! 解释:
54//! 变量命名时可以在第一个小写字母后跟随数字.
55//! ```
56//!
57//!
58//! ## 注意:
59//!
60//! * 我们给定的 `expression` 表达式都是格式化后的:表达式前后没有多余的空格,表达式的不同部分(关键字、变量、表达式)之间仅使用一个空格分割,并且在相邻括号之间也没有空格。我们给定的表达式均为合法的且最终结果为整数。
61//! * 我们给定的表达式长度最多为 2000 (表达式也不会为空,因为那不是一个合法的表达式)。
62//! * 最终的结果和中间的计算结果都将是一个 32 位整数。
63//!
64//! See [leetcode](https://leetcode-cn.com/problems/parse-lisp-expression/)
65//!
66
67use std::collections::{HashMap, HashSet};
68use std::iter::{Fuse, Peekable};
69
70/// 用 Rust 写代码,无法对错误视而不见。 只有在最后调用的时候假设输入都是合法的。
71///
72/// 代码看起来挺长,其实很简单,代码结构也很清晰。
73///
74/// 主要思路是递归,先 tokenize 输入,这里因为用了 [`Iterator`](Iterator) tokenize 返回的时候是没有遍历的。
75///
76/// lisp 语法规则很简单,直接看 `eval()`。
77///
78/// 主要逻辑在 `eval()` 里,很简单,就是处理 `let` 语句稍微需要注意下,进入 `eval_let()` 之前需要入栈,`eval_let()` 返回后需要出栈。
79///
80/// 在 `eval_let()` 里循环处理赋值语句,最后表达式求值返回。
81///
82/// 另外要说的是,Rust 实现的思路一般不像 C 那样直接处理下标,而是利用高级别的抽象(例如 [`Iterator`](Iterator))这种去处理,只要遍历一次。
83///
84/// 栈的实现,没有在进入下一个作用域的时候拷贝变量空间,而是把当前作用域的变量名对应的键值对入栈,出栈的时候先删除当前作用域里的变量,再从整个栈里恢复变量空间。
85pub struct Solution;
86
87type Result<T> = std::result::Result<T, String>;
88
89impl Solution {
90
91    pub fn evaluate(expression: String) -> i32 {
92        let mut e = Evaluation::new(tokenize(&expression));
93        // assume all inputs will be valid
94        let res = e.eval(None).unwrap_or_else(|e| panic!("{}", e));
95        // 如果还有符号,说明输入是非法的
96        assert!(e.is_end(), "Unexpected input");
97        res
98    }
99}
100
101struct Evaluation<T: Iterator> {
102    /// stacks for each level local variables
103    stacks: Vec<HashMap<String, i32>>,
104
105    /// entire namespace in the current level
106    vars: HashMap<String, i32>,
107
108    tokens: Peekable<Fuse<T>>,
109}
110
111impl<T: Iterator> Evaluation<T> {
112    fn new(tokens: T) -> Self {
113        Self {
114            stacks: Vec::new(),
115            vars: HashMap::new(),
116            tokens: tokens.fuse().peekable(),
117        }
118    }
119}
120
121impl<T: Iterator<Item = Token>> Evaluation<T> {
122
123    #[inline]
124    fn expect(&mut self, expect: Token) -> Result<()> {
125        self.tokens.next()
126            .ok_or_else(|| format!("Invalid, missing required token: {:?}", expect))
127            .and_then(|token| {
128                if token == expect {
129                    Ok(())
130                } else {
131                    Err(format!("Invalid, expect token: {:?}, found: {:?}", expect, token))
132                }
133            })
134    }
135
136    #[inline]
137    fn is_end(&mut self) -> bool {
138        self.tokens.peek().is_none()
139    }
140
141    // Evaluate expression
142    fn eval(&mut self, local: Option<&HashSet<String>>) -> Result<i32> {
143        match self.tokens.next() {
144            Some(Token::LeftParenthesis) => {
145                self.eval(local).and_then(|res| {
146                    // expect RightParenthesis
147                    self.expect(Token::RightParenthesis)?;
148                    Ok(res)
149                })
150            }
151            Some(Token::Let) => {
152                // 进入 let 语句的时候,需要入栈
153                // 退出 let 语句的时候,需要出栈
154                self.push_stack(local);
155                let mut local = HashSet::new();
156                let res = self.eval_let(&mut local)?;
157                self.pop_stack(Some(&local));
158                Ok(res)
159            }
160            Some(Token::Add) => {
161                self.eval(local).and_then(|e1| self.eval(local).map(|e2| e1 + e2 ))
162            }
163            Some(Token::Mult) => {
164                self.eval(local).and_then(|e1| self.eval(local).map(|e2| e1 * e2 ))
165            }
166            Some(Token::Const(num))  => {
167                Ok(num)
168            }
169            Some(Token::Ident(var)) => {
170                self.vars.get(&var).map(|&v| v).ok_or_else(||format!("Not found var: `{}`", var))
171            }
172            _ => {
173                Err("Invalid token".into())
174            }
175        }
176    }
177
178    /// Evaluate `let` expression, from the first item after `let`
179    fn eval_let(&mut self, local: &mut HashSet<String>) -> Result<i32> {
180        loop {
181            // 分两种情况,先处理键值对的赋值语句,然后处理 `let` 语句中最后的 expr 部分
182            match self.tokens.peek() {
183
184                // 如果下一个表达式是标识符,那么有以下几种符合的情况
185                Some(Token::Ident(_var)) => {
186                    let ident = match self.tokens.next().unwrap() {
187                        Token::Ident(s) => s,
188                        _ => unreachable!(),
189                    };
190
191                    match self.tokens.peek() {
192                        // assignment a var with a parenthesis expression (...) or a constant or a variable
193                        // 赋值表达式,给之前的 ident 赋值,可以是 括号表达式、常量表达式、变量表达式,求值后更新变量空间,同时记录 local 变量名,循环处理
194                        Some(Token::LeftParenthesis) | Some(Token::Const(_)) | Some(Token::Ident(_)) => {
195                            let res = self.eval(Some(&local))?;
196                            self.vars.insert(ident.clone(), res);
197                            local.insert(ident);
198                        }
199                        // evaluate the last expression of let
200                        // 如果标识符之后接着是右括号,说明这个标识符是 `let` 语句的最后一部分,也就是说这个标识符是变量表达式,可以直接求值返回
201                        Some(Token::RightParenthesis) => {
202                            return self.vars.get(&ident).map(|&v| v).ok_or_else(||format!("Not found var: `{}`", ident));
203                        }
204                        _ => {
205                            return Err("Invalid let, expect expression".into());
206                        }
207                    }
208                }
209
210                // let expr part is const or is (...) expr
211                // 如果最后一个表达式是常量表达式或者是括号表达式,可以直接求值回返,紧接着之后一定是一个右括号,否则就不合法
212                Some(Token::Const(_)) | Some(Token::LeftParenthesis) => {
213                    return self.eval(Some(&local));
214                    // next should be Token::RightParenthesis
215                }
216
217                _ => {
218                    return Err("Invalid `let` expression".into());
219                }
220            }
221        }
222    }
223
224    /// 从变量空间里找到当前使用域里的变量,入栈
225    fn push_stack(&mut self, local: Option<&HashSet<String>>) {
226        local.map(|local| {
227            let mut stack = HashMap::new();
228            for k in local.iter() {
229                if let Some(v) = self.vars.get(k) {
230                    stack.insert(k.clone(), v.clone());
231                }
232            }
233            self.stacks.push(stack);
234        });
235    }
236
237    /// 从变量空间里删除当前作用域里的变量,然后从栈里恢复所有变量空间里的值,然后弹出栈顶
238    fn pop_stack(&mut self, local: Option<&HashSet<String>>) {
239        local.map(|local| {
240            for k in local.iter() {
241                self.vars.remove(k);
242            }
243
244            for stack in &self.stacks {
245                for (k, v) in stack {
246                    self.vars.insert(k.clone(), v.clone());
247                }
248            }
249            self.stacks.pop();
250        });
251    }
252}
253
254#[derive(Debug, PartialEq)]
255enum Token {
256    /// 常量
257    Const(i32),
258
259    /// 标识符,可以是用于赋值左侧的变量名,也可以是一个求值表达式
260    Ident(String),
261
262    /// Keyword `let`
263    Let,
264
265    /// Keyword `add`
266    Add,
267
268    /// Keyword `mult`
269    Mult,
270
271    /// Left parenthesis `(`
272    LeftParenthesis,
273
274    /// Right parenthesis `)`
275    RightParenthesis,
276}
277
278impl Token {
279    fn from_str<S: AsRef<str>>(s: S) -> Self {
280        let s = s.as_ref();
281        match s {
282            "(" => Self::LeftParenthesis,
283            ")" => Self::RightParenthesis,
284            "let" => Self::Let,
285            "add" => Self::Add,
286            "mult" => Self::Mult,
287            c if c.len() > 0 => {
288                match c.chars().next().unwrap() {
289                    'a'..='z' => Self::Ident(s.into()),
290                    _ => Self::Const(s.parse().unwrap()),  // assume all expr valid
291                }
292            }
293            _ => {
294                panic!("Invalid");
295            }
296        }
297    }
298}
299
300fn tokenize<'a>(s: &'a str) -> impl Iterator<Item = Token> + 'a {
301    let mut chars = s.chars();
302    let mut cache = String::new();
303    std::iter::from_fn(move || {
304        while let Some(c) = chars.next() {
305            match c {
306                '('  => return Some(Token::from_str("(")),
307                v @ ')' => {
308                    if cache.len() > 0 {
309                        let next = Some(Token::from_str(cache.drain(..).collect::<String>()));
310                        cache.push(v);
311                        return next;
312                    } else {
313                        return Some(Token::from_str(")"));
314                    }
315                }
316                ' ' => {
317                    return Some(Token::from_str(cache.drain(..).collect::<String>()));
318                }
319                c => cache.push(c),
320            }
321        }
322
323        if cache.len() > 0 {
324            Some(Token::from_str(cache.drain(..).collect::<String>()))
325        } else {
326            None
327        }
328    })
329}
330
331#[cfg(test)]
332mod tests {
333    use super::*;
334
335    #[test]
336    fn test() {
337        let cases = vec![
338            (3, "(add 1 2)"),
339            (15, "(mult 3 (add 2 3))"),
340            (10, "(let x 2 (mult x 5))"),
341            (14, "(let x 2 (mult x (let x 3 y 4 (add x y))))"),
342            (2, "(let x 3 x 2 x)"),
343            (5, "(let x 1 y 2 x (add x y) (add x y))"),
344            (6, "(let x 2 (add (let x 3 (let x 4 x)) x))"),
345            (4, "(let a1 3 b2 (add a1 1) b2)"),
346            (14, "(let x 2 (mult (let x 3 y 4 (add x y)) x))"),
347            (-128534112, "(let x0 -4 x1 2 x2 -4 x3 3 x4 2 x5 3 x6 2 x7 2 x8 -1 x9 -1 (mult (mult (mult x2 -8) (add -5 (let x0 1 x5 -3 (add (add x7 (add (let x0 -5 x9 -4 (add (mult 1 1) -10)) (mult -8 (mult x3 -5)))) (add (let x0 3 x8 -1 (let x0 -1 x9 1 (add x4 -6))) x9))))) (mult (add (mult (add (mult -6 (mult (add x1 x4) -4)) (let x0 -2 x7 4 (mult (mult (let x0 -3 (mult 1 1)) (add (mult 1 1) (mult 1 1))) (mult -5 (mult -9 (mult 1 1)))))) -10) x5) (mult (mult x5 -7) x8))))"),
348        ];
349        for (expect, arg) in cases {
350            assert_eq!(expect, Solution::evaluate(arg.into()));
351        }
352    }
353}