编译器实践四 之 FIRST集合,NULLABLE集合,FOLLOW集合

闲来无事,就把龙书拿出来有看了看,把最近学的总结一下。

FIRST(X)集合定义:可从X推导得到的串的首符号的集合,其中X是任意文法符号。如果X=>······=>ε ,那么ε也在FIRST(X)中。(定义来自龙书)

算法伪代码(非准确版):

<span style="font-size:14px;">foreach(nonterminal N)
	FIRST(N) = {}
while(some set is changing)
	foreach (production p: N->β1 … βn)
	if (β1== a …)
		FIRST(N)∪= {a}
	if (β1== M …)
		FIRST(N)∪= FIRST(M)</span>

算法还是很好理解的,对于每一个产生式A->B1 B2···BN ,如果B1是终结符,则FIRST(A) U= {B1},若B1是非终结符则FIRST(A) U= FIRST(B1),这里用到了递归来求解。只要当前集合出现变化,第二层循环就再来一次,一直到没有集合都没有变化为止。这算一个不动点算法。

NULLABLE集合的归纳定义:

1基本情况:

X ->ε

2归纳情况:

X -> Y1 … Yn

Y1, …, Yn 是n个非终结符,且都属于NULLABLE集

算法伪代码:

<span style="font-size:14px;"></span><pre name="code" class="cpp">NULLABLE = {};
while (NULLABLE is still changing)
    foreach (production p: X-> β)
        if (β== ε)
            NULLABLE ∪= {X}
        if (β== Y1 … Yn)
            if (Y1∈ NULLABLE && … && Yn ∈NULLABLE)
                NULLABLE ∪= {X}

这个很好理解吧。

我们先不急看FOLLOW集合,再看看先前FIRST的伪代码吧,这哥伪代码粗略一看,感觉是对的,可是一细想,如果说B1是非终结符,但是如果B1->ε成立的话,那么是否要往后考虑一下?答案是正确的,这时还要FIRST(X) U= FIRST(B2),如果B2->ε仍然成立的话,继续FIRST(X)
U= FIRST(B3),,依次类推。

新的求FIRST集合伪代码:

foreach(nonterminal N)
	FIRST(N) = {}
while(some set is changing)
	foreach (production p: N->β1 … βn)
		foreach (βi from β1 upto βn)
			if (βi== a …)
				FIRST(N) ∪= {a}
				break
			if (βi== M …)
				FIRST(N)∪= FIRST(M)
				if (M is not in NULLABLE)
					break

接下来就是FOLLOW集合了:

对于非终结符号X,FOLLOW(A) 被定义为可能在某些句型中紧跟在X右边的总结符号集合。(定义来自龙书)

举个例子:如果存在S=>aBcd(a,b,d是文法符号串),这样c就在FOLLOW(B)中。

FOLLOW集的不动点算法:

<span style="font-size:14px;">foreach(nonterminal N)
	FOLLOW(N) = {}
while(some set is changing)
	foreach (production p: N->β1 … βn)
		temp = FOLLOW(N)
		foreach (βi from βn downto β1) // 逆序!
			if (βi== a …)
				temp = {a}
			if (βi== M …)
				FOLLOW(M)∪= temp
				if (M is not NULLABLE)
					temp = FIRST(M)
				else
					temp∪= FIRST(M)
</span>

好的,完成了这一步,我们就可以得到任意串的FIRST集合,

如下伪代码:

foreach(production p)
	FIRST_S(p) = {}
calculte_FIRST_S(production p: N->β1 … βn)
	foreach (βi from β1 to βn)
		if (βi== a …)
			FIRST_S(p)∪= {a}
			return;
		if (βi== M …)
			FIRST_S(p)∪= FIRST(M)
			if (M is not NULLABLE)
				return;
	FIRST_S(p)∪= FOLLOW(N)

好了,就总结到这里。

若有错误的地方,水平有限,还望指出。

谢谢

与君共勉

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-28 20:17:23

编译器实践四 之 FIRST集合,NULLABLE集合,FOLLOW集合的相关文章

Linux及安全实践四——ELF文件格式分析

