3. 产生式函数的改进
前两节我们已经实现了自上而下语法分析算法和产生式函数的构造,在这一节,我着重阐述对产生式函数的运行效率和占用空间进行优化的方法。
首先考察一下产生式E -> T+E | T-E | T的分析函数:
void E_AddSub()
{
T_MulDiv(); //调用非终结符T的产生式函数分析T
If(ch==’+’ ||ch==’-‘) //如果当前字符是’+’或’-‘,
//如果是’+’,则用产生式E -> T+E推导,
//如果是’-‘,则用产生式E -> T-E推导。
{
advance(); //则取下一个字符
E_AddSub(); //调用非终结符E的产生式函数分析E
} //此时产生式E -> T+E | T-E的推导算法结束
//如果下一个字符不是不是’+’或’-‘,
//则本函数是根据产生式E -> T来进行推导的,不必进行错误处理。
}
大家看到,在if语句块中有一句E_AddSub();,这意味着在E_AddSub()函数中的语句可以调用自己本身,即函数中存在递归。然而在这里,我们完全可以节省一部分因递归占用的程序堆栈空间,在这同时也减少了因对程序堆栈进行push/pop操作耗费的时间。在这里我要用到的一种改进的方法是用循环代替if通过消除自身递归来削弱递归深度的方法,比如改进后的E_AddSub()函数如下:
//清单7:改进后的产生式E -> T+E | T-E | T的分析函数
void E_AddSub()
{
T_MulDiv(); //调用非终结符T的产生式函数分析T
while(ch==’+’ ||ch==’-‘) //如果当前字符是’+’或’-‘,
//如果是’+’,则用产生式E -> T+E推导,
//如果是’-‘,则用产生式E -> T-E推导。
{
advance(); //则取下一个字符
T_MulDiv(); //调用非终结符E的产生式函数分析T
} //若当前指示器指示的符号是’+’或’-‘,则继续while循环
//如果下一个字符不是不是’+’或’-‘,
//则本函数是根据产生式E -> T来进行推导的,不必进行错误处理。
}
我们可以看到在清单7中,在把if变成while的同时,还把while语句块中的E_AddSub()变为T_MulDiv(),这意味着把产生式(其中op为’+’或’-‘):
E -> T op E
转换为:
E -> T op T op T op T op ……………… op T
两者是等价的。显然对于型如i op i op i op i这样的句子,后者有更快的推导速度,而前者需要多进行3次递归堆栈。因此,改进后的产生式函数更高效。同样,T_MulDiv()也可以通过这种方法改进。
然而,这种方法并不能完全消除递归,只是减少了递归的调用次数,削减了递归层次。每当分析到括号运算符时,因为F_Number()会被T_MulDiv()调用,T_MulDiv()会被E_AddSub()调用,所以会产生一个对开始符E的产生式函数的递归:
void F_Number()
{
if(ch==’(‘) //如果当前的指示器指示的字符是’(‘
{ //则根据产生式F -> (E)推导
advance(); //跳过’(‘,指示器指向下一个字符
E_AddSub(); //调用非终结符E的产生式函数分析E
If(ch!=’)’)
error(); //如果出错,则进行出错处理。
Advance(); //如果有’)’,语法正确,跳过’)’
return; //返回
}
………………………………
return; //返回
}
按照这种方法只有在分析括号运算符内的算术表达式时才增加一个递归层次,可以有效地提高语法分析的执行效率。
4. 语法分析中的出错处理
进行出错处理也许是件很麻烦的事。想象一个设计良好的编译调试环境,比如Visual Studio,我们在用它开发编译程序时,不光可以知道哪一句错了,而且可以获得出错的原因。我们现在要做的是对一句算术表达式(如果出错的话)找出出错的原因,并把错误原因和相关信息提示给用户。这该怎么办呢?
《编译原理》的课本上大都讲过通过考察FIRST集和FOLLOW集构造语法分析表的方法来处理错误,这样可以把错误的处理方法填充到分析表中。然而在这里,既然我们已经构造好了文法产生式函数,简单地,这样,我们仅仅通过在函数中出现error()函数调用的地方进行分析一下即可逐步实现对错误的处理。
考察清单5中产生式F -> (E) | i的函数:
void F_Number()
{
if(ch==’(‘)
{
advance();
E_AddSub();
If(ch!=’)’) //如果当前指示器指示的字符不是’)’ ,则产生错误,
error(); //错误号:1
advance();
return;
}
if(ch是数字)
{
advance();
}
else //如果当前指示器指示的字符不是数字,则产生错误
error(); //错误号:2
return;
}
在上述代码中可以看到有两处可能产生错误的地方,其中1号错误产生的原因很容易看出来,是“缺少与左括号匹配的右括号”。2号错误产生的原因是“当前指示器指示的字符不是数字”,即在算术表达式中该出现数字的地方没有出现数字,比如当指示器指到非法表达式“23+#b”中的“#”、“1-(+”中的“+”和“2+*3”中的“*”时都属于这种情况。2号错误还有两种情况,一种是当括号内无表达式(即括号内表达式为空时),比如“3+()”,这样需要判断当前指示的字符是否为’)’;第二种是表达式不完整(即表达式提前结束),比如“4*(2+3)+”,这需要判断当前指示的字符是否为’\0’(字符串结束符)。
再考察一下清单6中的主函数:
int main()
{
………………………………
//对输入字符缓冲区和字符指示器初始化
//调用开始符E的分析函数开始自上而下语法分析:
E_AddSub();
//分析结束
………………………………
return 0;
}
然而,根据我们的设计,当E_AddSub() 函数返回(分析结束)时,在指示器所指字符的后面有可能还有未被分析的字符,凡此时存在未被指示器扫描过的字符的表达式均为错误的表达式。比如当指示器指到非法表达式“2*(3+4)5”中的“5”、“2+3(4+5)”中的“(”和“23a”中的“a”时都属于这种错误情况。
(待续)
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/hifrog/archive/2004/01/30/21641.aspx
分享到:
相关推荐
### 算术表达式的自上而下语法分析及其实现 #### 一、算术表达式的产生式 本文探讨了一种基于自上而下的语法分析技术,旨在通过解析简单的算术表达式来构建实用的语法分析程序。该文法模型能够支持五种基本运算:...
算术表达式预测分析程序实现是计算机科学中一个重要的研究领域,旨在开发出能够对给定算术表达式进行预测分析的程序。该程序的设计需要掌握自上而下语法分析的要求与特点、预测语法分析的基本原理和方法、相应数据...
(使用Python实现,注释详尽)在词法分析器的基础上,采用递归下降的方法实现算术表达式的语法分析器,以加深对自上而下语法分析过程的理解。 1、对算术表达式文法: E→TE' E'→+TE'| -TE' |ε T→FT' T'→*FT'| /...
通过本次实验,掌握了自上而下语法分析法的特点和递归下降语法分析的基本原理和方法。递归下降分析法是一种简单、直观、易构造分析程序的方法,但它不适于文法过于复杂的场景。 在实验中,需要注意程序的每一步,...
编译原理实验(二)--语法分析:采用自上而下的方法实现算术表达式的语法分析器,以加深对自上而下语法分析过程的理解。 E→TE' E'→+TE'| -TE' |ε T→FT' T'→*FT'| /FT' |ε F→(E) | id | num
递归下降分析器是编译原理中的一种重要的语法分析技术,具有简单、易于实现和快速分析的特点,但也存在一些缺点,需要在实际应用中加以注意。 资源相关信息: * 编译原理 * 语法分析 * 递归下降分析器 * LL(1)文法...
* 调试调试例子应包括符合语法规则的算术表达式,以及分析程序能够判别的若干错例。 * 输出对于所输入的算术表达式,不论对错,都应有明确的信息告诉外界。 * 扩充有余力的同学,可适当扩大分析对象。 五、语法分析...
《编译原理》实验报告的主题聚焦于算术表达式的递归下降分析程序设计,这是一个典型的技术性任务,旨在让学生深入理解编译原理中的语法分析过程。实验的主要目标包括三个方面: 1. 掌握自上而下的语法分析方法,这...
LL(1)语法分析程序的设计与实现(C语言) 一、实验目的: 本实验的目的是通过设计LL(1)语法分析程序来理解自顶向下的语法分析思想。LL(1)语法分析是一种常用的语法分析方法,它可以自动判断所给字符串是否为所给...
这个文法允许计算简单的算术表达式,如加法和乘法。在消除左递归和提取公因子后,等价的LL(1)文法变为: E' → +TR | ε T → TR | T T' → *FM | ε F → (E) | i 在实验中,学生需要实现以下步骤: 1. **文法...
### 编译原理:LL(1)语法分析器的设计 #### 概述 本文将详细介绍一个简单的LL(1)语法分析器的设计与实现过程。...本篇介绍的LL(1)语法分析器提供了一个基本框架,可用于理解和实现更复杂的语法分析任务。
词法分析器的实现通常基于正则表达式或状态机,确保能够准确地识别和转换源代码中的各种元素。 进入正题,LL(1)语法分析器的“LL”代表“Left-to-right”,意味着它从左到右扫描输入序列;“1”表示“使用一个输入...
在这个项目中,C语言被选为实现语法分析器的工具,因为它的效率高且对内存管理有直接的控制。 ### 2. 词法分析 词法分析是编译器的第一步,它将源代码分解成一个个称为“标记”或“词素”的基本单元。这些词素可以...
本章将重点介绍典型的语法分析方法及相关的概念和实现技术 语法分析分为: 自上而下:递归下降分析法(LL预测分析法—>推导 自下而上:算符优先分析法(LR分析法—>归约 4.1 语法分析器的功能 4.1.1 语法分析器任务 ...
对每一个非终结符(分别代表一个语法单位)按其产生方式结构构造相应的语法子程序,以完成非终结符号所对应的语法单位的分析和识别任务。其中终结符号产生匹配命令,而非终结符号则产生过程调用命令。因为文法可以...
1. 预习自上而下语法分析小节的内容; 2. 学生自己考虑使用的开发环境,如 VC++,熟悉开发环境。 三、实验内容 针对算术表达式文法:E→TE’ E’ → +TE’|ε T→FT’ T’ →*FT’ |ε F→(E) |i 为其编写递归...
本文将深入探讨自上而下的语法分析方法,以及如何利用这种方法对算术表达式进行语法分析并计算其值。 自上而下的语法分析,也称为递归下降分析,是一种基于规则的解析技术,从输入符号串的起始符号开始,按照文法...