学过编译原理的同学大概都知道对一个句子进行自上而下语法分析的方法。我参考了陈火旺院士的《高级程序设计语言编译原理》,在这篇文章里我主要是站在编译原理的角度讲述一种语法分析程序的实现的方法,通过对一个典型的例子——算术表达式的分析,从而使大家了解构造一个实用的语法分析程序的方法,同时,也为广大程序员提供一种解决实际问题的思路。
本文包括以下内容:
1. 算术表达式的产生式;
2. 自上而下语法分析的算法和的产生式函数的构造;
3. 产生式函数的改进;
4. 语法分析中的出错处理;
5. 自上而下语法分析程序的实现。
1. 算术表达式的产生式
我在这里要实现的算术表达式要实现5种运算:加、减、乘、除和括号。比如一个简单的算术表达式的文法G1中包含以下产生式:
G1:
E -> E+E | E-E | E*E | E/E | (E) | i
为了明确运算符的优先权(括号的优先权高于乘除法,乘除法的优先权高于加减法),可改写文法G1如下:
改写后的文法G2:
E -> T+E | T-E | T
T -> F*T | F/T | F
F -> (E) | i
任何具有加、减、乘、除和括号运算优先权的算术表达式都可以通过上述文法中的产生式推导出来,比如对于行如i-i*(i+i)的算术表达式,有如下推导过程(其中i是数字或变量标示符,推导需要从开始符E开始推导,以下是最左推导):
E=> T-E => F-E => i-E => i-T => i-F*T => i-i*T => i-i*F => i-i*(E) => i-i*(T+E) =>i-i*(F+E) => i-i*(i+E) => i-i*(i+T) => i-i*(i+F) => i-i*(i+i)
在本文中,我们就使用文法G2中的产生式构造语法分析程序。
2.自上而下语法分析的算法和的产生式函数的构造
我们可以把一个对句子从开始符E到终结符的推导过程转化为一棵语法树,根节点(即开始符)在上、叶节点(即终结符)在下,自上而下的语法分析就是对这样一棵语法树“自上而下”地遍历过程。即,每次遍历从根节点(开始符)开始,通过各个中间节点(除开始符外非终结符)到达叶节点(终结符)。如果把每一个产生式做成一个函数,那么我们可以方便地通过对这些函数的递归调用和回溯来实现对语法树的遍历。那么对于文法G2中的3个产生式,我们需要3个函数:
void E_AddSub(); //对应于非终结符E的产生式
void T_MulDiv(); //对应于非终结符T的产生式
void F_Number(); //对应于非终结符F的产生式
我们通过对输入字符流的分析来实现自上而下的语法分析。在语法分析的过程中,我们需要一个输入字符缓冲区,用来存放输入的算术表达式字符串,需要一个字符指示器来指示当前正在分析的字符,还需要一个出错处理模块。在算法设计实现中,我们用到了3个全局成员:ch、advance和error,它们的含义如下:
ch 当前指示器所指的字符
advance() 使指示器指向输入字符缓冲器中的下一个字符的函数
error() 出错处理程序函数
由此可以构造自上而下语法分析算法,首先分析产生式E -> T+E

本文介绍了如何基于编译原理,采用自上而下的语法分析方法实现算术表达式的解析。通过算术表达式的产生式,详细阐述了E、T、F三个非终结符的产生式函数构造,以及如何通过这些函数实现对输入字符流的分析。文章以文法G2为例,展示了E -> T+E | T-E | T的语法分析函数,并给出了E、T、F的分析函数实现,为实现一个实用的语法分析程序提供了思路。
&spm=1001.2101.3001.5002&articleId=21640&d=1&t=3&u=4b913000463a449d9d08b0bf1cf48279)
2590

被折叠的 条评论
为什么被折叠?



