第三章 语法分析 LL分析算法

合集下载

实验原理ll1分析法

实验原理ll1分析法

实验原理ll1分析法
LL(1)分析法是一种语法分析方法,是从上到下递归分析的一种方式。

LL指的是“Left to right, leftmost derivation”,表示从左到右、最左派生。

1表示在当前读入符号下,只需要向前看一个符号即可确定使用哪个产生式进行推导。

其核心思想是通过预测分析表来进行语法分析,预测分析表是一个二维数组,横坐标是非终结符号,纵坐标是终结符号。

在分析过程中,根据当前读入的终结符号和栈顶的非终结符号,查找分析表中对应的表项,判断使用哪个产生式进行推导。

如果表项为空,则表示当前输入串不符合语法规则。

LL(1)分析法的优点是实现简单、可自动化,同时可以处理大部分常见的上下文无关文法,且分析的速度较快,适合在语法分析器中应用。

缺点是只能处理LL(1)文法,对于LL(k)文法或其他类型的文法稍显局限。

第3章 语法分析

第3章 语法分析
计算机科学与技术学院 29
第3章 语法分析
2.1型文法与1型语言(对应线性界限自动机, 自然语言)
文法G的每一个产生式α→β,均在0型文法 的基础上增加了字符长度上满足∣α∣≤∣β∣的 限制,则称文法G为1型文法或上下文有关文法, 记为CSG。 1型文法相应的语言称为1型语言或上下文有 关语言,它的识别系统是线性界限自动机。
计算机科学与技术学院 5
第3章 语法分析
有了规则以后,可以按照如下方式用它们 去推导或产生句子: 符号⇒称为 <句子> ⇒ <主语> <谓语> “推导”, ⇒ <代词> <谓语> 它的含义是, ⇒ 我<谓语> 使用一条规 ⇒ 我<动词> <直接宾语> 则,代替⇒ 左端的某个 ⇒我是 <直接宾语> 符号,产生⇒ ⇒我是 <名词> 右端的符号 串。 ⇒我是大学生
计算机科学与技术学院 18
第3章 语法分析
用S表示“字母数字串”类,由于T是一字 母或数字,ST也是字母数字串。 则有: S→T∣ST
其中,产生式S→T∣ST是一种左递归形 式,由它可以产生一串T。 用I表示“标识符”类,它或者是一单个 字母,或者为一字母后跟字母数字串。 则有: I→L∣LS
计算机科学与技术学院 19
计算机科学与技术学院 28
第3章 语法分析
1. 0型文法与0型语言(对应图灵机)
如果文法G的每一个产生式具有下列形式: α→β 其中,α V* VN V* , β V* , V=VT∪VN 。 0型文法又叫短语文法,记为PSG。0型文 法相应的语言称为0型语言或称递归可枚举集, 它的识别系统是图灵(Turing)机。

编译原理 第三章 语法分析

编译原理 第三章 语法分析

α1=>α2=>...=>αn,则称此过程为零步或多步推导,记为:
α1=*>αn,其中α1=αn的情况为零步推导。
若α1≠αn,即推导过程中至少使用一次产生式,则称此过
程为至少一步推导,记为:α1=+>αn。

定义3.2强调了两点: α,有α=*>α,即推导具有自反性;
若α=*>β,β=*>γ,则α=*>γ,即推导具有传递性。
5. 静态语义错误:如类型不一致、参数不匹配等
6. a,b:integer; x:array[1..10] of integer;
7. x:=a+b;
8. 动态语义错误(逻辑错误):如死循环、变量为零时作除数等
9. while (t) { ...};
a:=a/b;
精品文档
4
3.1.2 语法错误的处理原则(续1)
棵树。
(1) 根由开始符号所标记;
(2) 每个叶子由一个终结符、非终结符、或ε标记;
(3) 每个内部结点由一个非终结符标记;
(4) 若A是某内部节点的标记,且X1,X2,...,Xn是该节点
从左到右所有孩子的标记,则A→X1X2...Xn是一个产生式。若
A→ε,则标记为A的结点可以仅有一个标记为ε的孩子。
精品文档
8
3.2.1 CFG的定义与表示(续1) 例3.2 简单算术表达式的上下文无关文法可表示如下:
N = {E} T = {+,*,(,),-,id} S = E P: E → E + E (1) E → E * E (2) E →(E) (3) (G3.1) E → -E (4) E → id (5)
精品文档

编译原理——语法分析详解

编译原理——语法分析详解
temp->type = type;
temp->addr = addr;
temp->line = line;
temp->next = NULL;
p->next = temp;
}
void createNewError(char * content,char *descirbe,int type,int line)
strcpy(idenHead->describe,"");
idenHead->type = -1;
idenHead->addr = -1;
idenHead->line = -1;
idenHead->next = NULL;
}
void createNewNode(char * content,char *descirbe,int type,int addr,int line)
连续使用上面的规则,直至每个集合FIRST不再增大为止。②FOLLOW集合的构造算法:
(1)对于文法的开始符号S,置#于FOLLOW(S)中;(2)若A→αBβ是一个产生式,则把FIRST(β)| {ε}加至FOLLOW(B)中;
(3)若A→αB是一个产生式,或A→αBβ是一个产生式而βε(即ε∈FIRST(β)),则把FOLLOW(A)加至FOLLOW(B)中。连续使用上面的规则,直至每个集合FOLLOW不再增大为止。现在来构造G[E]的LL(1)预测分析表。预测分析表M[A, a]是如下形式的一个矩阵。A为非终结符,a是终结符或‘#’。矩阵元素M[A, a]中存放这一条关于A的产生式,指出当A面临输入符号a是所应采用的规则。M[A, a]也可能存放一条“出错标志”,指出当A根本不该面临输入符号a。

编译原理语法4(自顶向下语法分析:LL分析法)

编译原理语法4(自顶向下语法分析:LL分析法)

