loop_in_codes

低调做技术__欢迎移步我的独立博客 codemaro.com 微博 kevinlynx

kl中的错误处理

kl中的错误处理

    之前我一直说错误处理是kl里的软肋,由于一直在关注一些具体功能的改进,也没有对
这方面进行改善。

    我这里所说的错误处理,包括语言本身和作为库本身两方面。
    语言本身指的是对于脚本代码里的各种语法错误、运行时错误等的处理。好的处理应该
不仅仅可以报告错误,而且还能忽视错误让处理过程继续。
    而把kl解释器作为一个库使用时,库本身也应该对一些错误情况进行报告。

    整体上,kl简单地通过回调函数指针来把错误信息传给库的应用层。而因为我希望整个
kl实现的几层(词法分析、语法分析、符号表、解释器等)可以尽可能地独立。例如虽然语
法分析依赖于词法分析(依赖于词法分析提供的接口),但是因为词法分析并不对语法分析
依赖,所以完全可以把词法分析模块拿出来单独使用。所以,在日志方面,我几乎为每一层
都附加了个error_log函数指针。
    而用户层在通过kllib层使用整个库时,传入的回调函数会被间接地传到词法分析层。
实际上,当kl作为一个库时,kllib正是用于桥接库本身和用户层的bridge。

    另一方面,语言本身在处理错误的脚本代码时,错误分为几大类型层次:
    1.词法错误 lex error,如扫描字符串出错
    2.语法错误 syntax error,整理语法树时出错
    3.运行时错误 runtime error,在解释执行代码时出错
    4.库错误 lib error,发生在kllib这个bridge层的错误
    kl在报告错误信息时,会首先附加该错误是什么类型的错误。

    这里最麻烦的是语法错误的处理。因为语法分析时发生错误的可能性最大,错误类型也
有很多。例如你少写了分号,少写了括号,都会导致错误。这个阶段发生错误不仅要求能准
确报告错误,还需要忽略错误让整个过程尽量正确地下去。

    语法分析阶段最根本的就是符号推导(单就kl的实现而言),所谓的符号推导是这样一
个过程,例如有赋值语句:a = 1;语法分析时,语法分析器希望(所谓的推导)等号后面会
是一个表达式,当分析完了表达式后,又希望接下来的符号(token)是分号作为该语句的结
束。
    所以,klparser.c中的syn_match正是完成这个过程。每次你传入你希望的符号,例如
分号,该函数就检查词法分析中当前符号(token)是否是分号。当然,对于正确的脚本代码,
它是一个分号,但是如果是错误的代码,syn_match就会打印诸如:
    >>syntax error->unexpected token-> ....
    即当前的符号是不被期望的。

    上面完成了错误的检测。对于错误的忽略,或者更高级点地对错误的校正,kl中处理得
比较简单,即:直接消耗掉这个不是期望中的符号。例如:
    a = 1 /* 忘加了分号 */
    b = 1;
    上面两句代码被处理时,在处理完a=1后,发现当前的符号(token)b(是一个ID token)不
是期望(expect)中的分号,首先报告b不是期望的符号,然后kl直接掠过b,获取下个符号=。
然后处理a=1这个过程结束。当然,下次处理其他语句时,发现=符号,又会继续发生错误。

    错误信息中比较重要的还有行号信息。之前kl这方面一直存在BUG,我在写贪食蛇例子
的时候每次新加代码都不敢加太多。因为解释器报告的错误行号总是错误的,我只能靠有没
有错误来找错误,而不能通过错误信息找错误。
    行号信息被保存在词法分析状态中(lexState:lineno),语法分析中获取token时,会取
出当前的行号,保存到语法树树节点中。因为包括解释模块都是基于树节点的,所以词法分
析语法分析解释器三层都可以准确报告行号。

    但是之前解释器报告的行号始终很诡异。症结在于我在载入脚本代码文件时,以rb方式
载入,即二进制形式。于是,在windows下,每行文本尾都会有\r\n两个字符。而在词法分
析阶段对于行号的增加是:
    case '\n':
    case '\r':
        ls->lineno ++;
    不同OS对于文本文件的换行所添加的字符都不一样,例如windows用\r\n,unix系用\n
,貌似Mac用\r。所以,词法分析这里写应该可以准确地处理行号。

    但是对于windows,这里就直接将行号增加了两次,所以也就导致了行号出错的问题。查
了下文档,发现以文本方式打开文件("r"),调用fread函数读入文件内容时,就会自动把
\r\n替换为\n。

    代码改后,又出问题。这个时候,通过fseek和ftell获取到的文件尺寸,貌似包括了
\r\n,而fread出来的内容却因为替换\r\n为\n而没有这么多。
    不过文件载入不属于kl库本身,kl只接收以字符串形式表示的脚本代码,所以也算不了
核心问题。

    同样,最新代码可以从google SVN获取。当然,我也在考虑是否换一个新的项目地址。

posted on 2009-03-26 17:17 Kevin Lynx 阅读(3131) 评论(0)  编辑 收藏 引用 所属分类: kl脚本实现编译原理


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理