Linux及安全实践四——ELF文件格式分析 一.ELF文件格式概述 1. ELF:是一种对象文件的格式,用于定义不同类型的对象文件中都放了什么东西.以及都以什么样的格式去放这些东西. 二.分析一个ELF文件 以一个最简单的helloworld程序为例 1. ELF文件头 使用工具查看ELF文件头:readelf -h obj 在/usr/include/elf.h中可以找到文件头结构定义: 大小总共为64字节,换算成十六进制为0x40.在十六进制代码中找到前0x40字节,即为文件头信息部分(阅

自己动手开发编译器(四)利用DFA转换表建立扫描器

上回我们介绍了两种有穷自动机模型——确定性有穷自动机DFA和非确定性有穷自动机,以及从正则表达式经过NFA最终转化为DFA的算法.有些同学表示还是难以理解NFA到底怎么转化为DFA.所以本篇开头时我想再多举一个例子,看看NFA转化为DFA之后到底是什么样.首先我们看下面的NFA,它是从一组词法分析所用的正则表达式转换而来的.这个NFA合并了IF.ID.NUM.error这四个单词的NFA.因此,它的四个接受状态分别代表遇到了四种不同的单词. 用上一篇学到的方法,我们需要求出一个DFA,它的每个状

Java集合(一):Java集合概述

注:本文基于JDK 1.7 1 概述 Java提供了一个丰富的集合框架,这个集合框架包含了许多接口.虚拟类和实现类.这些接口和类提供了丰富的功能,能够满足基本的聚合需求.下图就是这个框架的整体结构图: 可以看见,这个框架非常大,大到吃惊的地步.这个图的左面部分是接口,右面部分是类,中间的线代表了右面的类实现了左面的哪些接口.比如,AbstractList类实现了List接口,那么继承自AbstractList类的子类都实现了这个接口.还有,如果一个类实现了一个接口,那么这个类也实现了这个接口的所

C#泛型集合与非泛型集合_Felix(转自新浪博客)

在.NET FCL为我们提供了很多集合类型,是编程中非常有力的工具.泛型集合主要在System.Collections.Generic名称空间中,而非泛型集合主要在System.Collections,首先抛出结论:如果在C#2.0版本以上,尽量使用泛型集合类,而不使用非泛型集合类.因为,1.泛型编程是从c#2.0开始才被.net支持的.2.泛型集合在性能和类型安全方面优于非泛型集合. 非泛型集合-System.Collections名字空间中的类主要包括ArrayList, Hashtable

编写高质量代码改善C#程序的157个建议——建议20:使用泛型集合代替非泛型集合

建议20:使用泛型集合代替非泛型集合 在建议1中我们知道,如果要让代码高效运行,应该尽量避免装箱和拆箱,以及尽量减少转型.很遗憾,在微软提供给我们的第一代集合类型中没有做到这一点,下面我们看ArrayList这个类的使用情况: ArrayList al=new ArrayList(); al.Add(0); al.Add(1); al.Add("mike"); foreach (var item in al) { Console.WriteLine(item); } 上面这段代码充分演

5月11日 ArrayList集合复习、特殊集合、枚举类型

一.ArrayList集合复习 //定义 ArrayList al = new ArrayList(); //添加元素 al.Add(2); //插入元素 al.Insert(1,3); //查看个数 int a = al.Count;//count数数的意思 //清空集合 al.Clear(); //克隆一个集合 al.Clone(); //判断是否包含一个值 bool b = al.Contains("2"); //查看3第一个出现的索引号 int c = al.IndexOf(3

第14章 集合框架(1)-List集合的各种类

1.概述 1.1.Java集合框架的由来 1.2.什么是集合框架? 1.3.为什么需要集合框架 1.4.常用的框架接口规范 2.Vector类 2.1.存储原理 2.2.构造方法 2.3.常用方法 3.Stack类 3.1.什么是栈 3.2.栈的构造方法和常用方法 4.ArrayList类 5.LinkedList类 5.1定义 5.2.常用方法 1.概述 1.1.Java集合框架的由来 刚开始的时候java只有Vetor,Stack,Hashtable这些同容器类用来保存大量的对象.容器类是可

I学霸官方免费教程三十三:Java集合框架之Map集合

Map接口 Map集合采用键值对(key-value)的方式存储数据,其中键不可以重复.值可以重复. 常用类有HashMap.TreeMap和Properties HashMap类 假如,现在我有一个集合,集合中存储着一批WiFi的名称和密码,现在要求通过名称快速找到密码.这样的需求使用List集合实现起来非常困难,Java为我们提供了另一种形式的集合,可以很好的解决这样的问题.就是Map集合. 实例: package map.hashMap; import java.util.HashMap;

java集合体系与C#集合比较

集合框架是为表示和操作集合而规定的一种统一的标准的体系结构.任何集合框架都包含三大块内容:对外的接口.接口的实现和对集合运算的算法. java集合框架: 1. 什么是框架:类库的集合 2.集合框架:用来表示和操作的统一的架构,包含了实现集合的接口与类 3.集合:存放数据的容器 集合框架包含了两部分:一部分是接口,一部分是类 4.为什么会出现接口:因为集合框架中的很多类 功能是相似的[所以用接口来规范类] 主要结构图: 简化图 ollection 接口用于表示任何对象或元素组.想要尽可能以常规方式