PART 01
引言
编译原理概述
01
编译原理是研究将高级语言程序转换为低级语言程序的过程、 方法和技术的学科。
02
编译过程包括词法分析、语法分析、语义分析、优化和代码生
成等多个阶段。
编译原理是计算机科学的重要分支,对于理解计算机如何执行
03
程序以及开发高效、可靠的软件具有重要意义。
语法分析在编译过程中的作用
递归下降分析法
递归下降分析法基本原理
基于文法规则
递归下降分析法是一种自顶向下 的语法分析方法,它基于文法规 则进行推导。
递归调用
对于每个非终结符,都编写一个 相应的子程序来进行识别和处理。 当遇到非终结符时,就调用相应 的子程序进行处理。
预测分析
在子程序中,根据当前输入符号 和文法规则,预测下一个可能的 输入符号,并据此选择正确的推 导路径。
WENKU DESIGN
2023-2026
END
THANKS
感谢观看
KEEP VIEW
WENKU DESIGN
WENKU DESIGN
WENKU
REPORTING
https://
01
深入学习编译原理中的其他分 析方法,如LR分析法、SLR分 析法等,以便更全面地掌握编 译原理的核心内容。
02
探索编译原理在实际应用中的 价值,如编译器设计、程序优 化等,将理论知识与实践相结 合。
03
关注编译原理领域的最新研究 动态和技术发展,不断拓宽自 己的视野和知识面。
WENKU DESIGN
递归下降分析法实现步骤
构造文法
首先,需要构造一个合适的文法,用于描述待分 析的语言。
调用子程序

《编译原理教程》课后习题答案第三章语法分析

《编译原理教程》课后习题答案第三章语法分析

