LR(0)文法

合集下载

《编译原理》中LR(0)语法分析动态演示系统分析与设计

《编译原理》中LR(0)语法分析动态演示系统分析与设计

《编译原理》中LR(0)语法分析动态演示系统分析与设计1. 引言1.1 研究背景编译原理是计算机科学领域的重要基础课程,而LR(0)语法分析是编译原理中一个关键的内容。

LR(0)语法分析是一种自底向上的语法分析方法,能够准确地判断一个输入串是否是给定文法的句子,同时可以生成句子对应的语法树。

LR(0)语法分析比上下文无关文法分析更为强大,因此被广泛应用于编译器的设计和实现中。

对于学习者来说,理解和掌握LR(0)语法分析并不是一件容易的事情。

传统的教学方法往往是通过讲解和演示来进行,但存在一定的局限性,学生很难深入理解其中的逻辑和原理。

设计一个LR(0)语法分析动态演示系统是十分必要和有意义的。

这样的系统可以通过图形化的界面展示LR(0)语法分析的每个步骤和过程,帮助学生更直观地理解LR(0)语法分析的原理和实现。

1.2 研究目的研究目的是为了通过设计和实现一个LR(0)语法分析动态演示系统,帮助学生和从业者更好地理解和应用LR(0)语法分析算法。

具体来说,研究目的包括但不限于以下几点:通过分析LR(0)语法分析算法的原理和流程,深入探讨其在编译原理中的重要性和应用价值,为用户提供一个直观、动态的学习工具,帮助他们更好地理解和掌握这一算法的核心概念。

通过设计和实现一个功能齐全、易于操作的LR(0)语法分析动态演示系统,提供用户友好的界面和交互功能,使用户可以通过实际操作和观察,加深对LR(0)语法分析算法的认识,并在实践中掌握其使用方法和技巧。

通过系统测试和优化,不断改进系统性能和用户体验,确保系统稳定运行并具有良好的可用性和可靠性,为用户提供一个高质量的学习工具和应用工具。

通过这些努力,旨在提高用户对LR(0)语法分析算法的理解和应用能力,促进编译原理领域的教学和研究工作的发展。

1.3 研究意义编译原理是计算机专业的重要基础课程,而LR(0)语法分析是编译原理中一项重要的内容。

通过设计和实现一个LR(0)语法分析动态演示系统,可以帮助学生更加直观地理解和掌握LR(0)语法分析的原理和算法。

《编译原理》中LR(0)语法分析动态演示系统分析与设计

《编译原理》中LR(0)语法分析动态演示系统分析与设计

《编译原理》中LR(0)语法分析动态演示系统分析与设计一、引言随着计算机科学领域的不断发展,编译原理作为计算机科学的核心课程之一,对于理解编程语言和编译器的原理和技术具有重要意义。

LR(0)语法分析作为编译器中的重要组成部分,在编译原理课程中具有重要的地位。

为了更好地理解与掌握LR(0)语法分析,本文将课程中的相关理论与实践相结合,提出了一个LR(0)语法分析动态演示系统的设计与分析。

二、LR(0)语法分析概述在编译器的构建中,语法分析是非常重要的一环。

而LR(0)语法分析是一种常用的语法分析方法之一。

LR(0)语法分析使用的是LR(0)自动机进行分析,它是一种自底向上的语法分析方法,它的优势在于可以处理大部分的上下文无关文法(Context-Free Grammar, CFG),并且可以准确地进行语法分析。

LR(0)语法分析是通过构建状态机的方式,根据文法产生式中的右部项目来进行状态转换并最终得到文法的推导序列。

为了更好地理解LR(0)语法分析的原理与过程,我们需要深入学习LR(0)自动机的构建过程、状态转换的规则以及分析过程的具体步骤。

仅仅通过理论学习,学生们往往难以深刻理解LR(0)语法分析的工作原理与流程。

我们需要设计一个能够直观演示LR(0)语法分析过程的系统,通过动态的展示来帮助学生更好地理解LR(0)语法分析的过程和原理。

三、LR(0)语法分析动态演示系统的需求分析为了实现LR(0)语法分析动态演示系统,首先需要进行系统需求分析,明确系统的功能需要和用户需求。

