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}