语法树学习总结

来源:互联网 发布:淘宝神笔我的模块批量 编辑:程序博客网 时间:2024/04/29 18:36

语法树



语法树是句子结构的图形表示,它代表了句子的推导结果,有利于理解句子语法结构的层次。简单说,语法树就是按照某一规则进行推导时所形成的树。
中文名 语法树 外文名 Parse Tree 文    法 G=(Vn,Vt,P,S) 性    质 计算机语言 释    义 一个句型的所有可能的推导过程
目录
1 简介
2 详细信息
简介
给定文法G=(Vn,Vt,P,S),对于G的任何句型都能构造与之关联的语法树(推导树)。树中的每一个节点都有一个标记,此标记是V= Vn∪Vt中的一个符号。语法树是句子结构的图形表示,它代表了句子的推导结果,有利于理解句子语法结构的层次。简单说,语法树就是按照某一规则进行推导时所形成的树。
对应关系
对应关系
一棵语法树包括了一个句型的所有可能的推导过程。
详细信息
这个语法树满足:
(1) 树中每一个结点都有一个标记,此标记是V= VN∪VT中的一个符号。
(2) 根的标记是S。
(3) 若树的一结点A至少有一个子女,则A∈VN。
(4) 如结点A的子女结点从左到右次序为B1,B2...Bn,则必有产生式A→B1B2...Bn。
例:G[S]: S→aAS | a
A→SbA |SS |ba
对句型aabbaa的推导过程可表示为下图所示语法树。
语法树
语法树
下面两个推导过程均可由右图表示。
(1) SÞaASÞaSbASÞaabASÞaabbaSÞaabbaa
(2) SÞaASÞaAaÞaSbAaÞaSbbaaÞaabbaa
这说明同一语法树可以表示对同一句型不同的推导过程。
========

编译原理学习周入门教程--(5)上下文无关文法,及其语法树

 
         首先我们回顾一下上篇的内容,上篇讲述了四种类型的文法,0型1型2型3型,他们要求的规则越来越严格。
 
         开始教程:
 
         本篇着重讲解上下文无关文法及其语法树,因为对于计算机程序来讲,上下文无关文法表达能力足够强,来表达大多数程序语言的语法。
 
         描述一种上下文无关的推导工具:句型的推导和语法树(推导树)
 
          给定文法G(VN,VT,P ,S),对于G的任何句型都能构造与之关联的语法树。这棵树满足下面四个条件:
 
           ① 每个结点都有一个标记,此标记是V的 一个符号。(说的是节点一定是终结符或非终结符)


           ② 根的标记是S。(说的是树根的标记是开始符号S)


           ③ 若一结点标记A,至少有一个从它出发的分枝,则A肯定在VN中(说的是如果一个节点有分支的话,这个节点一定是非终结符)


           ④ 如果标记为A,有n个从它出发的分枝,并且这些分枝的结点的标记(从左到右)为B1, B2,…,Bn,那么A→B1B2,…,Bn一定是P中的一个产生式。(说的是从A出发的叶子节点从左到右排列,一定是P中规则的一个产生式)
 
         例1: 文法G[S]:


          S→aAS
          A→SbA
          A→SS
          S→a
          A→ba


  写出aabbaa句型的推导过程:
  (1)S=>aAS=>aAa=>aSbAa=>aSbbaa=>aabbaa(最右推导)(最右推导,就是从最右侧的非终结符开始)
  (2)S=>aAS=>aSbAS=>aabAS=>aabbaS=>aabbaa(最左推导)(最左推导,就是从最左侧的非终结符开始)        


          例2: G[E]:        E→E+T|T
                      T→T*F|F
                      F→(E)|a
                      判断a+a*a         是否是合法的句子,采用最左推导和最右推导
 
    E=>E+T=>T+T=>F+T=>a+T=>a+T*F
                 =>a+F*F=>a+a*F=>a+a*a(最左推导)
 
    E=>E+T=>E+T*F=>E+T*a=>E+F*a
                 =>E+a*a=>T+a*a=>F+a*a=>a+a*a(最右推导)
 
               书上规定,最右推导又称为规范推导,规范推导推导出的句型又称为规范句型。
 
               构造上述句型的语法树:
 
                画出a+a*a句型的语法树            
                  E→E+T|T 
                  T→T*F|F
                  F→(E)|a                 
 
                注:上面的例子来自网络。
 
        而一个语法树可以表示可能的不同推导过程,包括最右推导和最左推导。但是一个句型是否对应唯一的一颗语法树呢?一个句型是否只有唯一的一个最左推导(最右推导)?答案是否定的,下面我们讲述二义文法。
 
                看看下面的文法推导树:                 
 
                      二义文法的定义:
 
                      若一个文法存在某个句子对应两棵不同的语法树,则称这个文法是二义的,或一个文法有两个不同的最左推导,则称这个文法是二义的。
 
                     当然我们不希望程序的某些文法是二义的,希望对程序的每个句子的分析是唯一的。
  
