`
jiang5495
  • 浏览: 89616 次
  • 性别: Icon_minigender_1
  • 来自: 湖南
社区版块
存档分类
最新评论

(转载) 算术表达式的自上而下语法分析及其实现(中)

阅读更多
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'| /...

    编译原理:算术表达式递归下降分析程序设计[定义].pdf

    通过本次实验,掌握了自上而下语法分析法的特点和递归下降语法分析的基本原理和方法。递归下降分析法是一种简单、直观、易构造分析程序的方法,但它不适于文法过于复杂的场景。 在实验中,需要注意程序的每一步,...

    phrase.cpp

    编译原理实验(二)--语法分析:采用自上而下的方法实现算术表达式的语法分析器,以加深对自上而下语法分析过程的理解。 E→TE' E'→+TE'| -TE' |ε T→FT' T'→*FT'| /FT' |ε F→(E) | id | num

    递归下降分析器设计与实现.pdf

    递归下降分析器是编译原理中的一种重要的语法分析技术,具有简单、易于实现和快速分析的特点,但也存在一些缺点,需要在实际应用中加以注意。 资源相关信息: * 编译原理 * 语法分析 * 递归下降分析器 * LL(1)文法...

    实验5-LL(1)语法分析程序的设计与实现(C语言).doc

    LL(1)语法分析程序的设计与实现(C语言) 一、实验目的: 本实验的目的是通过设计LL(1)语法分析程序来理解自顶向下的语法分析思想。LL(1)语法分析是一种常用的语法分析方法,它可以自动判断所给字符串是否为所给...

    编译原理(四)–语法分析

    本章将重点介绍典型的语法分析方法及相关的概念和实现技术 语法分析分为: 自上而下:递归下降分析法(LL预测分析法—>推导 自下而上:算符优先分析法(LR分析法—>归约 4.1 语法分析器的功能 4.1.1 语法分析器任务 ...

    编译原理:LL(1)语法分析器的设计

    E →T E’ E’→+ T E’ | λ TF→ T’ T’→* F T’ | λ F →id| ( E ) 符号串 i + i * i # 的LL[1]分析过程:

    自上而下递归分析表达式正确性

    对每一个非终结符(分别代表一个语法单位)按其产生方式结构构造相应的语法子程序,以完成非终结符号所对应的语法单位的分析和识别任务。其中终结符号产生匹配命令,而非终结符号则产生过程调用命令。因为文法可以...

    top_down.rar_top down_top-down_语法分析值

    自上而下的语法分析方法 能对算术表达式进行语法分析并计算出表达式的值

    编译原理 语法分析程序、LL(1)文法

    根据算术表达式的语法定义,设计相应的产生式规则...该程序能够对输入字符串进行自上而下无回溯的语法分析即预测分析,并输出“语法正确”或“语法错误”的结果,该程序能够实现First集、Follow集和构造预测表的算法。

    递归下降语法分析程序设计.doc

    该程序设计采用递归下降分析程序,通过自上而下的分析方式,来实现对赋值语句的语法分析。 递归下降分析算法 递归下降分析算法是一种自上而下的分析方法,它通过对语法规则的递归应用,来实现对输入语句的语法分析...

    词法分析器

    掌握语法分析的两类基本方法:自上而下的分析与自下而上的分析,并通过对自上而下的分析的编码实现,理解其执行过程以及相关限制。 实验内容:实现下述我们定义的语言的语法分析器。这种语言的程序结构很简单,语法...

    递归下降子程序的编写

    1. 预习自上而下语法分析小节的内容。 2. 学生自己考虑使用的开发环境,如 VC++,熟悉开发环境。 三、实验内容 我们将选择一个算术表达式文法:E→TE’,E’ → +TE’|ε,T→FT’,T’ →*FT’ |ε,F→(E) |i,...

    预测分析程序的设计与实现报告

    根据算术表达式的语法定义,设计相应的产生式规则,并改造为LL(1)文法。根据此文法构造预测分析表和预测分析程序。该程序能够对输入字符串进行自上而下无回溯的语法分析,并输出“语法正确”或“语法错误”的结果。

    递归下降分析器设计实现分析范文.doc

    1. 掌握自上而下语法分析的要求与特点。 2. 掌握递归下降语法分析的基本原理和方法。 3. 掌握相应数据结构的设计方法。 实验内容 编程实现给定算术表达式的递归下降分析器。算术表达式文法如下: E --> E+T|T T -...

    《编译原理》——期末复习.docx

    17.3 算术表达式和赋值语句 175 17.4 单元测试 178 十八、语义分析和中间代码产生_2 179 18.1 布尔表达式的作用和文法描述 179 18.2 做控制用布尔表达式的翻译(回填) 181 18.3 控制流语句的翻译 186 18.4 控制流...

    程序设计语言编译原理 (陈火旺)

    7.3.1 简单算术表达式及赋值语句 7.3.2数组元素的引用 7.3.3 记录中域的引用 7.4布尔表达式的翻译 7.4.1数值表示法 7.4.2作为条件控制的布尔式翻译 7.5控制语句的翻译 7.5.1控制流语句 7.5.2标号与goto语句...

    编译原理实验三 递归下降分析

    递归下降分析实验报告 ...通过本次实验,我们加深了对递归下降分析法的理解,并掌握了递归下降分析程序的编写和实现。该实验为我们提供了一个实践递归下降分析法的机会,提高了我们对编译原理的理解和掌握。

Global site tag (gtag.js) - Google Analytics