TINYC编译器的设计与实现语法分析器的设计与实现.docx
《TINYC编译器的设计与实现语法分析器的设计与实现.docx》由会员分享,可在线阅读,更多相关《TINYC编译器的设计与实现语法分析器的设计与实现.docx(46页珍藏版)》请在冰点文库上搜索。
TINYC编译器的设计与实现语法分析器的设计与实现
Contents
TINY—C编译器的设计与实现
—--语法分析器的设计与实现
摘要
编译器是将一种源语言翻译为目标语言的计算机程序。
本项目采用一种类(ANSI)C的小型语言:
TINY语言作为源语言,构造TINY语言的编译器。
项目由三人共同完成,其中本人主要是完成了语法分析器的构造,主要工作如下:
研究语法分析器的设计原理,并对几种典型的语法分析算法进行分析.生成TINY文法,并证明该文法为LL
(1)文法,在此基础上,选择递归下降算法实现TINY语法分析.最终实现了一个TINY语法分析器,它以词法分析器所产生的记号为输入,采用递归下降分析程序进行语法分析,并输出语法树作为下阶段编译的输入。
我们最后构造了一个Dephi接口程序,显式输出抽象语法树。
关键词:
编译器TINY记号语法分析语法树
Tiny—CComplierdesignandrealization
--—Syntaxanalyzerdesignandrealization
RenJun
Abstract
Thecompilerisacomputerprogramwhichtranslatesthesourcelanguageintothetargetlanguage。
Thisprojectusesalanguagesimilarto(ANSI)C:
UsingtheTINYlanguageasthesourcelanguagetoconstructthecompilerofTINY.Thewholeprocessoftheprojectisfinishedbythejointeffortofthreepeople,andImyselfmainlycompletedthestructureofsyntaxanalyzer。
Themajorworkisasfollows:
Analyzingthedesigningprinciplesofthesyntaxanalyzer,andseveralkindsoftypicalparsingalgorithm.ProducingtheTINYgrammar,provingthisgrammarisLL
(1)grammar,andinthisfoundation,choosingrecursiondropalgorithmtorealizetheTINYgrammaranalysis。
ATINYgrammaranalyzerhasthusbeenaccomplished.Itappliesthesymbolswhichareproducedbythemorphologyanalyzerastheinput,andusestherecursiondropanalysisprogramtocarryonthegrammaranalysis,thenoutputthesyntaxtreeastheinputfornextcompilingphase’sinput.WestructuredaDephiinterfaceroutineatlasttodisplaytheabstractsyntaxtree.
Keyword:
Compiler,TINY,Token,Syntaxanalysis,Syntaxtree
1.前言
系统概述
在计算机上执行一个高级语言程序一般要分为两步:
第一步,用一个编译程序把高级语言翻译成机器语言程序;第二步:
运行所得的机器语言程序求得计算结果.通常所说的翻译程序是指这样的一个程序,它能够把某一种语言程序转换成另一种语言程序,而后者与前者在逻辑上是等价的。
语法分析器,简称分析器,对单词符号串进行语法分析(根据语法规则进行推导或规约),识别除各类语法单位,最终判断输入串是否构成语法上的正确的”程序”.
词法分析器
目标代码生成器
语法分析器
词义分析和中间代码产生器
优化器
表格管理
错误处理
目标代码
中间代码
中间代码
语法单位
单词符号
源程序
图1-1编译程序框
TINY语言的概述
TINY的程序结构很简单,它在语法上和Pascal的语法相似:
仅是一个由分号分隔开的语句序列。
另外,它既无过程也无声明。
所有的变量都是整型变量,通过对其赋值可较轻易地声明变量(类似FORTRAN或BASIC)。
它只有两个控制语句:
if语句和repeat语句,这两个控制语句本身也可包含语句序列。
If语句有一个可选的else部分且必须由关键字end结束.除此之外,read语句和write语句完成输入/输出.在花括号中可以有注释,但注释不能嵌套.
2.语法分析器的设计原理
2.1语法分析器的功能
语法分析是编译过程的核心部分。
它的任务是在词法分析识别出单词符号串的基础上,分析并判定程序的语法结构是否符合语法规则.语法分析器在编译程序中的地位如图1。
1所示。
词法分析
语法分析器
编译后续部分
单词符号
取下一个单词符号
语法分析树
图2。
1语法分析器在编译程序中的地位
2.2语法分析的目标和作用
1)语法分析的目标是确定程序的语法,或称作结构,也正是这个原因,它又被称作语法分析(syntaxanalysis)。
2)分析过程
分析程序的任务是从由扫描程序产生的记号中确定程序的语法结构,以及或隐式或显式地构造出表示该结构的分析树或语法树。
因此,可将分析程序看作一个函数,该函数把由扫描程序生成的记号序列作为输入,并生成语法树作为它的输出:
记号序列语法树。
2.3构造语法分析器的步骤
a写出文法
b根据文法选择合适的分析算法。
C实现算法
2。
4上下文无关文法及分析
实际上,几乎所有程序设计语言都是通过上下文无关文法来定义的。
另一方面,上下文无关文法又足够简单,使得我们可以构造有效的分析算法来检验一个给定字串是否是由某个上下文无关文法产生的。
1)上下文无关文法定义
在计算机科学中,一个形式文法G=(NΣPS)称之为上下文无关的,如果它的产生式规则都取如下的形式:
V->w,这里V∈N,w∈(N∪Σ)*.上下文无关文法取名为“上下文无关"的原因就是因为字符V总可以被字串w自由替换,而无需考虑字符V出现的上下文。
一个形式语言是上下文无关的,如果它是由上下文无关文法生成的﹙条目上下文无关语言﹚。
上下文无关文法重要的原因在于它们拥有足够强的表达力来表示大多数程序设计语言的语法;BNF﹙巴克斯—诺尔范式﹚经常用来表达上下文无关文法。
2)上下文无关文法规则
上下文无关文法规则确定了为由规则定义的结构的记号符号符合语法的串集.文法规则通过推导确定记号符号的正规串。
推导(derivation)是在文法规则的右边进行选择的一个结构名字替换序列。
推导以一个结构名字开始并以记号符号串结束。
在推导的每一个步骤中,使用来自文法规则的选择每一次生成一个替换。
3)上下文无关文法的形式定义
定义上下文无关文法由以下各项组成:
(1)终结符(terminal)集合T。
(2)非终结符(nonterminal)集合N(与T不相交)。
(3)产生式(production)或文法规则(grammarrule)A→a的集合P,其中A是N的一个元素,a是(TÈN)*中的一个元素(是终结符和非终结符的一个可为空的序列)。
(4)来自集合N的开始符号(startsymbol)。
令G是一个如上所定义的文法,则G=(T,N,P,S)。
G上的推导步骤(derivationstep)格式aAgÞabg,其中a和g是(TÈN)*中的元素,且有A→b在P中(终结符和非终结符的并集,有时被称作G的符号集,setofsymbol),且(TÈN)*中的串a被称作句型(sententialform))。
将关系aÞ*b定义为推导步骤关系Þ的传递闭包;也就是:
假若有零个或更多个推导步骤,就有aÞ*b(n≥0)a1Þa2Þ⋯Þan-1Þan其中a=a1,b=an(如果n=0,则a=b)。
在文法G上的推导(derivation)形如SÞ*w,且wÎT*(即:
w是终结符的一个串,称作句子(sentence)),S是G的开始符号。
由G生成的语言(languagegeneratedbyG)写作L(G),它被定义为集合L(G)={wÎT*|存在G的一个推导SÞ*w},也就是:
L(G)是由S推导出的句子的集合。
最左推导(leftmostderivation)SÞ*w是一个推导,在其中的每一个推导步骤aAgÞabg都有aÎlmT*,换言之,a仅由终结符组成。
类似地,最右推导(rightmostderivation)就是每一个推导步骤aAgÞabg都有属性gÎT*。
文法G上的分析树(parsetree)是一个带有以下属性的作了标记的树:
(1)每个节点都用终结符、非终结符或标出。
(2)根节点用开始符号S标出。
(3)每个叶节点都用终结符或标出。
(4)每个非叶节点都用非终结符标出。
(5)如带有标记AÎN的节点有n个带有标记X1,X2,。
..Xn的孩子(可以是终结符也可以是非终结符),就有A→X1,X2,。
..XnÎP(文法的一个产生式)。
每一个推导都引出一个分析树,这个分析树中的每一个步骤aAgÞabg都在推导中,且b=X1,X2,。
.。
Xn与带有标记X1,X2,。
。
.Xn的n个孩子的结构相对应,其中X1,X2,。
..Xn带有标记A.许多推导可引出相同的分析树。
但每个分析树只有唯一的一个最左推导和一个最右推导。
最左推导与分析树的前序编号相对应,而与之相反,最右推导与分析树的后序编号相对应。
若上下文无关文法G有L=L(G),就将串L的集合称作上下文无关语言(context-freelanguage)。
一般地,许多不同的文法可以生成相同的上下文无关语言,但是根据所使用的文法的不同,语言中的串也会有不同的分析树。
若存在串wÎL(G),其中w有两个不同的分析树(或最左推导或最右推导),那么文法G就有二义性(ambiguous)。
2.5常用的语法分析方法和几种算法的比较
语言的语法结构是用上下文无关文法描叙的.因此,语法分析器的工作本质上就是按文法的产生式,识别输入符号串(指由单词符号组成的有限序列)是否为一个句子.对于一个文法,当给出一串符号时,怎么知道它是不是该文法的一个句子(“程序")?
就要从文法的开始符号出发推导出这个输入串,也就是要建立一个与输入串相匹配的语法分析树.
按照语法分析树的建立方法,可以将语法分析办法分成两类,一类是自上而下分析法,另一类是自下而上分析法。
2.5.1自上而下分析法
1)定义:
从文法的开始符号出发,向下推导,推出句子.
2)优点:
符合人的思想,比较容易理解
3)缺点:
a)文法的左递归性问题,因此使用自上而下分析发必须消除文法的左递归性。
b)回溯问题
c)虚假匹配
d)效率低,代价高
e)难于确定出错位置
f)只适合LL
(1)文法
*注释:
LL
(1)文法:
一个文法G,若它的分析表M不含多重定义入口,则被称为LL为
(1)文法.LL
(1)中的第一个“L”意味着自左而右地扫描输入,第二个“L”意味着生成一个最左推导,并且“1”意味着为做出分析动作的决定,在每一步利用一个向前看符号,一个文法G是LL
(1)的,那么必须满足:
1)文法不含左递归
2)对于文法的每一个非终结符A的各个产生式的候选首符集两两不相交。
即:
FIRST(α)∩FIRST(β)=Φ;它们不应该都能推出空字ε;
3)对于文法中的每个非终结符A,若它存在某个候选首符集包含ε。
即:
假若β包含ε,那么,FIRST(α)∩FOLLOW(A)=Φ。
4)主要算法
A.递归下降分析程序
定义:
若一个文法G不含有左递归,而且每个非终结符的所有候选式的首符集都是两两不相交的,那么就能为G中每个非终结符编写一个相应的递归过程.把该文法中所有这样的递归过程组合起来就可能构成一个不带回溯的自上而下分析程序—-递归下降分析程序。
实现思想:
为文法中每个非终结符编写一个递归过程,每个过程的功能是识别由该非终结符推出的串,当某非终结符的产生式有多个候选式时,按LL
(1)形式唯一确定选择哪个候选式进行推导,若遇到某候选式为e,认为其自动匹配。
把这些递归过程组合起来就构成了文法的递归下降分析程序。
实现方法:
a)使用LL
(1)文法
先将文法消除左递归、提取公共左因子,使之成为LL
(1)文法,后将每个非终结符对应一个递归过程,过程体是按照相应产生式的右部符号串顺序编写.每匹配一个终结符,则再读入下一个符号,对产生式右部的每个非终结符,则调用相应的过程.
b)使用BNF范式
先将文法改写为BNF形式,后再书写递归子程序.
优点:
容易理解.
缺点
a)对文法的要求高,必须满足LL
(1)文法。
b)高深度的递归调用会影响语法分析的效率,速度慢,占空间多。
B.预测分析程序
定义:
使用高级语言的递归过程描述递归下降分析器,只有当具有实现这种过程的编译系统时才有实际意义。
实现LL
(1)分析的另一种有效方式是使用一张分析表和一个栈进行联合控制。
实现思想:
预测分析程序就是属于这种类型的LL
(1)分析器。
实现方法:
构造分析表和栈,设栈顶符号为X,读入符号为a,则
a)若X=a=‘#’,则表示识别成功,退出分析程序;
b)若X=a¹’#',则表示匹配,弹出栈顶符号X,读头前进一格,让读头指向下一个符号,以读入下一个符号;若X是终结符,但X¹a,则调用error处理;
c)若XÎVN,则查预测分析表M.若M[X,a]中存放着关于X的产生式,则弹出X,且将相应产生式右部以自右向左的顺序压入栈,在输出带上记下产生式编号;若M[X,a]中存放着出错标记,则调用相应Error处理。
优点:
过程比递归分析的效率高,速度快,占空间少,仅用表结构。
缺点:
对文法的要求高,必须满足LL
(1)文法。
2。
5。
2自下而上分析法
1)定义:
所谓自下而上分析法就是从输入串开始,逐步进行“规约”,直至规约到文法的开始符号;或者说从语法树的末端开始,步步向上“规约",直到根结.
2)优点:
从输入符号串开始分析开始分析,因此进行语法分析和进行语义分析可以在一遍内进行,而自上而下的分析法是从根节点开始进行语法分析,因此必须先经过一遍扫描建立语法树,让后再经过一遍扫描进行语法分析.因此自下而上的分析法效率更高。
3)缺点:
和人的思想相反,不容易理解,算法更复杂。
4)主要算法
A.算符优先分析法
定义:
定义算符之间(确切地说,终结符之间)的某种优先关系,借助于这种优先关系寻找“可归约串"和进行归约。
实现思想:
优先表构造优先函数,寻找最作素短语。
(设G是一个算符文法,β是句型baδ关于A的短语(即有S-〉αAδ且A-〉β)且β至少含有一个终结符号,并且除自身之外不再含有任何更小的带有终结符号的短语,则称β是句型αβδ关于A的素短语.所谓最左素短语是指处于句型最左边的那个素短语.)
实现方法:
算符优先分析法自底向上地分析句子,解决了前面提到的两个问题,即:
1)可以只根据相邻运算符的优先关系,就能方便地并且唯一地确定归约的“句柄”;
2)可以用来分析二义性文法所产生的语言。
是仿照算术表达式的四则运算过程而设计的一种语法分析方法.
终结符号运算符
非终结符号运算对象
算符优先分析法的关键在于用合适的方法去定义任何两个可能相继出现的结符号a和b(它们之间可能插有一个非终结符号)之间的优先级。
然后利用这种关系比较相邻运算符之间的优先级来确定可归约串并进行归约.
终结符号a与b之间的优先关系有三种:
a<·b表示a的优先级低于b
a≡b表示a的优先级等于b
a·>b表示a的优先级大于b
优点:
a)有利于表达式分析,宜于手工实现。
b)使用优先表,只对算符优先比较,占用的存储量比较小,速度快.
缺点:
a)可能错误接受非法句子,能力有限
b)要求文法必须是算符优先文法,这个条件比较苛刻.
B.LR算法
定义:
从左到右扫描输入串.并且构造一个最右推导的逆过程。
实现思想与方法:
LR分析的核心部分是一张分析表。
这张分析表包括两部分,一是“动作”(ACTIOB)表,另一是“状态转换"(C0m)表.它们都是二维数组.
优点:
对文法要求较低,适合大部分文法。
缺点:
算法比算符优先法复杂,占用资源较多,速度较慢。
3.语法分析器的设计和实现
3.1TINY语言的介绍
1)TINY的程序结构是一个由分号分隔开的语句序列。
2)既无过程也无声明。
3)所有的变量都是整型变量,通过对其赋值可较轻易地声明变量.
4)只有两个控制语句:
if语句和repeat语句,这两个控制语句本身也可包含语句序列。
If语句有一个可选的else部分且必须由关键字end结束。
5)read语句和write语句完成输入/输出.
6)TINY的表达式只有布尔表达式和整型算术表达式。
布尔表达式由对两个算术表达式的比较组成,该比较使用〈与=比较算符.算术表达式可以包括整型常数、变量、参数以及4个整型算符+、-、*、/,此外还有一般的数学属性。
例子:
一个输出其输入阶乘的TINY语言程序
readx;{inputaninteger}
if0fact:
=1;
repeat
fact:
=fact*x;
x:
=x—1
untilx=0;
writefact{outputfactorialofx}
end
3。
2TINY的文法生成
由TINY语言介绍中的第一条可知TINY程序由分号分隔开的语句序列构成,其文法表示如下:
program—〉stmt-sequence
stmt—sequence->stmt-sequence;statement|statement
program表示程序,stmt-sequence表示语句序列,statement表示语句
由TINY语言介绍中的第2,3,4,5条可知语句分为赋值语句、if语句、repeat语句、read语句和write,其文法表示如下:
statement—〉if-stmt;repeat-stmt;assign—stmt;read-stmt;write—stmt
(语句)(if语句)(循环语句)(赋值语句)(读语句)(写语句)
A)if语句(if—stmt)
而if语句有两种形式:
a)if表达式then语句序列end
例如:
ifx〈0theny:
=1end
b)if表达式then语句序列else语句序列end
例如:
ifx<0theny:
=1elsey:
=0end
由此可得if语句的文法为:
(exp表示参考量)
if-stmt-〉ifexpthenstmt-sequenceend
|ifexpthenstmt—sequenceelsestmt—sequenceend
B)循环语句(repeat—stmt)
循环语句语句的形式为:
repeat语句序列until表达式
例如:
repeat
fact:
=fact*x;
x:
=x—1
untilx=0;
由此可得循环语句语句的文法为:
repeat-stmt->repeatstmt-sequenceuntilexp
C)赋值语句(assign-stm)
由3可知赋值语句的左边为变量(标识符),右部为表达式.
形式为:
变量:
=表达式|值
例如:
x:
=x-1
由此可得赋值语句的文法为:
assign—stmt—>identifier:
=exp
D)读写语句(read—stmt和write—stmt)
读写语句形式为:
读出变量|写入变量
例如:
readx;{inputaninteger}
writefact{outputfactorialofx}
由此可得读写语句的文法为:
read-stmt—>readidentifier
write-stmt-〉writeexp
E)布尔表达式和整型算术表达式
表达式的要求:
表达式满足优先顺序,优先顺序从低到高为:
比较运算符〈和=→加和减→乘和除→括号
算术运算是左结合,布尔表达式由对两个算术表达式的比较组成,无结合关系.
为了满足以上优先关系,我们可以认为表达式为布尔表达式和算术表达式两种,而布尔表达式由对两个算术表达式的比较组成,这样,比较运算将最后进行,因此比较运算的优先级最低.
exp—〉simple—expcomparison-opsimple-exp|simple—exp
comparison-op—>〈|=
类似的,算术表达式由加法项(term表示)构成。
这时,加减法在算术运算中最后进行,因此在算术运算中加减法的优先级最低。
另外加减法必须满足左结合原则,因此递归项simple-exp置于产生式右部的最左边。
simple-exp-〉simple—expaddopterm|term
addop—〉+|—
依此类推,我们可以得到表达式的文法如下所示:
exp—>simple-expcomparison-opsimple—exp|simple-exp
comparison-op->〈|=
simple—exp-〉simple—expaddopterm|term
addop-〉+|—
term—>termmulopfactor|factor
mulop—〉*|/
factor—>(exp)|number|identifier
其中,exp表示表达式,simple-exp表示算术表达式term表示加法项,mulop表示乘除项,factor表示其他因子(数字或标示符)
综上所述,可以得到下图TINY的文法如图2-1所示:
program-〉stmt—sequence
stmt—sequence-〉stmt-sequence;statement|statement
statement-〉if—stmt;repeat-stmt;assign—stmt;read-stmt;write—stmt
if-stmt->ifexpthenstmt-sequenceend
|ifexpthenstmt—sequenceelsestmt—sequenceend
repeat—stmt-〉repeatstmt