编译原理之语法分析

来源:互联网 发布:淘宝服务市场哪个好用 编辑:程序博客网 时间:2024/05/01 05:13

在编译原理的前端部分最核心的便是语法分析,其主导着整个前端部分的编译工作。

按照编译器的结构来看,语法分析器的主要工作任务在于构造一棵语法分析树,并将其传给编译器的其他部分进行进一步的处理,但是在实际上,并不需要将语法分析树显示的构造出来,而是在遍历构造这棵语法树时直接通过语义动作等完成前端的任务,比如对源程序的检查、翻译动作等。总之,语法分析其可以和前端的其他部分用一个模块来实现,实际实践中也多是这样做的。


在前面的文章中以及提到了在语法分析中最常用的方法:上下文无关文法。在这里,给出上下文无关文法的完整定义:

一个上下文无关文法由终结符号集、非终结符号集、一个开始符号和一组产生式组成:终结符号是组成串的基本符号,在编译器中也就是从词法分析器中得到的词法单元的名字;非终结符号是表示串的集合的“语法变量”,定义由文法生成的语言,给吃了语言的层次结构,而这种层次结构是语法分析和翻译的关键;开始符号是一个选定的非终结符号;产生式是由终结和非终结符号组成串的方法。

有了上下文无关文法之后再说一下上下文无关语言,在这之前要说明三个概念:推导、句型和句子

推导:从开始符号出发,以产生式为重写规则,将非终结符号不断换为它的某个产生式的体,最终得到一个串;

句型:如果在推导中的到的串是终结符号和非终结符号都有,则成该串为该文法的一个句型;

句子:如果在推导中的到的串完全由终结符号构成,则称该串为该文法的一个句子;

我们将一个文法所有可以推导出的句子的集合称为这个上下文无关文法的上下文无关语言。

当然,在推导的时候有一个问题,便是我们应当选择句型中的哪一个非终结符号进行替换,有两种策略:

最左推导:总是选择每个句型的最左非终结符号;

最右推导:总是选择每个句型的最右非终结符号;

无论是最左推导还是最右推导,对于一个特定的上下文无关文法,每棵语法分析树都和唯一的最左推导和唯一的最右推导相对应,我们也常用最左或最右推导来进行语法分析。


再设计文法时,有几个问题需要注意,在前面的文章中也有部分提及,这里系统的总结一下:

二义性:一个文法可以是某个句子产生多可语法树,典型例子就是在设计表达式语法时,表达式中运算符的优先级问题如果不考虑从正确的话,会导致二义性,这个问题可以用因子,项和表达式的划分来解决;

左递归:在一个文法中存在形如A→Aα的推导时,称该文法是左递归的,其问题在于左递归的文法无法用自顶向下语法分析方法进行分析,因为回到一直做左递归而无法进行真正的语法分析。其解决方法是直接消除左递归,将上面的推导改为:A→βA‘,A'→αA’ | ε ;

提取左公因子:其目的不仅仅在于简洁,还是为了适用于预测分析法:其方法非常简单,类似于数学中的提取公因式,例如,A→αβ1|αβ2|αβ3,可以改为A→α A‘,A’→β1|β2|β3;

同时,对于文法设计中遇到的语言中和上午文有关的结构,放在编译前端的其他部分,如语义分析中去做,比如变量的声明等。


常用的两种语法分析方法:自顶向下的语法分析方法和自底向上的语法分析方法,基于篇幅这里就不多做赘述,但这两部分内容是很核心很重要的。


在很多时候,我们并不需要自己去写一个语法分析器,而是可以用语法分析器生成工具来代替我们完成这一任务,比如Yacc。具体的入门手册可以看

http://www.ibm.com/developerworks/cn/linux/sdk/lex/

0 0