根据LR(0)语法分析的原理与过程,系统的主要功能需求包括:1. 文法输入:能够接受用户输入的文法表达式,包括非终结符、终结符及产生式。

2. LR(0)自动机构建:根据用户输入的文法表达式自动生成LR(0)自动机,并进行展示。

3. 状态转换展示:根据LR(0)自动机中的状态转换规则,动态展示状态之间的转换过程及转换规则。

4. 分析过程展示:根据LR(0)自动机和输入的句子,展示分析过程中状态的变化和产生式的规约过程。

编译原理词法分析器-ll1-lr0-python实现代码

编译原理词法分析器-ll1-lr0-python实现代码

编译原理词法分析器-ll1-lr0-python实现代码计算机科学与通信工程学院编译原理实验报告题目: 1.词法分析器2. LL(1)分析器3. LR(0)分析器班级:姓名:学号:指导老师:2017年月目录一、实验题目 (1)二、实验目的和要求 (1)三、代码实现 (2)四、总结 (25)一、实验题目1.词法分析器分析一段程序代码,将代码中的单词符号分解出来,并对其进行检查,输出token表和error表2.LL(1)文法分析器分析给定文法。

求出文法的FIRST集,FOLLOW集,并构建分析表,对给定输入串进行分析。

3.LR(0)文法分析器分析给定文法。

用Ꜫ_CLOSURE方法构造文法的LR(0)项目集规范族,根据状态转换函数GO构造出文法的DFA,并转换为分析表,对给定输入串进行分析。

二、实验目的和要求1.学会词法分析器的实现思路。

2.学会求解FIRST集, FOLLOW集,构造LL(1)分析表。

3.学会Ꜫ_CLOSURE方法,状态转换函数GO, 构造LR(0)分析表。