第三章 语法分析 来消除左递归。由此,将产生式B→Bb|d改造为
B→dB′ B′→bB′| ε
其次,应通过提取公共左因子的方法来消除G[A]中的回 溯,即将产生式A→aABl|a改造为 A→aA′ A′→ABl | ε
最后得到改造后的文法为 G[A′]:A→aA′ A′→ABl | ε B→dB′ B′→bB′| ε
S→(T) | aS′ S′→+S | ε T→ST′ T′→,ST′| ε 改造后的文法已经是LL(1)文法,不带回溯的递归子程序如下: void match (token t)
{ if ( lookahead==t) lookahead=nexttoken; else error ( ); }
第三章 语法分析 void S ( ) {
第三章 语法分析 3.3 已知文法G[S]为S→aSb|Sb|b,试证明文法
G[S]为二义文法。 【 解 答】 由 文 法G[S] :S→aSb|Sb|b ,对 句 子
aabbbb可对应如图3-1所示的两棵语法树。
第三章 语法分析
S aSb aSb
Sb b
S Sb aSb aSb b
图3-1 句子aabbbb对应的两棵不同语法树
第三章 语法分析
求得:
FIRST(A)={a}
FIRST(A′)={a, ε }
FIRST(B)={d}
FIRST(B′)={b, ε }
对文法开始符号A,有FOLLOW(A)={#}。
由 A′→ABl 得 FIRST(B)\{ ε }FOLLOW(A) , 即 FOLLOW(A)={#,d};
第三章 语法分析 【解答】 (1) 消除左递归后,文法G[D′]如下:
D→TL T→int|long|short L→idL

编译原理课程设计-LL语法分析

编译原理是计算机科学中的重要领域,研究如何将源代码转换为可执行的程序。它涉及词法分析、语法分析、 语义分析等多个阶段。
为什么需要LL语法分析
LL语法分析具有许多优点,如简单易懂、容易实现、高效快速。它是编译器 中重要的组成部分,可以帮助开发人员进行语法检查和错误排除。
LL(1)文法的定义和特征
LL(1)文法是一种满足特定条件的上下文无关文法,它具有单一产生式、左递 归消除、左因子消除等特征,用于构建LL(1)分析表和语法分析树。
LL语法分析的优缺点和应用
LL语法分析具有诸多优点,如易于实现、适用于自上而下的语法分析、能够 提供详细的错误报告等。它广泛应用于编译器、解释器和语法分析工具的开 发中。
编译原理课程设计-LL语 法分析
欢迎来到编译原理课程设计-LL语法分析的世界!在本课程中,我们将探索编 译原理的重要概念和应用,并深入研究LL语法分析的原理和实现。
LL语法分析的介绍
什么是LL语法分析?这是一种基于LL(1)文法的自上而下的语法分析方法,用 于解析和验证源代码的语法结构。
什么是编译原理
LL(1)分析表的构造
构造LL(1)分析表是一项重要的任务,它将文法的终结符和非终结符映射到对 应的分析动作和跳转状态,以便进行LL语法分析的推导和规约。
Hale Waihona Puke LL(1)语法分析算法的原理和步骤
LL(1)语法分析基于LL(1)分析表实现,使用递归下降的方式进行语法分析。它的基本步骤包括选择产生式、推 导和规约。

语法分析:LL(1)分析

语法分析:LL(1)分析本篇介绍的LL(1)分析,这是⼀种⾃上⽽下分析的⽅法,第⼀个 L 表⽰从左向右扫描,第⼆个 L 表⽰分析过程是最左推导,(1)表⽰每次只向前看⼀个符号进⾏分析本⽂中,若⽆特别说明,⼩写字母[a-z]表⽰终结符,α、β等∈(V T∪V N)*,ABCD等表⽰⾮终结符⾃上⽽下分析从⽂法的开始符号出发,向下推导。

推出句⼦根据输⼊串,从⽂法开始符号(根结点)出发,⾃上⽽下地为输⼊串建⽴语法树eg:有语法:S → xAy A → ** | *从左向右扫描输⼊串,取到 x 进⾏匹配时,分析⽂法开始符号 S 的产⽣式,只有⼀个 S → xAy,那么只能将 S 推导为句型 xAy,继续由 xAy 来匹配输⼊串,输⼊符号(终结符)x 与当前句型中的 x 相匹配,则继续⽤ Ay 匹配剩下的输⼊串 *y对符号 * 进⾏匹配,遇到⾮终结符 A,分析 A 可进⾏的推导,A → ** | *按照先后顺序,先尝试 A → **,则现在的的分析树变成很好,我们使 * 得到了匹配,继续匹配哟吼,完蛋,⾮终结符 * 是⽆法匹配 y 的,匹配失败但是我们还有另外⼀条路 A → * 没试呢回到刚刚 A 没有展开,* 等待匹配的状态,将 A 推导为 ** 得到匹配后,y 也匹配成功,输⼊串结束且匹配成功,语法分析结束这就是LL(1)的推导过程那么,这种匹配⽅式就存在⼀些限制回溯问题这是⼀个⾮终结符具有多个产⽣式候选带来的问题当⼀个⾮终结符⽤某个候选式进⾏匹配时,匹配成功可能是暂时的如果要遍历所有匹配的可能,在每个多候选式终结符进⾏匹配时,就要记录下当前等待匹配的符号的位置、当前推导句型中⾮终结符的位置,和该⾮终结符选择的产⽣式的序号某次匹配失败后,舍弃某些分析结果,回溯到上⼀个岔路⼝,⾛下⼀条路尝试回溯会导致语法分析的效率问题,此外,最终分析失败时,没法确定应该在哪个岔路⼝抛出错误还有⼀个上述推导⽰例没有反映出来的死循环问题⽂法左递归问题假设有⽂法:S → xAy A → A* | *⾮终结符 A 的产⽣式是以 A 开头的串,称为左递归在上述匹配过程中,就会进⼊到 A 的左递归的产⽣式的⽆限循环中,连回溯的机会都莫得因此要消除⽂法的左递归,并避免回溯消除左递归存在左递归 P → Pα1 | Pα2 |…| Pαm | β1 |…| βn(每个α都不等于ε,每个β都不以P开头)观察上式,易知 P 推导出的句型为 (β1 |…| βn)(α1 | α2 |…| αm)*通过以下⽅法将左递归转化为右递归(易知右递归不会进⼊⽆限循环)P → (β1 |…| βn)P/P/→α1P/ | α2P/ |…| αm P/ | ε例,有如下⽂法G(E):E → E + T | TT → T * F | FF → (E) | i消除左递归后E → TE/E/→ + TE/ | εT → FT/T/→ * FT/ | εF → (E) | i但是有⼀种特殊的左递归需要注意S → Qc | cQ → Rb | bR → Sa | a看起来没有显式的左递归,实际上暗藏⽞机S → Qc | c ⇒ S → Rbc | bc | c ⇒ S → Sabc | abc | bc | c,实际上 S、Q、R 都是左递归的显然这种间接的左递归也需要消除下⾯给出⼀种左递归消除算法,使⽤这个算法的前提条件如下:不含以ε为右部的产⽣式不含有回路(⾮终结符 P 经⼀次或若⼲次推导再次得到 P)实际上,这两个条件并不苛刻,⼤多数⽂法都可以满⾜将⽂法 G 当前所有的⾮终结符按某种顺序排列 P1,P2,P3,……,P n;并按此顺序将 P i改造成 P i→ a | P i+1 | P i+2 | … | P n,具体做法是{ 将所有的 P i→ P jγ的规则改写成 P i→ ( δ1 | δ2 | … | δn )γ,其中 j < i,且 P j→δ1 | δ2 | … | δn 然后消除 P i⾥的直接左递归,得到形如 P i→ a | P i+1 | P i+2 | … | P n的 P i}消除左递归后的⽂法规则中可能有⼀些⽆法到达,删除它们另外,由于初始排列顺序的不同,最终消除左递归后的得到的⽂法规则可能不同,但是它们产⽣的语⾔是⼀样的(证明略)消除回溯消除回溯即是要保证,匹配某个符号时,可选择的候选式是唯⼀的、准确的,若输⼊串是合法的句⼦,所选推导⼀定可以使输⼊串分析成功;如果分析不成功,则输⼊串⼀定不是合法句⼦那么在匹配符号 a 时,⾮终结符 P 仅有⼀个产⽣式可以推导出以 a 开头的串,就是我们需要的情况FIRST集合由上⾯的想法,对不含左递归的⽂法 G 所有⾮终结符的每个候选α定义终结⾸符集FIRST集合如下FIRST(α) = { a | α⇒* a…,a ∈ V T },即FIRST(α)中的符号均是候选α可以推导出的串的第⼀个终结符特别是,若α⇒*ε,规定ε∈ FIRST(α)那么上述想法⽤FIRST集合的概念描述就是⾮终结符 A 的任何两个不同的候选αi、αj,有FIRST(αi) ∩ FIRST(αj) = ∅当使⽤ A 去匹配输⼊符号 a 时,若某FIRST(α)中包含a,就选择 A 的候选式α斯巴拉西,但是如何保证 FIRST(αi) ∩ FIRST(αj) = ∅呢?有提取左公共因⼦算法如下若关于 A 的语法规则符合如下形式:A →δβ1 | δβ2 | … | δβn | δ | γ1 | γ2 | … | γm则提取左公因⼦ A →δA/ | γ1 | γ2 | … | γm,A/→β1 | β2 | … | βn | ε |继续检查 A 与 A/的候选式是否可以继续提取反复提取左公共因⼦(包括新引⼊的⾮终结符),就可以使得所有候选⾸符集两两不相交现在我们已经得到不含有左递归、对于任何输⼊符号都能确定唯⼀推导过程的⽂法然⽽,还是有⼀种情形会使我们的推导有不确定性考虑如下⽂法S → ABA → a | εB → aCC → ……当匹配输⼊串 ab…… 时,取到输⼊符号 a,将 S 推导为 AB 后,出现了⽆法确定推导过程的情形:1. 将 A 推导为 a ,a 匹配成功,进⾏下⼀单词的匹配2. 将 A 推导为ε,⽤ B 去匹配 a ,再继续进⾏推导注意我们是⽆回溯的,当然不能有岔路FOLLOW集合为了确定化这种情况(FOLLOW集合的作⽤:判断能不能将⾮终结符推导为ε ),定义FOLLOW集如下FOLLOW(A) = { a | S ⇒*…Aa…,a ∈ V T },有些输⼊串以 # 作为结束标志,因此若 S ⇒*…A,规定 # ∈ FOLLOW(A)若某个⾮终结符 A 的候选⾸符集FIRST(αi)包含ε,则要求FIRST(αi)∩FOLLOW(A) = ∅也就是说,如果某个等待匹配的输⼊符号 a,不属于此时的⾮终结符 A 的FIRST集合,就会有三种情况A 的候选⾸符集均不包含ε,a 匹配失败,a 此时在输⼊串中导致语法错误A 的某个候选⾸符集包含ε,且 a ∈ FOLLOW(A),则将 A 推导为ε,继续由 A 后的推导串来匹配 aA 的某个候选⾸符集包含ε,且 a ∉ FOLLOW(A),a 匹配失败,a 此时在输⼊串导中致语法错误okk,罗⾥吧嗦这么多,终于把适⽤于LL(1)分析的⽂法的限制条件讲完辽再总结⼀遍⽂法不含左递归⽂法中每⼀个⾮终结符 A 的各个产⽣式的候选⾸符集不相交,即若 A →α1 | α2 | … | αnFIRST(αi)∩FIRST(αj) = ∅,i ≠ j对于⽂法中的每个⾮终结符 A,若它的某个候选⾸符集包含ε,则 FIRST(αi)∩FOLLOW(A) = ∅⼀个⽂法,先消除左递归,再提取公共左因⼦,得到的⽂法 G 若满⾜以上条件,则称⽂法 G 为LL(1)⽂法,可以进⾏LL(1)分析LL(1)分析的过程如下:假设当前等待匹配的符号为 a,进⾏匹配的⾮终结符为A,A 的所有产⽣式为 A →α1 | α2 | … | αn,若 a ∈ FIRST(αi),则将 A 推导为αi,a得到匹配,斯巴拉西,继续分析下⼀个符号①若 a ∉ FIRST(αi)若ε∈ FIRST(αi),且 a ∈ FOLLOW(A),则将 A 推导为ε,a 交给 A 后⾯的串匹配②否则,匹配失败,a 此时在输⼊串中是语法错误③如果这个⽂法是LL(1)⽂法,则每⼀步都能且只能在①②③中确定,每⼀步都只有⼀种情况。

LL(1)文法分析.


构造预测分析表
在确定的自顶向下分析方法中,又有递归子程序法和预测分 析方法,我们采用的是预测分析的方法。一个预测分析器 由三部分组成: (1)预测分析程序 (2)先进后出栈 (3)预测分析表 其中,只有预测分析表与文法有关。分析表可用矩阵M 表示。M(A,a)中的下标A表示非终结符,a为终结符 或括号,矩阵元素M(A,a)中的内容是一条关于A的产 生式,表明当用非终结符A往下推导时,面临输入符A时, 所应采取的候选产生式,元素内容无产生式时,则表明出 错。为便于辨认,我们令M数组为 Analyze数组。
算法介绍
1、在对输入序列进行LL(1)文法分析之前,首先要对文法进行判 别,看文法是不是LL(1)文法。这个文法应该满足无二义性,无 左递归,无公因子。具体的判别过程是,求出能推出ε的非终结 符,求出FIRST集,求出FOLLOW集,求出SELLECT集,看相 同左部的产生式的SELLECT集是否有交集,有就不是LL(1)文 法。 2、如果输入文法不是LL(1)文法,可以进行转换,转换一般有两 种方法:提取左公因子法和消除左递归法。 3、构造预测分析表,设二维矩阵M。
4、预测分析。
人员分工
• 负责MFC界面制作,程序总控,各个非终结 符能否推出ε的计算,判断是否LL(1),以及人员 分工。 • 消除左递归的实现 • 提取公因子的实现 • 求FIRST集 • 求FOLLOW集 • 求SELLECT集 • 构造预测分析表,分析输入的句子
程序流程
程序开始 InitAndConvertPt(); //读入文法、消除左递归、提取公因子 InitArray(); //初始化N[ ]数组 VnRefresh(Pt); //构造非终结符集 VtRefresh(Pt);//构造终结符集 Create_N_Table(); //判断哪些非终结符可以推出空,存入N[ ]

LL(1)分析法

LL(1)分析法编译原理实验报告日期:班级:题目:LL(1)分析法组员:LL(1)语法分析程序1. 实验目的:1.根据某一文法编制调试LL (1)分析程序,以便对任意输入的符号串进行分析。

2.本次实验的目的主要是加深对预测分析LL (1)分析法的理解。

2. 实验平台Windows + VC + Win32 Console范例程序: “3-LL1.c ”3. 实验内容1. 在范例程序的基础上完善功能对下列文法,用LL (1)分析法对任意输入的符号串进行分析:(1)E→TG(2)G→+TG|—TG(3)G→ε(4)T→FS(5)S→*FS|/FS(6)S →ε(7)F →(E)(8)F →i程序输入/输出示例:程序现有功能:输入: 一个以 # 结束的符号串(包括 + * ( )i # )输出: 只能输出步骤1, 格式如下:程序目前还不能对所有输入串进行正确的分析. 需要完善的功能:(1) 请输出完整的分析过程。

即详细输出每一步骤分析栈和剩余串的变化情况, 及每一步所用的产生式.(2) 请输出最终的分析结果, 即输入串 “合法”或 “非法”.(3)示例程序只能完成 + 、* 、(、)的语法分析, 请加入 - 和 / 的语法分析(4)可将测试用的表达式事先放在文本文件中,一行存放一个表达式,以分号分割。

同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照;备注:1. 在“所用产生式”一列中,如果对应有推导,则写出所用产生式;如果为匹配终结符,则写明匹配的终结符; 如分析异常出错则,写为“分析出错”;如成功结束则写为“分析成功”。

步骤 分析栈 剩余输入串 所用产生式 1 #E i+i*i# E →TG2. 对一个新的文法实现LL(1)分析。

4.程序代码第一种文法#include<stdio.h>#include<stdlib.h>#include<string.h>#include<dos.h>char A[20];/*分析栈*/char B[20];/*剩余串*/char v1[20]={'i','+','-','*','/','(',')','#'};/*终结符*/ char v2[20]={'E','G','T','S','F'};/*非终结符*/ int j=0,b=0,top=0,l;/*L为输入串长度*/ typedef struct type/*产生式类型定义*/ char origin;/*大写字符*/char array[7];/*产生式右边字符*/int length;/*字符个数*/}type;type e,t,g,g0,g1,s,s0,s1,f,f1;/*结构体变量*/ type C[10][10];/*预测分析表*/void print()/*输出分析栈*/int a;/*指针*/for(a=0;a<=top+1;a++)printf("%c",A[a]);printf("\t\t");}/*print*/void print1()/*输出剩余串*/int j;for(j=0;j<b;j++)/*输出对齐符*/printf(" ");for(j=b;j<=l;j++)printf("%c",B[j]);printf("\t\t\t");}/*print1*/void main()int m,n,k=0,flag=0,finish=0;char ch,x;type cha;/*用来接受C[m][n]*//*把文法产生式赋值结构体*/e.origin='E';strcpy(e.array,"TG");e.length=2;t.origin='T';strcpy(t.array,"FS");t.length=2;g.origin='G';strcpy(g.array,"+TG");g.length=3;g0.origin='G';strcpy(g0.array,"-TG");g0.length=3;g1.origin='G';g1.array[0]='^';g1.length=1;s.origin='S';strcpy(s.array,"*FS");s.length=3;s0.origin='S';strcpy(s0.array,"/FS");s0.length=3;s1.origin='S';s1.array[0]='^';s1.length=1;f.origin='F';strcpy(f.array,"(E)");f.length=3;f1.origin='F';f1.array[0]='i';f1.length=1;for(m=0;m<=4;m++)/*初始化分析表*/for(n=0;n<=7;n++)C[m][n].origin='N';/*全部赋为空*//*填充分析表*/C[0][0]=e;C[0][5]=e;C[1][1]=g;C[1][2]=g0;C[1][6]=g1;C[1][7]=g1;C[2][0]=t;C[2][5]=t;C[3][1]=s1;C[3][2]=s1;C[3][3]=s;C[3][4]=s0;C[3][6]=s1;C[3][7]=s1;C[4][0]=f1;C[4][5]=f;printf("提示:本程序只能对由'i','+','-','*','/','(',')'构成的以'#'结束的字符串进行分析,\n");printf("请输入要分析的字符串:\n");do/*读入分析串*/scanf("%c",&ch);if ((ch!='i') &&(ch!='+') &&(ch!='-') &&(ch!='*') &&(ch!='/') &&(ch!='(') &&(ch!=')') &&(ch!='#')) printf("输入串中有非法字符\n");exit(1);B[j]=ch;j++;}while(ch!='#');l=j;/*分析串长度*/ch=B[0];/*当前分析字符*/A[top]='#'; A[++top]='E';/*'#','E'进栈*/printf("步骤\t\t分析栈\t\t剩余字符\t\t所用产生式\n"); dox=A[top--];/*x为当前栈顶字符*/printf("%d",k++);printf("\t\t");for(j=0;j<=7;j++)/*判断是否为终结符*/if(x==v1[j])flag=1;break;if(flag==1)/*如果是终结符*/if(x=='#')finish=1;/*结束标记*/printf("合法\n");/*接受*/getchar();getchar();exit(1);}/*if*/if(x==ch)print();print1();printf("%c匹配\n",ch);ch=B[++b];/*下一个输入字符*/flag=0;/*恢复标记*/}/*if*/else/*出错处理*/print();print1();printf("%c出错\n",ch);/*输出出错终结符*/exit(1);}/*else*/}/*if*/else/*非终结符处理*/for(j=0;j<=4;j++)if(x==v2[j])m=j;/*行号*/break;for(j=0;j<=7;j++)if(ch==v1[j])n=j;/*列号*/break;cha=C[m][n];if(cha.origin!='N')/*判断是否为空*/print();print1();printf("%c->",cha.origin);/*输出产生式*/for(j=0;j<cha.length;j++)printf("%c",cha.array[j]);printf("\n");for(j=(cha.length-1);j>=0;j--)/*产生式逆序入栈*/A[++top]=cha.array[j];if(A[top]=='^')/*为空则不进栈*/top--;}/*if*/else/*出错处理*/print();print1();printf("%c出错\n",x);/*输出出错非终结符*/exit(1);}/*else*/}/*else*/}while(finish==0);}/*main*/测试一(1)测试i+i#(2)测试i-i(3)测试i*i#(4)测试i/i#(5)测试i+i*i#(6)测试输入非法字符i+i*#第二中文发#include<stdlib.h>#include<stdio.h>#include<string.h>int count=0; /*分解的产生式的个数*/int number; /*所有终结符和非终结符的总数*/char start; /*开始符号*/char termin[50]; /*终结符号*/char non_ter[50]; /*非终结符号*/char v[50]; /*所有符号*/char left[50]; /*左部*/char right[50][50]; /*右部*/char first[50][50],follow[50][50]; /*各产生式右部的FIRST和左部的FOLLOW集合*/char first1[50][50]; /*所有单个符号的FIRST集合*/char select[50][50]; /*各单个产生式的SELECT集合*/char f[50],F[50]; /*记录各符号的FIRST和FOLLOW是否已求过*/ char empty[20]; /*记录可直接推出^的符号*/char TEMP[50]; /*求FOLLOW时存放某一符号串的FIRST集合*/ int validity=1; /*表示输入文法是否有效*/int ll=1; /*表示输入文法是否为LL(1)文法*/int M[20][20]; /*分析表*/char choose; /*用户输入时使用*/char empt[20]; /*求_emp()时使用*/char fo[20]; /*求FOLLOW集合时使用*/判断一个字符是否在指定字符串中int in(char c,char *p)int i;if(strlen(p)==0)return(0);for(i=0;;i++)if(p[i]==c)return(1); /*若在,返回1*/if(i==strlen(p))return(0); /*若不在,返回0*/得到一个不是非终结符的符号char c()char c='A';while(in(c,non_ter)==1)c++;return(c);分解含有左递归的产生式void recur(char *point){ /*完整的产生式在point[]中*/int j,m=0,n=3,k;char temp[20],ch;ch=c(); /*得到一个非终结符*/k=strlen(non_ter);non_ter[k]=ch;non_ter[k+1]='\0';for(j=0;j<=strlen(point)-1;j++)if(point[n]==point[0]){ /*如果'|'后的首符号和左部相同*/ for(j=n+1;j<=strlen(point)-1;j++)while(point[j]!='|'&&point[j]!='\0')temp[m++]=point[j++];left[count]=ch;memcpy(right[count],temp,m);right[count][m]=ch;right[count][m+1]='\0';m=0;count++;if(point[j]=='|')n=j+1;break;else{ /*如果'|'后的首符号和左部不同*/ left[count]=ch;right[count][0]='^';right[count][1]='\0';count++;for(j=n;j<=strlen(point)-1;j++)if(point[j]!='|')temp[m++]=point[j];elseleft[count]=point[0];memcpy(right[count],temp,m);right[count][m]=ch;right[count][m+1]='\0';printf(" count=%d ",count);m=0;count++;left[count]=point[0];memcpy(right[count],temp,m);right[count][m]=ch;right[count][m+1]='\0';count++;m=0;分解不含有左递归的产生式void non_re(char *point)int m=0,j;char temp[20];for(j=3;j<=strlen(point)-1;j++)if(point[j]!='|')temp[m++]=point[j];elseleft[count]=point[0];memcpy(right[count],temp,m);right[count][m]='\0';m=0;count++;left[count]=point[0];memcpy(right[count],temp,m);right[count][m]='\0';count++;m=0;读入一个文法char grammer(char *t,char *n,char *left,char right[50][50]) char vn[50],vt[50];char s;char p[50][50];int i,j,k;printf("\n请输入文法的非终结符号串:");scanf("%s",vn);getchar();i=strlen(vn);memcpy(n,vn,i);n[i]='\0';printf("请输入文法的终结符号串:");scanf("%s",vt);getchar();i=strlen(vt);memcpy(t,vt,i);t[i]='\0';printf("请输入文法的开始符号:");scanf("%c",&s);getchar();printf("请输入文法产生式的条数:");scanf("%d",&i);getchar();for(j=1;j<=i;j++)printf("请输入文法的第%d条(共%d条)产生式:",j,i);scanf("%s",p[j-1]);getchar();for(j=0;j<=i-1;j++)if(p[j][1]!='-'||p[j][2]!='>'){ printf("\ninput error!");validity=0;return('\0');} /*检测输入错误*/for(k=0;k<=i-1;k++){ /*分解输入的各产生式*/if(p[k][3]==p[k][0])recur(p[k]);elsenon_re(p[k]);return(s);将单个符号或符号串并入另一符号串void merge(char *d,char *s,int type){ /*d是目标符号串,s是源串,type=1,源串中的' ^ '一并并入目串;type=2,源串中的' ^ '不并入目串*/int i,j;for(i=0;i<=strlen(s)-1;i++)if(type==2&&s[i]=='^')elsefor(j=0;;j++)if(j<strlen(d)&&s[i]==d[j])break;if(j==strlen(d))d[j]=s[i];d[j+1]='\0';break;求所有能直接推出^的符号void emp(char c){ /*即求所有由' ^ '推出的符号*/char temp[10];int i;for(i=0;i<=count-1;i++)if(right[i][0]==c&&strlen(right[i])==1)temp[0]=left[i];temp[1]='\0';merge(empty,temp,1);emp(left[i]);求某一符号能否推出' ^ 'int _emp(char c){ /*若能推出,返回1;否则,返回0*/int i,j,k,result=1,mark=0;char temp[20];temp[0]=c;temp[1]='\0';merge(empt,temp,1);if(in(c,empty)==1)return(1);for(i=0;;i++)if(i==count)return(0);if(left[i]==c) /*找一个左部为c的产生式*/j=strlen(right[i]); /*j为右部的长度*/if(j==1&&in(right[i][0],empty)==1)return(1);else if(j==1&&in(right[i][0],termin)==1)return(0);elsefor(k=0;k<=j-1;k++)if(in(right[i][k],empt)==1)mark=1;if(mark==1)continue;elsefor(k=0;k<=j-1;k++)result*=_emp(right[i][k]);temp[0]=right[i][k];temp[1]='\0';merge(empt,temp,1);if(result==0&&i<count)continue;else if(result==1&&i<count)return(1);判断读入的文法是否正确int judge()int i,j;for(i=0;i<=count-1;i++)if(in(left[i],non_ter)==0){ /*若左部不在非终结符中,报错*/printf("\nerror1!");validity=0;return(0);for(j=0;j<=strlen(right[i])-1;j++)if(in(right[i][j],non_ter)==0&&in(right[i][j],termin)==0&&right[i][j]!='^'){ /*若右部某一符号不在非终结符、终结符中且不为' ^ ',报错*/ printf("\nerror2!");validity=0;return(0);return(1);求单个符号的FIRSTvoid first2(int i){ /*i为符号在所有输入符号中的序号*/char c,temp[20];int j,k,m;c=v[i];char ch='^';emp(ch);if(in(c,termin)==1) /*若为终结符*/first1[i][0]=c;first1[i][1]='\0';else if(in(c,non_ter)==1) /*若为非终结符*/for(j=0;j<=count-1;j++)if(left[j]==c)if(in(right[j][0],termin)==1||right[j][0]=='^')temp[0]=right[j][0];temp[1]='\0';merge(first1[i],temp,1);else if(in(right[j][0],non_ter)==1)if(right[j][0]==c)continue;for(k=0;;k++)if(v[k]==right[j][0])break;if(f[k]=='0')first2(k);f[k]='1';merge(first1[i],first1[k],2);for(k=0;k<=strlen(right[j])-1;k++)empt[0]='\0';if(_emp(right[j][k])==1&&k<strlen(right[j])-1)for(m=0;;m++)if(v[m]==right[j][k+1])break;if(f[m]=='0')first2(m);f[m]='1';merge(first1[i],first1[m],2);else if(_emp(right[j][k])==1&&k==strlen(right[j])-1)temp[0]='^';temp[1]='\0';merge(first1[i],temp,1);elsebreak;f[i]='1';求各产生式右部的FIRSTvoid FIRST(int i,char *p)int length;int j,k,m;char temp[20];length=strlen(p);if(length==1) /*如果右部为单个符号*/if(p[0]=='^')if(i>=0)first[i][0]='^';first[i][1]='\0';elseTEMP[0]='^';TEMP[1]='\0';elsefor(j=0;;j++)if(v[j]==p[0])break;if(i>=0)memcpy(first[i],first1[j],strlen(first1[j]));first[i][strlen(first1[j])]='\0';elsememcpy(TEMP,first1[j],strlen(first1[j]));TEMP[strlen(first1[j])]='\0';else /*如果右部为符号串*/ for(j=0;;j++)if(v[j]==p[0])break;if(i>=0)merge(first[i],first1[j],2);elsemerge(TEMP,first1[j],2);for(k=0;k<=length-1;k++)empt[0]='\0';if(_emp(p[k])==1&&k<length-1)for(m=0;;m++)if(v[m]==right[i][k+1])break;if(i>=0)merge(first[i],first1[m],2);elsemerge(TEMP,first1[m],2);else if(_emp(p[k])==1&&k==length-1)temp[0]='^';temp[1]='\0';if(i>=0)merge(first[i],temp,1);elsemerge(TEMP,temp,1);else if(_emp(p[k])==0)break;求各产生式左部的FOLLOWvoid FOLLOW(int i)int j,k,m,n,result=1;char c,temp[20];c=non_ter[i]; /*c为待求的非终结符*/ temp[0]=c;temp[1]='\0';merge(fo,temp,1);if(c==start){ /*若为开始符号*/temp[0]='#';temp[1]='\0';merge(follow[i],temp,1);for(j=0;j<=count-1;j++)if(in(c,right[j])==1) /*找一个右部含有c的产生式*/for(k=0;;k++)if(right[j][k]==c)break; /*k为c在该产生式右部的序号*/for(m=0;;m++)if(v[m]==left[j])break; /*m为产生式左部非终结符在所有符号中的序号*/ if(k==strlen(right[j])-1){ /*如果c在产生式右部的最后*/if(in(v[m],fo)==1)merge(follow[i],follow[m],1);continue;if(F[m]=='0')FOLLOW(m);F[m]='1';merge(follow[i],follow[m],1);else{ /*如果c不在产生式右部的最后*/for(n=k+1;n<=strlen(right[j])-1;n++)empt[0]='\0';result*=_emp(right[j][n]);if(result==1){ /*如果右部c后面的符号串能推出^*/if(in(v[m],fo)==1){ /*避免循环递归*/merge(follow[i],follow[m],1);continue;if(F[m]=='0')FOLLOW(m);F[m]='1';merge(follow[i],follow[m],1);for(n=k+1;n<=strlen(right[j])-1;n++)temp[n-k-1]=right[j][n];temp[strlen(right[j])-k-1]='\0';FIRST(-1,temp);merge(follow[i],TEMP,2);F[i]='1';判断读入文法是否为一个LL(1)文法int ll1()int i,j,length,result=1;char temp[50];for(j=0;j<=49;j++){ /*初始化*/first[j][0]='\0';follow[j][0]='\0';first1[j][0]='\0';select[j][0]='\0';TEMP[j]='\0';temp[j]='\0';f[j]='0';F[j]='0';for(j=0;j<=strlen(v)-1;j++)first2(j); /*求单个符号的FIRST集合*/ printf("\nfirst1:");for(j=0;j<=strlen(v)-1;j++)printf("%c:%s ",v[j],first1[j]);printf("\nempty:%s",empty);printf("\n:::\n_emp:");for(j=0;j<=strlen(v)-1;j++)printf("%d ",_emp(v[j]));for(i=0;i<=count-1;i++)FIRST(i,right[i]); /*求FIRST*/printf("\n");for(j=0;j<=strlen(non_ter)-1;j++){ /*求FOLLOW*/if(fo[j]==0)fo[0]='\0';FOLLOW(j);printf("\nfirst:");for(i=0;i<=count-1;i++)printf("%s ",first[i]);printf("\nfollow:");for(i=0;i<=strlen(non_ter)-1;i++)printf("%s ",follow[i]);for(i=0;i<=count-1;i++){ /*求每一产生式的SELECT集合*/ memcpy(select[i],first[i],strlen(first[i]));select[i][strlen(first[i])]='\0';for(j=0;j<=strlen(right[i])-1;j++)result*=_emp(right[i][j]);if(strlen(right[i])==1&&right[i][0]=='^')result=1;if(result==1)for(j=0;;j++)if(v[j]==left[i])break;merge(select[i],follow[j],1);printf("\nselect:");for(i=0;i<=count-1;i++)printf("%s ",select[i]);memcpy(temp,select[0],strlen(select[0]));temp[strlen(select[0])]='\0';for(i=1;i<=count-1;i++){ /*判断输入文法是否为LL(1)文法*/length=strlen(temp);if(left[i]==left[i-1])merge(temp,select[i],1);if(strlen(temp)<length+strlen(select[i]))return(0);elsetemp[0]='\0';memcpy(temp,select[i],strlen(select[i]));temp[strlen(select[i])]='\0';return(1);构造分析表Mvoid MM()int i,j,k,m;for(i=0;i<=19;i++)for(j=0;j<=19;j++)M[i][j]=-1;i=strlen(termin);termin[i]='#'; /*将#加入终结符数组*/termin[i+1]='\0';for(i=0;i<=count-1;i++)for(m=0;;m++)if(non_ter[m]==left[i])break; /*m为产生式左部非终结符的序号*/ for(j=0;j<=strlen(select[i])-1;j++)if(in(select[i][j],termin)==1)for(k=0;;k++)if(termin[k]==select[i][j])break; /*k为产生式右部终结符的序号*/ M[m][k]=i;总控算法void syntax()int i,j,k,m,n,p,q;char ch;char S[50],str[50];printf("请输入该文法的句型:");scanf("%s",str);getchar();i=strlen(str);str[i]='#';str[i+1]='\0';S[0]='#';S[1]=start;S[2]='\0';j=0;ch=str[j];while(1)if(in(S[strlen(S)-1],termin)==1)if(S[strlen(S)-1]!=ch)printf("\n该符号串不是文法的句型!");return;else if(S[strlen(S)-1]=='#')printf("\n该符号串是文法的句型.");return;elseS[strlen(S)-1]='\0';j++;ch=str[j];elsefor(i=0;;i++)if(non_ter[i]==S[strlen(S)-1])break;for(k=0;;k++)if(termin[k]==ch)break;if(k==strlen(termin))printf("\n词法错误!");return;if(M[i][k]==-1)printf("\n语法错误!");return;elsem=M[i][k];if(right[m][0]=='^')S[strlen(S)-1]='\0';elsep=strlen(S)-1;q=p;for(n=strlen(right[m])-1;n>=0;n--)S[p++]=right[m][n];S[q+strlen(right[m])]='\0';printf("\nS:%s str:",S);for(p=j;p<=strlen(str)-1;p++)printf("%c",str[p]);printf(" ");一个用户调用函数void menu()syntax();printf("\n是否继续?(y or n):");scanf("%c",&choose);getchar();while(choose=='y')menu();主函数void main()int i,j;start=grammer(termin,non_ter,left,right); /*读入一个文法*/ printf("count=%d",count);printf("\nstart:%c",start);strcpy(v,non_ter);strcat(v,termin);printf("\nv:%s",v);printf("\nnon_ter:%s",non_ter);printf("\ntermin:%s",termin);printf("\nright:");for(i=0;i<=count-1;i++)printf("%s ",right[i]);printf("\nleft:");for(i=0;i<=count-1;i++)printf("%c ",left[i]);if(validity==1)validity=judge();printf("\nvalidity=%d",validity);if(validity==1)printf("\n文法有效");ll=ll1();printf("\nll=%d",ll);if(ll==0)printf("\n该文法不是一个LL1文法!");elseMM();printf("\n");for(i=0;i<=19;i++)for(j=0;j<=19;j++)if(M[i][j]>=0)printf("M[%d][%d]=%d ",i,j,M[i][j]);printf("\n");menu();测试二(1)测试输入一个文法(2)测试输入一个符号串(3)测试再次输入一个符号串,然后退出程序5.缺少功能要求(4)可将测试用的表达式事先放在文本文件中,一行存放一个表达式,以分号分割。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

g d w
FIRST集的不动点算法
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)
1
2
3
{a, c, d} {c}
{a, c, d} {c, a, d} {a}
示例:构造LL(1)分析表
0: Z -> d 1: a Z Y X 1 3 4, 5 c 1 2, 3 4 d 0, 1 3 4 | X Y Z 2: Y -> c 3: |
4: X -> Y 5: 2 3 4 | a 5
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; N\FIRST Z Y X 0 {} {} {} 1 2 Z -> d | X Y Z Y -> c | X -> Y | a
示例:构造FIRST_S集
0: Z -> d
NULLABLE = {X, Y}
X FIRST {a, c} Y {c} Z {a, c, d}
1:
| X Y Z
2: Y -> c 3: |
FOLLOW {a, c, d} {a, c, d} {}
4: X -> Y 5: | a 4 5
0 FIRST_S {d}
FOLLOW集的不动点算法
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)
0: S -> N V N 1: N -> s 2: | t 3: | g 4: | w 5: V -> e 6: | d 4 5
N\FIRST S N V
0 {} {} {}
1
2
3
把FIRST集推广到任意串上
FIRST_S(β1 … βn) = FIRST(N), if β1 == N; {a}, if β1 == a. // 在右侧产生式上标记这个FIRST_S集合 0: S -> N V N 1: N -> s 2: | t 3: | g 4: | w 5: V -> e 6: | d
Z -> d

首先研究右侧的例子:

| X Y Z Y -> c | X -> Y | a
FIRST_S(X Y Z)?


一般情况下需要知道某个非终结 符是否可以推出空串 NULLABLE

并且一般需要知道在某个非终 结符后面跟着什么符号

跟随集FOLLOW
NULLABLE集合

归纳定义: 非终结符X属于集合NULLABLE,当且仅 当:

基本情况:

X -> X -> Y1 … Yn


归纳情况:

Y1, …, Yn 是n个非终结符,且都属于NULLABLE集
NULLABLE集合算法
NULLABLE = {}; while (NULLABLE is still changing) foreach (production p: X-> β) if (β== ) NULLABLE ∪= {X} if (β== Y1 … Yn) if (Y1 NULLABLE && … && Yn NULLABLE) NULLABLE ∪= {X}
0 1
5
6
N\FIRST S N V {s, t, g, w} {s, t, g, w} {e, d}
0: S -> N V N 1: N -> s {s} 2: | t {t} 3: | g {g} 4: | w {w} 5: | w V {w} 6: V -> e {e} 7: | d {d}
一般条件下的LL(1)分析表构造
示例
Z -> d NULLABLE = {}; | X Y Z Y -> c while (NULLABLE is still changing) | foreach (production p: X-> β) if (β== ) X -> Y NULLABLE ∪= {X} | a if (β== Y1 … Yn) if (Y1 NULLABLE && … && Yn NULLABLE) NULLABLE ∪= {X}
0: S -> N V N 1: N -> s 2: | t 3: | g 4: | w 5: V -> e 6: | d 分析这个句子
g d w
correct
table[N, T]
FIRST集
// 定义: // FIRST(N) = 从非终结符N开始推 // 导得出的句子开头的 // 所有可能终结符集合 // 计算公式(第一个版本,近似!): 对 N -> a … FIRST(N) ∪= {a} 对 N -> M … FIRST(N) ∪= FIRST(M) 0: S -> N V N 1: N -> s 2: | t 3: | g 4: | w 5: V -> e 6: | d 推导这个句子
LL(1)分析表
语法分析 驱动代码
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集计算示例
0: Z -> d
NULLABLE = {X, Y}
X FIRST {a, c} Y {c} Z {a, c, d}
1:
| X Y Z
2: Y -> c 3: |
4: X -> Y 5: | a
N\FOLLOW Z Y X
0 {} {} {}
1
2
计算FIRST_S集合
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)
N\T S N V
s 0 1
t 0 2
g 0 3
w 0 4
e
d
5
6
tokens[]; // all tokens i=0; stack = [S] // S是开始符号 while (stack != []) if (stack[top] is a terminal t) if (t==tokens[i++]) pop(); else backtrack(); error(…) else if (stack[top] is a nonterminal T) pop(); push(the next right hand side of T)
N\FIRST S N V {s, t, g, w} {s, t, g, w} {e, d}
构造LL(1)分析表
N\T s S N V 0 1 t 0 2 g 0 3 w 0 4 5 6 e d
{s,t,g,w}
0: S -> N V N 1: N -> s {s} 2: | t {t} 3: | g {g} 4: | w {w} 5: V -> e {e} 6: | d {d}
语法分析: LL(1)分析算法
编译原理 2017-12-5
前端
源程序 词法分析器 记号
语法分析 器
抽象语法树
语义分析器
中间表 示
语法分析器的任务
记号流
语法分析器
语法树
语言的语法规则
自动生成
声明式的规范 语法分析器
LL(1)分析算法

从左(L)向右读入程序,最左(L)推 导,采用一个(1)前看符号
FIRST集合的完整计算公式
相关文档
最新文档