[语法分析]混合语法分析

    之前小小地透露过,我会用LR分析方法。它很强大,而且效率比较高,而且Jerry语言的语法(虽然还未具体证实,但我可以保证)是相对(于LALR(1)或LR(1)方法)容易构造的SLR(1)文法。

    然而无论如何,Jerry语言语法的复杂性显然是大大高于书上一般给出的练习,那些练习通常只有几个产生式,至多十来个LR项目。然而Jerry一共有三十多个产生式,写出LR项目一共有大约70个。所以用严格的LR分析方法来搞,复杂度是不可思议的(特别是当语法产生式有扩充的时候),LR项目族集。因此得简化LR分析法。

 

    从LR分析的本质上看,它就是一个分析3型文法的DFA再带个有规约功能的栈。使用栈的重要原因(也是唯一原因)就是因为语法会递归,这些信息需要用栈来存放。因此如果把语法分析中的产生式分成两类——会递归的和不会递归的——分开分析,那么一些LR分析会更清晰一些(在不完全画出LR项目族集时)。对于不递归的产生式,把它们认为是特殊的3型文法就可以了;而递归的产生式也不必那么纠结,仔细看看,除了在变量定义时可以定义一个或多个需要递归,就是各种运算。而运算这个东西嘛,不知道大家是否玩过表达式求值的小程序,其实可以把这个程序简化一下(可以将词法分析从中剔除掉)移植过来,在需要(Assignment)时就跳转到这个小程序中进行。

    之前说到nextToken这个重要的函数是语法分析和词法分析的桥梁,那么只要搭两座桥就可以了——写两个nextToken函数的实现。当然,这并不意味着词法分析在获得符号后去需要去选择一个函数,这样词法分析就变得太复杂了。一个易行的解决方案是,将nextToken声明为一个函数指针,默认指向LR分析函数,当LR分析函数读入到

    First(Assignment)

中的元素时,压进栈,然后改变指针指向表达式求值的变种版本。当表达式求值遇到任何错误时(相当有可能是正确结束时),再把指针改回来。万事大吉。

 

    然而,事情没这么简单,如果只是在两种不同的语法分析方法之间切换,那么遇到诸如

    x = a[13 + b[31]];

这样的输入,语法分析器就没辙了,因为在遇到 b[31] 之前,语法分析器指针就一直指向算符优先分析函数,读到这里时,怎么处理呢?一种方案是将算符优先分析再弄复杂一点(这确实是可行的),让它也能够识别所有的包括嵌套着的变量数组。我觉得这是很不适合的,因为混入算符优先分析的初衷就是为了简化单个的语法分析模块;其次,如果单独抽出识别变量数组的语法分析作为一个新的模块,它还可以在识别变量声明语句是被重用。

    这里我想到的另一种解决方法是,再开辟一个语法分析器栈,每到需要时,将最适合的语法分析函数(和它所需的数据结构)压入分析器栈的栈顶。在栈底的是LR分析器。如识别到

    int x[100][200 + 100 * // 未完成

的时候,分析器栈内是这种状况:

 

栈底

    LR分析函数

    变量识别函数

    算符优先分析函数

栈顶

 

当读入到

    int x[100][200 + 100 * 20] // 未完成

时,算符优先分析碰到无法识别的符号 ']' ,即认为识别结束,然后将识别到的代表

    200 + 100 * 20

的非终结符记录下来,然后弹出栈顶分析函数(算符优先分析函数),将该非终结符送入此时栈顶的变量识别函数。变量识别函数将该非终结符移进(姑且用这个词),然后继续识别(从接下来的 ']' 开始)。

 

    说去说来,语法分析里面遍布栈的踪影,因此我们急需一个栈结构。不过并不用费心自己来写一个,以下站点包含一个开源的C语言基本数据结构库(而且是C语言面向对象的):

http://code.google.com/p/cobjorntlib/source/browse/#svn/trunk

你可能感兴趣的:(数据结构,SVN,Google)