三、代码实现1.词法分析器program.txt 中存放要分析的文法:E->TRR->+TR|-TR|~T->FGG->*FG|/FG|~F->(E)|i代码:KEYWORD_LIST = ['while', 'if', 'else', 'switch', 'case']SEPARATOR_LIST = [';', ':', ',', '(', ')', '[', ']', '{', '}']OPERATOR_LIST1 = ['+', '-', '*']OPERATOR_LIST2 = ['<=', '<', '==', '=', '>', '>=']CATEGORY_DICT = {# KEYWORD"while": {"while": ""},"if": {"if": ""},"else": {"else": ""},"switch": {"switch": ""},"case": {"case": ""},# OPERATOR"+": {"+": ""},"-": {"-": ""},"*": {"*": ""},"<=": {"relop": "LE"},"<": {"relop": "LT"},">=": {"relop": "GE"},">": {"relop": "GT"},"==": {"relop": "EQ"},"=": {"=": ""},# SEPARATOR";": {";": ""},":": {":": ""},",": {",": ""},"(": {"(": ""},")": {")": ""},"[": {"]": ""},"]": {"]": ""},"{": {"{": ""},"}": {"}": ""},}CONSTANTTABLE = []TOKENTABLE = []OPERATORTABLE = []KEYWORDTABLE = []SEPARATORTABLE = []UNDEFINEDTABLE = []# READ FILEdef read_file(path, method):temp_str = ""try:file = open(path, method)for line in file:line = line.replace('\n', " ") temp_str += linetemp_str = str(temp_str)except IOError as e:print(e)exit()finally:file.close()return temp_str.strip() + " "# GETBEdef getbe():global tokengetchar()token = ""return# GETCHARdef getchar():global characterglobal locationwhile all_string[location] == " ":location = location + 1character = all_string[location]return character# LINK TOKENdef concatenation():global tokenglobal charactertoken = token + character# IS NUMBERdef digit():if '0' <= character <= '9':return Truereturn False# IS ALPHABETdef letter():if 'A' <= character <= 'Z' or 'a' <= character <= 'z': return Truereturn False# IS IDENTIFIERdef reserve():if token in KEYWORD_LIST:return CATEGORY_DICT[token]else:return 0# RETRACTdef retract():global locationglobal character# location = location - 1character = ""return# MAIN FUNCTIONdef main():global tokenglobal characters = getchar()getbe()if 'a' <= s <= 'z' or 'A' <= s <= 'Z':while letter() or digit():concatenation()location = location + 1character = all_string[location]retract()c = reserve()if c == 0:TOKENTABLE.append(token)print("这是标识符:{'", token, "':'", TOKENTABLE.index(token), "'}") else:KEYWORDTABLE.append(token)print("这是保留字:", CATEGORY_DICT[token])elif '0' <= s <= '9':while digit():concatenation()location = location + 1character = all_string[location]retract()CONSTANTTABLE.append(token)print("这是常数:{'", token, "':'", CONSTANTTABLE.index(token), "'}") elif s in OPERATOR_LIST1:location = location + 1OPERATORTABLE.append(s)print("这是单操作符:", CATEGORY_DICT[s])elif s in OPERATOR_LIST2:location = location + 1character = all_string[location]if character == '=':OPERATORTABLE.append(s + character)print("这是双操作符:", CATEGORY_DICT[s + character])else:retract()location = location + 1OPERATORTABLE.append(s)print("这是单操作符:", CATEGORY_DICT[s])elif s in SEPARATOR_LIST:location = location + 1SEPARATORTABLE.append(s)print("这是分隔符:", CATEGORY_DICT[s])else:UNDEFINEDTABLE.append(s)print("error:undefined identity :'", s, "'")if __name__ == '__main__':character = ""token = ""all_string = read_file("program.txt", "r")location = 0while location + 1 < len(all_string):main()print('KEYWORDTABLE:', KEYWORDTABLE)print('TOKENTABLE:', TOKENTABLE)print('CONSTANTTABLE:', CONSTANTTABLE)print('OPERATORTABLE:', OPERATORTABLE)print('SEPARATORTABLE:', SEPARATORTABLE)运行结果:2.LL(1)分析器program.txt 中存放要分析的文法:E->TRR->+TR|-TR|~T->FGG->*FG|/FG|~F->(E)|i输入串:i+i*i代码:NonTermSet = set() # 非终结符集合TermSet = set() # 终结符集合First = {} # First集Follow = {} # Follow集GramaDict = {} # 处理过的产生式Code = [] # 读入的产生式AnalysisList = {} # 分析表StartSym = "" # 开始符号EndSym = '#' # 结束符号为“#“Epsilon = "~" # 由于没有epsilon符号用“~”代替# 构造First集def getFirst():global NonTermSet, TermSet, First, Follow, FirstAfor X in NonTermSet:First[X] = set() # 初始化非终结符First集为空for X in TermSet:First[X] = set(X) # 初始化终结符First集为自己Change = Truewhile Change: # 当First集没有更新则算法结束Change = Falsefor X in NonTermSet:for Y in GramaDict[X]:k = 0Continue = Truewhile Continue and k < len(Y):if not First[Y[k]] - set(Epsilon) <= First[X]: # 没有一样的就添加,并且改变标志if Epsilon not in First[Y[k]] and Y[k] in NonTermSet and k > 0: # Y1到Yi候选式都有~存在Continue = Falseelse:First[X] |= First[Y[k]] - set(Epsilon)Change = Trueif Epsilon not in First[Y[k]]:Continue = Falsek += 1if Continue: # X->~或者Y1到Yk均有~产生式First[X] |= set(Epsilon)# FirstA[Y] |= set(Epsilon)# 构造Follow集def getFollow():global NonTermSet, TermSet, First, Follow, StartSymfor A in NonTermSet:Follow[A] = set()Follow[StartSym].add(EndSym) # 将结束符号加入Follow[开始符号]中Change = Truewhile Change: # 当Follow集没有更新算法结束Change = Falsefor X in NonTermSet:for Y in GramaDict[X]:for i in range(len(Y)):if Y[i] in TermSet:continueFlag = Truefor j in range(i + 1, len(Y)): # continueif not First[Y[j]] - set(Epsilon) <= Follow[Y[i]]:Follow[Y[i]] |= First[Y[j]] - set(Epsilon) # 步骤2 FIRST(β)/~ 加入到FOLLOW(B)中。

文法。LR(0)分析表的构造

文法。LR(0)分析表的构造

• P126 识别活前缀的有限自动机 • 对任何一个上下文无关文法,只要能构 造出它的识别可归前缀的有限自动机, 就可以构造其相应的分析表(状态转换 表和动作表)。
#S0x1S1x2...... xmSm
S0S1...... Sm # x1x2..... xm
☆ 状态栈:
S0,S1,…,Sm 状态 S0---初始状态
逻辑上说,一个LR分析器由3个部分组成:
(1) 总控程序,也可以称为驱动程序。对所有的 LR 分析 器总控程序都是相同的。
(2) 分析表或分析函数,不同的文法分析表将不同,同一 个文法采用的 LR分析器不同时,分析表也不同,分析表又 可分为动作表(ACTION)和状态转换(GOTO)表两个部 分,它们都可用二维数组表示。 (3) 分析栈,包括文法符号栈和相应的状态栈,它们均是 先进后出栈。 分析器的动作就是由栈顶状态和当前输入符号所决定。
(1) 分析动作表Action
符号 状态
S0 S1 … Sn
a1
action[S0 , a1] action[S1 , a1] … action[Sn , a1]
a2
action[S0 , a2] action[S1 , a2] … action[Sn , a2]

… … … …
at
action[S0 , at] action[S1 , at] … action[Sn , at]
LR分析概述
• LR(k)分析是根据当前分析栈中的符 号串和向右顺序查看输入串的k(k≥0)个 符号就可以唯一确定分析的动作是移进 还是归约以及用哪个产生式归约。 • 从左到右扫描(L)自底向上进行规约(R) (是规范规约)
LR分析的优缺点
1)适合文法类足够大,适用于大多数上下文 无关文法 2)分析效率高 3)报错及时 4)手工实现工作量大 5)可以自动生成 美国Bell实验室推出的编译程序自动构造 工具——YACC:能接受一个用BNF描述的 满足LALR(1)上下文无关文法并对其自 动构造出LALR(1)分析器。

