(转载请表明出处 http://www.cnblogs.com/BlackWalnut/p/4472122.html )

  LL(K)语法分析技术是建立在预测分析的技术之上的。我们先来了解预测分析技术。考虑以下文法:

  

当使用该文法对(1*2-3)+4和(1*2-3)进行分析,前者因该调用E->E+T,而后者应该调用E->T,怎么确定到底使用哪个产生式呢?这就要使用预测分析技术来构建预测分析语法分析器,LL(k)是其一种。预测分析技术的关键是构建一个无冲突的预测分析表。所谓预测分析表就是程序可以根据当前的状态来查询该表,然后确定下一步使用哪个产生式。

  构建预测分析表要要用到两个集合,分别是first集合和follow集合。γ是终结符和非终结符组成的字符串,first(γ)是从γ中可以推到出的任意字符串中所包含的开头终结符所组成的集合。A是一个非终结符,follow(A)的意思可以直接跟在A后面的所有终结符的集合。这两个集合的求法可以描述为如下:

First集合的求法:

First集合最终是对产生式右部的字符串而言的,但其关键是求出非终结符的First集合,由于终结符的First集合就是它自己,所以求出非终结符的First集合后,就可很直观地得到每个字符串的First集合。

1.  直接收取:对形如U-a…的产生式(其中a是终结符),把a收入到First(U)中
2.  反复传送:对形入U-P…的产生式(其中P是非终结符),应把First(P)中的全部内容传送到First(U)中。  
    Follow集合的求法:
    Follow集合是针对非终结符而言的,Follow(U)所表达的是句型中非终结符U所有可能的后随终结符号的集合,特别地,“#”是识别符号的后随符。
1.反复传送:对形如U-…P的产生式(其中P是非终结符),应把Follow(U)中的全部内容传送到Follow(P)中2.  直接收取:注意产生式右部的每一个形如“…Ua…”的组合,把a直接收入到Follow(U)中。
3.直接收取:对形如“…UPA…”(P是非终结符)的组合,把First(P)直接收入到Follow(U)中。如果P的first集合包含由空(ε),则first(A)也要放入Follow(U)中。
  需要注意的是,空是只能在First集合中不能在follow集合中。
  从上面的求法中可以知道,其实first集合就是一个非终结符的等价终结符的可选集合,也就是说A可以直接推到出这些终结符,如果first集合可以为空,则说明A可以直接忽略,这个时候,为了预测A为空后的情形,我们构建了follow集合。可见,者两个完全是为了预测分析而产生的集合。
  预测分析表是一个二维表,用非终结符符标注每行,用终结符好标注每一列,根据这first和follow两个集合,我们使用如下规则构建一个预测分析表:从产生式集合中取出一个产生式A->γ,如果终结符a在first(γ)中,则讲A->γ放入(A,a)确定的位置中,如果γ可以为空且a在follow(A)中,也则讲A->γ放入(A,a)确定的位置中。这样我们根据文法以下文法得到其相应的预测分析表:
                           
                         
  如何使用这个分析表呢?要知道,我们所分析的数据是由词法分析其产生的,对于语法分析器而言,词法分析器产生的数据都是终结符。我们利用堆栈(用到堆栈的地方一般也可以用递归来解决,可以参考虎书英文版的第47页代码)来记录当前正在分析的非终结符,从词法分析器得到一个终结符a,以及栈顶的数据来查表,然后确定使用的产生式,如果产生式的右面有非终结符,将其从右到左压栈(保证每次从对产生式的最左面的非终结符开始推到,称为左推到),然后继续使用使用a对栈顶元素分析。直到找到一个产生式的右只包含终结符a,然后将a抛弃,重新读取新的终结符,继续分析。如果在过程中无法得到只包含终结符a的产生式,那么说明有语法错误。
  上面的算法过程就是一个预测分析过程我们称为LL(1)算法,第一个L是left to right parse,第二个L是leftmost derivation ,1是1-symbol lookahead.意思就是从左到右的分析词法分析器产生的数据,采用最左推到原则,每次只看超前查看一个终结符来确定后续动作。
  但是就对上面这张表而言,(Z,d)的位置有两个产生式,那么说明该文法是二义的,说明它是不是LL(K)文法。就不能使用预测分析技术来解析该语言,要使用功能更强大的LR(k)技术。
   这里介绍两种可能产生二义性的例子,第一个为左递归。查看下左图,因为first(T)正好是first(E+T)的子集合,所以,一定会产生冲突。我们使用右图来替换原来的产生式,称为消除左递归。
                                                          
  还有一种情况,我们解决的办法称为提取右因子。
                                                          
  以上就是LL(K)文法的全部,相比LR(k)文法,它的功能不够强大(我们在LR(K)中进行比较),但是想要构造一个预测分析表却十分的简单。对于某些LR(k)处理不了的情况,我们可以快速的建立相应的LL(K)分析表来解决。
  

现代编译原理--第二章(语法分析之LL(K))的更多相关文章

  1. 现代编译原理——第二章:语法分析之LL(K)

    转自: http://www.cnblogs.com/BlackWalnut/p/4472122.html LL(K)语法分析技术是建立在预测分析的技术之上的.我们先来了解预测分析技术.考虑以下文法: ...

  2. Java 实现《编译原理》简单-语法分析功能-LL(1)文法 - 程序解析

    Java 实现<编译原理>简单-语法分析功能-LL(1)文法 - 程序解析 编译原理学习,语法分析程序设计 (一)要求及功能 已知 LL(1) 文法为: G'[E]: E→TE' E'→+ ...

  3. 编译原理学习笔记·语法分析(LL(1)分析法/算符优先分析法OPG)及例子详解

    语法分析(自顶向下/自底向上) 自顶向下 递归下降分析法 这种带回溯的自顶向下的分析方法实际上是一种穷举的不断试探的过程,分析效率极低,在实际的编译程序中极少使用. LL(1)分析法 又称预测分析法, ...

  4. 编译原理根据项目集规范族构造LR(0)分析表

    转载于https://blog.csdn.net/Johan_Joe_King/article/details/79058597?utm_medium=distribute.pc_relevant.n ...

  5. 编译原理LR(0)项目集规范族的构造详解

    转载于https://blog.csdn.net/johan_joe_king/article/details/79051993#comments 学编译原理的时候,感觉什么LL(1).LR(0).S ...

  6. 第二章 Javac编译原理

    注:本文主要记录自<深入分析java web技术内幕>"第四章 javac编译原理" 1.javac作用 将*.java源代码文件转化为*.class文件 2.编译流程 ...

  7. 跟vczh看实例学编译原理——三:Tinymoe与无歧义语法分析

    文章中引用的代码均来自https://github.com/vczh/tinymoe.   看了前面的三篇文章,大家应该基本对Tinymoe的代码有一个初步的感觉了.在正确分析"print ...

  8. 《编译原理》-用例题理解-自顶向下语法分析及 FIRST,FOLLOW,SELECT集,LL(1)文法

    <编译原理>-用例题理解-自顶向下语法分析及 FIRST,FOLLOW,SELECT集,LL(1)文法 此编译原理确定某高级程序设计语言编译原理,理论基础,学习笔记 本笔记是对教材< ...

  9. 《编译原理》-用例题理解-自底向上的语法分析,FIRSTVT,LASTVT集

    <编译原理>-用例题理解-自底向上的语法分析,FIRSTVT,LASTVT集 上一篇:编译原理-用例题理解-自顶向下语法分析及 FIRST,FOLLOW,SELECT集,LL(1)文法 本 ...

  10. C语言编程入门之--第二章编译环境搭建

    第二章 编译环境搭建 导读:C语言程序如何工作,首先需要编译链接成可执行文件,然后就可以运行在不同的环境中,这个“环境”的意思就是比如说,电脑,手机,路由器,蓝牙音箱等等智能设备中,其中编译器启到了关 ...

随机推荐

  1. [综] meanshift算法

    Meanshift,聚类算法 http://www.cnblogs.com/liqizhou/archive/2012/05/12/2497220.html 记得刚读研究生的时候,学习的第一个算法就是 ...

  2. DDR3初识

    DDR3初识 选择2:1 ratio 意味用户总线宽度为DDR物理数据接口宽度的4倍.

  3. AsyncTask(异步任务)

    一.AsyncTask ①AsyncTask的源码: public abstract class AsyncTask<Params, Progress, Result> 三种泛型类型分别代 ...

  4. [UE4]CheckBox

    一.CheckBox默认情况下是比较小的 二.要让CheckBox变大,最简单的方法就是直接设置Transform.Scale,但如此一来CheckBox就变得模糊了. 三.CheckBox控件是在C ...

  5. vuex状态管理-数据改变不刷新

    困惑: 在页面初始化的时候,我提交到vuex状态管理,然后在获取的时候获取不到,我找到了出错的地点,并进行了修改,然后可以获取到状态 但是不知道原因? 定义了如下的state const state ...

  6. 边缘触发(Edge Trigger)和条件触发(Level Trigger)

    int select(int n, fd_set *rd_fds, fd_set *wr_fds, fd_set *ex_fds, struct timeval *timeout);     sele ...

  7. 用户名、密码等15个常用的js正则表达式

    本文收集整理了15个常用的javaScript正则表达式,其中包括用户名.密码强度.整数.数字.电子邮件地址(Email).手机号码.身份证号.URL地址. IPv4地址. 十六进制颜色. 日期. Q ...

  8. 执行webpack-dev-server时,提示端口被占用。

    执行webpack-dev-server时总出错,提示端口被占用.百度了很多答案都不能解决,最后找到了解决方案,如下: webpack-dev-server  --port 8088 使用以上命令修改 ...

  9. 序列化与反序列化之Kryo

    序列化:把对象转换为字节序列的过程称为对象的序列化. 反序列化:把字节序列恢复为对象的过程称为对象的反序列化. 需要序列化的情况: 当你想把的内存中的对象状态保存到一个文件中或者数据库中时候: 当你想 ...

  10. kettle数据库连接使用变量

    新增db连接(密码也可以设置参数) 转换中,右键空白处,选择转换设置