本篇到此结束,下篇讲述句型的简单分析。
========

Redy语法分析--抽象语法树简介



抽象语法树简介


(一)简介


抽象语法树(abstract syntax code,AST)是源代码的抽象语法结构的树状表示,树上的每个节点都表示源代码中的一种结构,这所以说是抽象的,是因为抽象语法树并不会表示出真实语法出现的每一个细节,比如说,嵌套括号被隐含在树的结构中,并没有以节点的形式呈现。抽象语法树并不依赖于源语言的语法,也就是说语法分析阶段所采用的上下文无文文法,因为在写文法时,经常会对文法进行等价的转换(消除左递归,回溯,二义性等),这样会给文法分析引入一些多余的成分,对后续阶段造成不利影响,甚至会使合个阶段变得混乱。因些,很多编译器经常要独立地构造语法分析树,为前端,后端建立一个清晰的接口。


抽象语法树在很多领域有广泛的应用,比如浏览器,智能编辑器,编译器。


(二)抽象语法树实例


(1)四则运算表达式


表达式: 1+3*(4-1)+2


抽象语法树为:


(2)xml


代码2.1:


<letter>
  <address>
    <city>ShiChuang</city>
  </address>
  <people>
    <id>12478</id>
    <name>Nosic</name>
  </people>
</letter>
抽象语法树


(3)程序1


代码2.2


while b != 0
{
    if a > b
        a = a-b
    else
        b = b-a
}
return a
抽象语法树


(4)程序2


代码2.3


sum=0
for i in range(0,100)
    sum=sum+i
end
抽象语法树


(三)为什么需要抽象语法树


当在源程序语法分析工作时,是在相应程序设计语言的语法规则指导下进行的。语法规则描述了该语言的各种语法成分的组成结构,通常可以用所谓的前后文无关文法或与之等价的Backus-Naur范式(BNF)将一个程序设计语言的语法规则确切的描述出来。前后文无关文法有分为这么几类:LL(1),LR(0),LR(1), LR(k) ,LALR(1)等。每一种文法都有不同的要求,如LL(1)要求文法无二义性和不存在左递归。当把一个文法改为LL(1)文法时,需要引入一些隔外的文法符号与产生式。


例如,四则运算表达式的文法为:


文法1.1


E->T|EAT
T->F|TMF
F->(E)|i
A->+|-
M->*|/
改为LL(1)后为:


文法1.2


E->TE'
E'->ATE'|e_symbol
T->FT'
T'->MFT'|e_symbol
F->(E)|i
A->+|-
M->*|/
例如,当在开发语言时,可能在开始的时候,选择LL(1)文法来描述语言的语法规则,编译器前端生成LL(1)语法树,编译器后端对LL(1)语法树进行处理,生成字节码或者是汇编代码。但是随着工程的开发,在语言中加入了更多的特性,用LL(1)文法描述时,感觉限制很大,并且编写文法时很吃力,所以这个时候决定采用LR(1)文法来描述语言的语法规则,把编译器前端改生成LR(1)语法树,但在这个时候,你会发现很糟糕,因为以前编译器后端是对LL(1)语树进行处理,不得不同时也修改后端的代码。


抽象语法树的第一个特点为:不依赖于具体的文法。无论是LL(1)文法,还是LR(1),或者还是其它的方法,都要求在语法分析时候,构造出相同的语法树,这样可以给编译器后端提供了清晰,统一的接口。即使是前端采用了不同的文法,都只需要改变前端代码,而不用连累到后端。即减少了工作量,也提高的编译器的可维护性。


抽象语法树的第二个特点为:不依赖于语言的细节。在编译器家族中,大名鼎鼎的gcc算得上是一个老大哥了,它可以编译多种语言,例如c,c++,java,ADA,Object C, FORTRAN, PASCAL, COBOL等等。在前端gcc对不同的语言进行词法,语法分析和语义分析后,产生抽象语法树形成中间代码作为输出,供后端处理。要做到这一点,就必须在构造语法树时,不依赖于语言的细节,例如在不同的语言中,类似于if-condition-then这样的语句有不同的表示方法


在c中为:


if(condition)
{
    do_something();
}
     在fortran中为:


If condition then
    do_somthing()
end if
在构造if-condition-then语句的抽象语法树时,只需要用两个分支节点来表于,一个为condition,一个为if_body。如下图:


在源程序中出现的括号,或者是关键字,都会被丢掉。
========
0 0