编译原理LR分析(主要是LR(0)分析)

编译原理LR分析(主要是LR(0)分析)

编译原理LR分析(主要是LR(0)分析)⼀、LR分析的基本原理1、LR分析的基本思想LR⽅法的基本思想就是,在规范归约的过程中,⼀⽅⾯要记住已移进和归约出的整个字符串,也就是说要记住历史;⼀⽅⾯能够根据所⽤的产⽣式的推测未来可能碰到的输⼊符号,也就是说能够对未来进⾏展望。

这样,当⼀串貌似句柄的字符串出现在分析栈的顶部时,我们希望能够根据历史和展望以及现实的输⼊符号这三部分的材料,决定出现在栈顶的这⼀串符号是否就是我们要找的句柄。

2、LR分析器的构成采⽤下推⾃动机这种数据模型。

包括以下⼏个部分:1.输⼊带2.分析栈:包括状态栈和⽂法符号栈两部分。

(s0,#)为分析开始前预先放在栈⾥的初始状态和句⼦括号。

3.LR 分析表:包括动作表和状态转移表两张表。

3、LR分析表是LR分析器的核⼼部分⼀张LR分析表包括两部分:动作表(ACTION)和状态转换表(GOTO)。

它们都是⼆维数组。

ACTION[s,a]规定了当状态s⾯临输⼊符号a时应采取什么动作(移进、归约、接受和报错),⽽GOTO[s,X]规定了当状态s⾯对⽂法符号X(终结符或⾮终结符)时的下⼀状态是什么。

显然,GOTO[s,X]定义了⼀个以⽂法符号为字母表的DFA。

不同的 LR 分析法构造LR分析表的⽅法都不同,由此产⽣了不同的LR分析法。

4、LR分析算法置ip指向输⼊串w的第⼀个符号 令Si为栈顶状态 a是ip指向的符号(当前输⼊符号) BEGIN(重复开始) IF ACTION[Si,a]=Sj THENBEGINPUSH j,a (进栈) ip前进(指向下⼀输⼊符号) END ELSEIF ACTION[Si,a]=rj(若第j条产⽣式为A→β) THEN BEGIN pop|β| 项 若当前栈顶状态为Sk pushGOTO[Sk,A] 和A(进栈) END ELSEIF ACTION[Si,a]=acc THEN return (成功) ELSE error END. (重复结束)⼆、LR(0)分析器1、可归前缀与规范句型的活前缀⽂法G[S]:(1) S → aAcBe[1](2) A → b[2](3) A → Ab[3](4) B → d[4]S ÞaAcBe[1]ÞaAcd[4]e[1]ÞaAb[3]cd[4]e[1]Þab[2]b[3]cd[4]e[1]每次归约句型的前部分依次为:ab[2]aAb[3]aAcd[4]aAcBe[1]规范句型的这种前部分符号串称为可归前缀我们把形成可归前缀之前包括可归前缀在内的所有规范句型的前缀都称为活前缀(活前缀就是可归前缀的前缀)如下:e,a,abe ,a,aA,aAbe ,a,aA,aAc,aAcde ,a,aA,aAc,aAcB,aAcBe三、LR分析(⼀)LR分析构造识别活前缀的有穷⾃动机项⽬(item):在每个产⽣式的右部适当位置添加⼀个圆点构成项⽬。

《编译原理》中LR(0)语法分析动态演示系统分析与设计

《编译原理》中LR(0)语法分析动态演示系统分析与设计

《编译原理》中LR(0)语法分析动态演示系统分析与设计一、引言编译原理是计算机科学与技术中的重要课程,它研究的是如何将高级程序语言翻译成机器语言的技术和方法。

在编译原理中,LR(0)语法分析是一个重要的内容,它是通过自底向上的方式进行语法分析的一种方法。

在学习编译原理的过程中,学生往往会遇到对LR(0)语法分析的理解困难,因为它涉及到许多抽象的概念和算法。

为了更好地帮助学生理解和掌握LR(0)语法分析,本文针对LR(0)语法分析动态演示系统进行了分析与设计,旨在通过动态演示的方式帮助学生更直观、深入地理解LR(0)语法分析的原理和过程。

二、LR(0)语法分析方法简介LR(0)语法分析是一种自底向上的语法分析方法,它能够对任意上下文无关文法(CFG)进行语法分析。

LR(0)语法分析的基本思想是通过分析输入串中的符号和栈中的符号,逐步地将输入串转换为目标符号串的过程。

在LR(0)语法分析中,使用LR(0)自动机来表示语法分析过程,并通过自动机的状态转换来完成对输入串的分析。

LR(0)语法分析包括了自动机的构建、状态的扩展和分析过程三个基本步骤,每个步骤都涉及到大量的状态转换和符号匹配。

三、LR(0)语法分析动态演示系统分析1. 功能需求分析为了帮助学生更直观、深入地理解LR(0)语法分析的原理和过程,需要实现一个动态演示系统,该系统应该具备以下基本功能:(1)自动机的构建:实现LR(0)自动机的构建过程,包括状态的生成、状态的扩展和状态转换规则的确定。

(2)状态的扩展:实现LR(0)自动机中状态的扩展过程,包括向状态图中添加新的状态和确定转移规则。

(3)分析过程演示:实现LR(0)语法分析的过程演示,包括输入串的处理和状态转换规则的应用。

2. 界面设计分析3. 技术实现分析动态演示系统的技术实现应该能够满足LR(0)语法分析的模拟和演示需求,具体应该采用以下技术实现方案:(1)使用HTML、CSS和JavaScript实现界面设计,实现LR(0)自动机状态图的展示和交互功能。

实验三编译原理综合实验报告——(LR(0)语法分析的实现)

实验三编译原理综合实验报告——(LR(0)语法分析的实现)
m_pTree->Create(IDD_DIALOG3, this);
m_pTree->SetControlInfo(IDC_TREE1, RESIZE_BOTH);
m_pTree->SetControlInfo(IDOK, ANCHORE_BOTTOM | ANCHORE_RIGHT);
void CAnalyzeDlg::OnOK()
{
// TODO: Add extra validation here
//CDialog::OnOK();
}
void CAnalyzeDlg::OnCancel()
{
// TODO: Add extra cleanup here
六、实验原理、数据(程序)记录
(一)实验原理:
利用LR(k)类分析算法的四个步骤,分别实现"移进"、"归约"、"成功"、"报错"的分析能力。同时采用相应的数据结构实现分析表的描述。
(二)程序框架:
#include "stdafx.h"
#include "GoData.h"
GoData::GoData()
assert(j != -1);
out.WriteString(GetStepInfo(iStep, Status, Symbol, m_input.Right(m_input.GetLength() - iPos), ToDo, j));
for(i = 0; i < m_g.GetPrecept(ToDo.two).GetRight().length(); i++)

LR0项目集族和LR分析表的构造文档资料

LR0项目集族和LR分析表的构造文档资料

2 #a
bbcde# 移进
3 #ab
bcde# 归约 A→b
4 #aA
bcde# 移进
5 #aAb
cde# 归约 A→Ab
6 #aA
cde# 移进
7 #aAc
de# 移进
8 #aAcd
e# 归约 B→d
9 #aAcB
e# 移进
10 #aAcBe
# 归约 S→aAcBe
11 #S
# 接受
#abbcde#的规范归约过程
• 表明一个产生式的右部已分析完,句柄已形成可 以归约
• 接受项目: S'→S·
• 表明已分析成功
三、LR(0)项目集规范族的构造
构造识别文法活前缀DFA的三种方法 *
• 求出活前缀的正规表达式,然后由此正规表
达式构造NFA, 再确定化为DFA。
• 求出文法的所有项目,按一定规则构造识别
活前缀的NFA, 再确定化为DFA。
从初态出发,经读出活 前缀γ后,而到达的项 目集称为活前缀γ的 有效项目集
a
c
I4:Ac•A A •cA
A d
A •d
c
d
I2:Ea•A
A •cA A
A •d
I0: S'•E E •aA
E •bB
E
I1: S' E •
b I3: Eb•B B B •cB
B •d c
d
识别文法 活前缀的DFA
图5.7 p106
DFA
•每个状态是一
个项目集, 称作 LR(0)项目集
•整个状态集称
为LR(0)项目集 规范族
3. LR(0)项目的分类
• 移进项目: A→α·aβ
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

编译原理实验报告实验名称:LR(0)文法分析实验时间:2011年12月1号院系:安徽大学江淮学院计算机科学与电子技术系班级:计算机科学与技术(2)班学号:JB094170、JB094172、JB094180、JB094188、JB094216 姓名:常文静、赵婷婷、连梦莹、陈绵慧、陈亚男一、实验目的:输入:任意的压缩了的上下文无关文法。

输出:相应的LR(0)分析表。

二、实验原理:对于LR文法,我们可以自动构造相应的LR分析表。

为了构造LR分析表,我们需要定义一个重要概念——文法的规范句型“活前缀”。

这种句柄之后不含任何符号的前缀称为活前缀。

在LR分析工作过程中的任何时候,栈里的文法符号(自栈底而上)X1X2…X m应该构成活前缀,把输入串的剩余部分配上之后即应成为规范句型(如果整个输入串确实构成一个句子)。

因此,只要输入串的已扫描部分保持可归约成一个活前缀,那就意味着所扫描过的部分没有错误。

对于一个文法G,我们可以构造一个有限自动机,它能识别G的所有活前缀,然后把这个自动机转变成LR分析表,按照该LR分析表进行LR分析,就能保证在分析的过程中,如果分析的句子是正确的,栈里的文法符号(自栈底而上)始终构成活前缀。

假若一个文法G的拓广文法G 的活前缀识别自动机中的每个状态(项目集)不存在下述情况:(1)既含移进项目又含归约项目;(2)含有多个归约项目,则称G是一个LR(0)文法。

该自动机的状态集合即为该文法的LR(0)项目集规范族。

构造识别文法活前缀DFA有3种方法:(1)根据形式定义求出活前缀的正则表达式,然后由此正则表达式构造NFA 再确定为DFA;(2)求出文法的所有项目,按一定规则构造识别活前缀的NFA再确定化为DFA;(3)使用闭包函数(CLOSURE)和转向函数(GO(I,X))构造文法G’的LR(0)的项目集规范族,再由转换函数建立状态之间的连接关系来得到识别活前缀的DFA 。

符号串的前缀是指该符号串的任意首部,包括空串ε。

例如,对于符号串abc ,其前缀有ε,a ,ab ,abc 。

如果输入串没有错误的话,一个规范句型的活前缀是该句型的一个前缀,但它不含句柄之后的任何符号。

之所以称为活前缀,是因为在该前缀后联接尚未输入的符号串可以构成一个规范句型。

活前缀与句柄的关系如下:(1)活前缀已含有句柄的全部符号,表明产生式A →β的右部β已出现在栈顶。

(2)活前缀只含句柄的一部分符号,表明A →β1β2的右部子串β1已出现在栈顶,期待从输入串中看到β2推出的符号。

(3)活前缀不含有句柄的任何符号,此时期望A →β的右部所推出的符号串。

在文法G 的每个产生式的右部(候选式)的任何位置上添加一个圆点,所构成的每个产生式称为LR (0)项目。

如产生式A → xyz 有如下项目:A →.xyz ,A →x.yz ,A →xy.z ,A →xyz.。

为刻划分析过程中的文法的每一个产生式的右部符号已有多大一部分被识别(出现在栈顶),可以用这种标有圆点的产生式来确定。

(1)A →β.刻划产生式A →β的右部β已出现在栈顶。

(2)A →β1.β 2 刻划A →β1β2的右部子串β1已出现在栈顶,期待从输入串中看到β2推出的符号。

(3)A →.β 刻划没有句柄的任何符号在栈顶,此时期望A →β的右部所推出的符号串。

(4)对于A →ε的LR(0)项目只有A →.。

设文法G=(V T ,V N ,S ,P )是一个上下文无关文法,若存在一个规范推导S *rm ⇒αAw rm ⇒αβ1β2w (其中A →β1β2∈P ),则称项目A →β1•β2对活前缀γ=αβ1是有效的,即LR(0) 有效项目。

从直观意义上讲,一个LR(0)项目指明了在分析过程中的某一步我们看到产生式的多大部分被识别,LR(0)项目中的圆点可看成是分析栈栈顶与输入串的分界线,圆点左边为已进入分析栈的部分,右边是当前输入或继续扫描的符号串。

不同的LR(0)项目,反映了分析栈顶的不同情况。

我们根据LR(0)项目的作用不同,将其分为四类:(1)归约项目:表现形式:A →a.这类LR(0)项目表示句柄a 恰好包含在栈中,即当前栈顶的部分内容构成了所期望的句柄,应按A →a 进行归约。

(2)接受项目:表现形式:S →a.其中S 是文法惟一的开始符号。

这类LR(0)项目实际是特殊的归约项目,表示分析栈中内容恰好为a ,用S →a 进行归约,则整个分析成功。

(3)移进项目:表现形式:A →a.βb (b ∈V T )这类LR(0)项目表示分析栈中是不完全包含句柄的活前缀,为构成恰好有句柄的活前级,需将b移进分析栈。

(4)待约项目:表现形式:A→α.Bβ(B∈V N)这类LR(0)项目表示分析栈中是不完全包含句柄的活前缀,为构成恰好有句柄的活前缀,应把当前输入字符串中的相应内容先归约到B。

在给出LR(0)项目的定义和分类之后,我们从这些LR(0)项目出发,来构造能识别文法所有前缀的有限自动机。

其步骤是:首先构造能识别文法所有活前缀的非确定的有限自动机,再将其确定化和最小化,最终得到所需的确定的有限自动机。

由文法G的LR(0)项目构造识别文法G的所有活前缀的非确定有限自动机的方法:(1)规定含有文法开始符号的产生式(设S'→A)的第一个LR(0)项目(即S'→.A)为NFA的惟一初态。

(2)令所有LR(0)项目分别对应NFA的一个状态且LR(0)项目为归约项目的对应状态为终态。

(3)若状态i和状态j出自同一文法G的产生式且两个状态LR(0)项目的圆点只相差一个位置,即:若i为X→X1X2·…X i-1·X i…X n,j为X→X1X2…X i·X i+1…X n,则从状态i引一条标记为X i的弧到状态j。

(4)若状态i为待约项目(设X→α·Aβ),则从状态i引ε弧到所有A →·r的状态。

为了使“接受”状态易于识别,我们通常将文法G进行拓广。

假定文法G是一个以S为开始符号的文法,我们构造一个G',它包含了整个G,但它引进了一个不出现在G中的非终结符S',并加进一个新产生式S'→S,以S'→S G'为开始符号。

那么,我们称G'是G的拓广文法。

这样,便会有一个仅含项目S'→S的状态,这就是惟一的“接受”态。

如果I是文法G'的一个项目集,定义和构造I的闭包CLOSURE(I)如下:(1)I的项目都在CLOSURE(I)中。

(2)若A→α.Bβ属于CLOSURE(I),则每一形如B→.γ的项目也属于CLOSURE(I)。

(3)重复(2)直到CLOSURE(I)不再扩大。

定义转换函数如下:GO(I,X)= CLOSURE(J)其中:I为包含某一项目集的状态,X为一文法符号,J={ A→αX .β | A→α.X β∈I}。

圆点不在产生式右部最左边的项目称为核,惟一的例外是S′→.S,因此用GOTO(I,X)状态转换函数得到的J为转向后状态闭包项目集的核。

使用闭包函数(CLOSURE)和转换函数(GO(I,X))构造文法G’的LR(0)的项目集规范族,步骤如下:(1)置项目S′→.S为初态集的核,然后对核求闭包CLOSURE({S′→.S})得到初态的闭包项目集。

(2) 对初态集或其他所构造的项目集应用转换函数GO(I ,X)=CLOSURE(J)求出新状态J 的闭包项目集。

(3) 重复(2)直到不出现新的项目集为止。

计算LR (0)项目集规范族C={I 0,I 1 , ... In }的算法伪代码如下:Procedure itemsets(G’);Begin C := { CLOSURE ({S’→.S})}RepeatFor C 中每一项目集I 和每一文法符号XDo if GO(I,X) 非空且不属于CThen 把 GO(I,X) 放入C 中Until C 不再增大End;一个项目集可能包含多种项目,若移进和归约项目同时存在,则称移进-归约冲突,若归约和归约项目同时存在,则称归约-归约冲突。

下面看一个具体的例子:我们希望能根据识别文法的活前缀的DFA 建立LR 分析器,因此,需要研究这个DFA 的每个项目集(状态)中的项目的不同作用。

我们说项目A →β1.β2对活前缀αβ1是有效的,其条件是存在规范推导ωβαβωα21⇒⇒'A S 。

一般而言,同一项目可能对几个活前缀都是有效的(当一个项目出现在几个不同的集合中时便是这种情形)。

若归约项目A →β1.对活前缀1αβ是有效的,则它告诉我们应把符号串1β归约为A ,即把活前缀1αβ变成αA 。

若移进项目A →β1.β2对活前缀1αβ是有效的,则它告诉我们,句柄尚未形成,因此,下一步动作应是移进。

但是,可能存在这样的情形,对同一活前缀,存在若干项目对它都是有效的。

而且它们告诉我们应做的事情各不相同,互相冲突。

这种冲突通过向前多看几个输入符号,或许能够获得解决。

对于每个活前缀,我们可以构造它的有效项目集。

实际上,一个活前缀γ的有效项目集正是从上述的DFA 的初态出发,经读出γ后而到达的那个项目集(状态)。

换言之,在任何时候,分析栈中的活前缀X 1X 2…X m 的有效项目集正是栈顶状态S m 所代表的那个集合。

这是LR 分析理论的一条基本定理。

实际上,栈顶的项目集(状态)体现了栈里的一切有用信息——历史。

前面我们已经对LR (0)文法进行了定义,下面我们来看一下LR (0)分析表是如何构造的。

对于LR (0)文法,我们可以直接从它的项目集规范族C 和活前缀识别自动机的状态转换函数GO 构造出LR 分析表。

下面是构造LR (0)分析表的算法。

假定C={I 0, I 1,…,In},令每个项目集I k 的下标k 为分析器的一个状态,因此,G '的LR(0)分析表含有状态0,1,…,n 。

令那个含有项目S '→.S 的I k 的下标k 为初态。

ACTION 子表和GOTO 子表可按如下方法构造:(1)若项目A →α.a β属于I k 且GO (I k , a)= I j , a 为终结符,则置ACTION[k,a]为“把状态j和符号a移进栈”,简记为“s j”;(2)若项目A→α.属于I k,那么,对任何终结符a,置ACTION[k,a]为“用产生式A→α进行规约”,简记为“r j”;其中,假定A→α为文法G'的第j个产生式;(3)若项目S'→S.属于I k, 则置ACTION[k, #]为“接受”,简记为“acc”;(4)若GO (I k, A)= I j, A为非终结符,则置GOTO[k, A]=j;(5)分析表中凡不能用上述1至4填入信息的空白格均置上“出错标志”。

相关文档
最新文档