脚本解释器构架(一)

解释器和编译器的前端是相似的。编译器包括前端(词法分析、语法分析、语义分析)和后端(优化、中间语言、指令生成)。解释器的前端不需要语义分析,仅靠语法分析构建一个语法树即可。后端就是解释运行环境。

词法分析太简单了。这里从语法分析讲起。

脚本的语法分析

绝大多数脚本的语法非常简单,任何一种自顶向下的分析法基本都可以胜任。LL(1)是个不错的选择——简单、高效。LL1的要求很严格:1、不允许左递归(这个通常有);2、不允从左至右的二义性冲突(这个很难)。

通常情况下,第一点不满足的话,是可以消除的。简单文法一般不会有间接左递归(复杂文法都很少用到间接左递归),要有也是直接左递归。消除直接左递归的方法是非常简单的。举个直观的例子:

1. expr -> expr + term
2. expr -> term
3. term -> term * factor
4. term -> factor
5. factor -> digits | identifier

该文法描述了由+、×两个二元运算符和数字、标识符构成的所有中缀表达式。1和3是左递归的,隐含了一个同级运算符从左至右组合计算的意义。消除这种直接左递归的方法是:

1. 构造一个新的产生式expr-aux -> + term | ε,蕴含符右边就是原来的右部去掉左端递归因子后剩下的部分。
2. 删除原左递归的产生式。
3. 所有相同非终结符导出的产生式后面加上expr-aux:expr -> term expr-aux

实际上就是把左递归变成了右递归。这样会产生一个问题:右递归隐含的组合顺序是从右至左。这只能在语义分析的时候再去调整。

如果不想再去调整,可以使用手动写递归下降来分析器解决。递归下降允许左递归。递归下降分析左递归文法时的流程如下:

 

从左至右的二义性冲突是最难解决的问题,该问题的复杂度没有上限。解决方法只有展开冲突产生式、合并冲突左因子。当文法中出现某些特定结构的时候,展开与合并是没有终结的:合并后总是会出现新的冲突,而且冲突模式与上一次的相似,还有,就是通常这种递归式的冲突是多重的。

好在脚本很简单,如果真的出现了这种二义性冲突,可以不改变功能而修改一下文法来达到需求。实际上,许多脚本甚至可以用正则表达式来分析,因为它们大多数都可以表示为正则文法(III型文法)。大多数的复杂语言都是上下文无关文法(II型),很少有I型或O型文法用于编程语言。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值