扩展SLLGEN的Scheme语法时嵌套列表解析错误的解决求助
问题描述
我是Scheme语言新手,尝试扩展EoPL开发者提供的原始SLLGEN的语法规则,以支持解释器识别嵌套列表。我在lang.scm中添加了如下语法规则:
(expression ("cons" "(" (arbno expression (arbno",")) ")") lst-exp)
同时在interp.scm中添加了适配函数。平级列表运行正常,但嵌套列表出现问题,例如执行命令:
(run "cons (1 ,cons(3 2))")
时,Racket解释器报错:
*cases: not a expval: (3 2)*
看起来解释器未将“3”和“2”识别为数字,而是将整个表达式视为字符串。附上data-structure.scm中相关的expval数据类型定义:
(define-datatype expval expval? (num-val (value number?)) (bool-val (boolean boolean?)) (lst-val (lst pair?)))
问题分析
当前语法规则中的(arbno expression (arbno","))存在逻辑错误:
- 该规则会匹配一个表达式后跟任意多个逗号的重复模式,无法正确识别用单个逗号分隔的多个表达式。比如嵌套调用
cons(3 2)里没有逗号时,语法解析会把(3 2)当成一个整体,而非两个独立的表达式。 - SLLGEN内置的
separated-list才是处理分隔符分隔元素列表的正确工具,专门用于实现逗号分隔的表达式列表场景。
解决方案
1. 修改lang.scm中的语法规则
将原cons表达式语法替换为separated-list版本:
(expression ("cons" "(" (separated-list expression ",") ")") lst-exp)
separated-list expression ","会正确识别用单个逗号分隔的多个表达式,包括嵌套的cons调用,同时支持列表末尾无逗号的写法。
2. 修正interp.scm中的lst-exp处理函数
确保处理函数对每个子表达式求值,再将结果组成合法列表并包装为lst-val:
(define (eval-exp exp env) (cases expression exp ;; ... 其他表达式处理规则 ... (lst-exp (exps) (lst-val (map (lambda (e) (expval->value (eval-exp e env))) exps))) ;; ... )) ;; 辅助函数:提取expval中的实际值 (define (expval->value v) (cases expval v (num-val (num) num) (bool-val (bool) bool) (lst-val (lst) lst) (else (error "Unknown expval type"))))
核心逻辑:
- 对每个子表达式
e调用eval-exp求值,得到expval类型结果。 - 用
expval->value提取出实际值(数字、布尔值或列表)。 - 用
map将所有值组成列表,再包装为lst-val。
3. 修正测试输入的语法
测试输入中嵌套的cons(3 2)缺少逗号,应改为cons(3 , 2),正确的测试命令为:
(run "cons (1 , cons(3 , 2))")
验证
修改后,解释器会正确解析嵌套表达式:
- 先求值
3得到num-val 3,2得到num-val 2,组成列表(3 2)并包装为lst-val。 - 再将
1的num-val和嵌套列表的lst-val组成新列表(1 (3 2)),最终返回对应的lst-val。
内容的提问来源于stack exchange,提问作者DBM
相关产品推荐
相关产品推荐

