Scheme中使用sllgen解析自定义语法时caddr错误的解决方法
解决sllgen中try-catch-finally语法解析的caddr错误及列表操作问题
错误原因分析
你遇到的caddr错误,本质是试图对长度不足3的列表调用caddr。caddr等价于(car (cdr (cdr x))),要求输入列表至少有3个元素(即x是(a b c ...)的形式)。而错误信息里给出的参数是'(expression ("try" "{" expression "}" ... try-exp))——这个列表只有2个元素:第一个是符号expression,第二个是整个try语法的规则定义。显然你是误将语法规则本身当成了解析后的AST节点来操作,或者对解析后的AST结构判断错误。
语法定义的修正
先修正你的语法定义问题:
- 非终结符错误:你把异常类型的非终结符
Except写成了字符串字面量"Except",这会导致解析器把[Except]中的Except当成固定字符串,而不是去匹配Except定义的异常类型。 - 语法规则不匹配规范:你的语法规范中catch块是
catch [ Except ] : Expression ;,但当前规则里用:结尾,应该改成;;finally块的规则需确保和规范一致。
修正后的完整语法定义:
(expression ("try" "{" expression "}" (arbno "catch" "[" Except "]" ":" expression ";") (arbno "finally:" expression ";") try-exp)) (Except ("general") Exception ("not a number") Exception ("not a boolean") Exception ("environment") Exception) (expression ("throw" Except) throw-exp)
正确的列表操作方法
当sllgen解析生成AST后,try-exp节点的结构为(try-exp 主体表达式 catch子句列表 finally子句列表)。此时访问各部分的正确方式:
- 主体表达式:
(cadr try-exp-node) - catch子句列表:
(caddr try-exp-node)(这里caddr合法,因为节点至少有4个元素) - finally子句列表:
(cadddr try-exp-node)
更稳妥的实践
- 先确认AST结构:解析后打印AST,比如
(display parsed-try-exp),直观看到节点的元素数量和顺序,避免凭想象操作。 - 用辅助函数替代直接调用caddr/cadddr:
这样代码更可读,也不容易因结构变化出错。(define (try-exp-body te) (cadr te)) (define (try-exp-catches te) (caddr te)) (define (try-exp-finally te) (cadddr te)) - 使用模式匹配(如果用Racket):Racket的
match可以更清晰地解构AST,避免手动列表操作:(match parsed-try-exp [`(try-exp ,body ,catches ,finally) (handle-try body catches finally)])
总结
- 先修正语法定义中的非终结符和规则匹配问题,确保解析出正确的AST结构。
- 区分语法规则定义和解析后的AST节点,不要对规则定义调用列表操作函数。
- 优先用辅助函数或模式匹配处理AST,减少直接使用caddr等函数带来的错误。
内容的提问来源于stack exchange,提问作者Majd Abusaleh
相关产品推荐
相关产品推荐

