SLR(1)文法分析实验报告
SLR(1)分析法
SLR(1)分析法由于LR(0)的能⼒实在是太弱了。
例如:I = { X=>α·bβ, A=>α·, B=>α· }这时候就存在两个冲突。
1、移进和规约的冲突;2、规约和规约的冲突。
SLR(1)就是为了解决冲突⽽设计的,解决冲突的⽅法就是向后多看⼀个字符,这就是SLR(1)。
简⽽⾔之就是为每个⾮终结符,计算出它们的follow集。
从⽽可以解决移进与规约、规约与规约的冲突了。
SLR(1)所说的多看⼀个字符在构造分析表的时候就根据follow集已经构造好了,分析程序和LR(0)是⼀样的,分析表不同。
具体实现如下:拓⼴⽂法 G'[S']:(0) S'→S(1) S→ABC(2) A→Aa(3) A→a(4) B→Bb(5) B→b(6) C→Cc(7) C→c1、计算初始状态的项⽬集Q0=CLOSURE({S'→•S })={ S'→•S , S→•ABC, A→•Aa, A→•a };2、计算每个状态的项⽬集Q1=GO(Q0,a)=CLOSURE({A→a •})={ A→a• };Q2=GO(Q0,S)=CLOSURE({S'→S •})={ S'→S • };Q3=GO(Q0,A) = CLOSURE({S→A•BC, A→A•a}) = {S→A•BC, A→A•a, B→•Bb, B→•b}; Q4=GO(Q3,a)=CLOSURE({A→Aa• })={ A→Aa• }; Q5=GO(Q3,b)=CLOSURE({B→b• })={ B→b•};Q6=GO(Q3,B)=CLOSURE({S→AB•C, B→B•b }) ={ S→AB•C, B→B•b , C→•Cc , C→•c }; Q7=GO(Q6,b)=CLOSURE({B→Bb •})={ B→Bb •}; Q8=GO(Q6,c)=CLOSURE({C→c •})={ C→c •};Q9=GO(Q6,C)=CLOSURE({S→ABC•, C→C•c })={ S→ABC•, C→C•c }; Q10=GO(Q9,c)=CLOSURE({C→Cc• })={ C→Cc•};3、构造识别可归约前缀的 DFA4、计算⽂法的 FIRST 和 FOLLOW 集合⾮终结符FIRST FOLLOWS a#A a a,bB b b,cC c c,#状态节点 Q9= { S→ABC•, C→C•c }中存在存在移进-规约冲突。
slr1文法
SLR(1)文法一、引言SLR(1)文法,全称为“简单优先文法”,是计算机科学中编译器设计和语言理论的一个重要概念。
它是一种上下文无关文法,使用一个栈来存储语法信息,并根据简单的优先级规则进行扩展。
本文将详细解释SLR(1)文法的定义、特性、应用和计算过程,并通过实例分析其工作原理。
二、SLR(1)文法定义SLR(1)文法是一种上下文无关文法,它使用一个栈来存储语法信息。
在每一步解析过程中,它选择具有最高优先级的产生式进行扩展。
如果存在多个具有相同优先级的产生式,则选择左边的那个。
如果栈为空或者无法选择合适的产生式进行扩展,则发生语法错误。
三、SLR(1)文法的特性SLR(1)文法具有以下特性:1.上下文无关性:SLR(1)文法是一种上下文无关文法,语法规则的适用不依赖于上下文环境。
2.简单优先级:在每一步解析过程中,SLR(1)文法选择具有最高优先级的产生式进行扩展。
优先级由产生式的左部符号决定。
3.栈的使用:SLR(1)文法使用一个栈来存储语法信息,以便在解析过程中进行产生式的扩展。
4.左角限制:如果存在多个具有相同优先级的产生式,SLR(1)文法只选择左角的产生式进行扩展。
5.语法错误处理:如果栈为空或者无法选择合适的产生式进行扩展,SLR(1)文法则认为存在语法错误。
四、SLR(1)文法的应用SLR(1)文法在编译器设计和语言理论中有广泛的应用。
它主要用于确定语言的语法结构,并生成相应的解析器。
通过将源代码转换为抽象语法树(Abstract Syntax Tree, AST),可以将源代码转换为可执行的机器代码或中间代码。
此外,SLR(1)文法还可以用于自然语言处理、文本挖掘等领域。
五、SLR(1)文法的计算过程SLR(1)文法的计算过程包括以下步骤:1.定义:为每个非终结符生成一个包含优先级和产生式的表格。
这个表格定义了每个非终结符的优先级和可能的产生式。
2.解析:根据输入的字符串,使用栈来存储语法信息,并根据优先级和产生式表格进行解析。
编译原理实验报告-语法分析
编译原理课程实验报告实验2:语法分析
(2)输出针对此测试程序对应的语法错误报告;
四、实验中遇到的问题总结
(一)实验过程中遇到的问题如何解决的?
问题1:关于action表中需要存储空‘#’以代表在某个状态读入空后所应该进行的动作,如何在action表中安排空这一列?
答:以0代表空,所以action表的列数为终结符数量加1,其中第0列表示某状态读入空时应该执行的动作。
问题2:关于数据结构,显然,文法中的终结符和非终结符都应该有一个唯一的标号来标识这是哪个文法符号,如何进行存储(文件和内存中)?用什么约束使得处理得到简化?答:我是通过一个short型的整型数标识文法符号的;文法输入文件的约束是,以终极符的数量加一为第一个非终结符的标识值,之后依次加一,必须连续且不重复。
对于终结符,从1开始为第1个终结符的标识值(0代表空),以后依次加一,必须连续且不重复;如此设计可以方便后续的action表和goto表的构建和查询操作。
问题3:构建项目集规范族或计算first集和follow集的过程中常常需要用到集合操作,如何编写相关代码?
答:可以直接使用现有的库或者自己实现一个set数据结构。
实验三 LR(1)分析表语法分析报告
学生实验报告(理工类)课程名称:编译原理专业班级:08计算机科学与技术(单)本所属院部:信息技术学院指导教师:洪蕾20 10 ——20 11 学年第二学期金陵科技学院教务处制实验报告书写要求实验报告原则上要求学生手写,要求书写工整。
若因课程特点需打印的,要遵照以下字体、字号、间距等的具体要求。
纸张一律采用A4的纸张。
实验报告书写说明实验报告中一至四项内容为必填项,包括实验目的和要求;实验仪器和设备;实验内容与过程;实验结果与分析。
各院部可根据学科特点和实验具体要求增加项目。
填写注意事项(1)细致观察,及时、准确、如实记录。
(2)准确说明,层次清晰。
(3)尽量采用专用术语来说明事物。
(4)外文、符号、公式要准确,应使用统一规定的名词和符号。
(5)应独立完成实验报告的书写,严禁抄袭、复印,一经发现,以零分论处。
实验报告批改说明实验报告的批改要及时、认真、仔细,一律用红色笔批改。
实验报告的批改成绩采用百分制,具体评分标准由各院部自行制定。
实验报告装订要求实验批改完毕后,任课老师将每门课程的每个实验项目的实验报告以自然班为单位、按学号升序排列,装订成册,并附上一份该门课程的实验大纲。
实验项目名称: LR(1)分析表语法分析实验学时: 6 同组学生姓名:无实验地点: B513 实验日期: 2011.4.7/4.21 实验成绩:批改教师:批改时间:一、实验目的和要求语法分析主要目的是按照程序语言的语法规则,从由词法分析输出的源程序符号串中识别出各类语法成分,同时进行语法检查,为语义分析和代码生成作准备.语法分析程序在分析过程中检查符号串是否为该程序的句子.若是则输出该句子的分析树,否则就表示源程序存在语法错误,并报告错误的性质与位置.二、实验仪器和设备主机一台:有Visual Studio 2005工具三、实验过程说明:此程序共有两个类,Lexical进行词法分析,Syntax进行语法分析.对于语法分析,采用LR(1)分析法,判断程序是否满足规定的结构.1:LR-table.txt:存放分析表,其中正数表示移进,负数表示归约,100表示接受状态,0表示不操作。
实验2 语法分析(SLR(1)分析)
实验2 语法分析(SLR(1)分析)一、实验任务:文法为:E→ E+T | E-T | TT→ T*F | T/F | FF→(E)| i根据SLR(1)分析法,对表达式进行语法分析,判断一个表达式是否正确。
二、实验时间:上机2次。
三、实验过程和指导:(一)准备:1.判别该文法是否为SLR(1)文法;若是,设计出SLR(1)分析表;2.考虑好SLR(1)分析法的设计方案,设计出模块结构和测试数据;3.初步编制好程序。
(二)上机实验:上机调试,发现错误,分析错误,逐渐修改完善。
(三)程序要求:程序输入/输出示例:如参考C语言的运算符。
输入如下表达式(以分号为结束)和输出结果:(1)10输出:正确(2)1+2*(15-6)输出:正确(3)(1+2)/3+4- (11+6/7)输出:正确(4)((1-2)/3+4输出:错误,出错位置是(5)1+2-3+(*4/5)输出:错误,出错位置是注意:1.为降低难度,表达式中不含变量(只含无符号整数);2.可以直接调用此法分析程序,取得单词;3.分析表有两个:ACTION表和GOTO表;4.分析过程有两个栈:状态栈和符号栈;5.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好,最好有详细的出错位置和出错性质说明);6.测试用的表达式事先放在文本文件中,一行存放一个表达式,同时以分号分割。
同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照;7.对学有余力的同学,可增加功能:当判断一个表达式正确时,输出计算结果,计算过程用浮点表示,但要注意不要被0除。
(四)练习该实验的目的和思路:程序比较复杂,需要利用到大量的编译原理,也用到了大量编程技巧和数据结构,通过这个练习可极大提高编程能力。
程序规模大概为四百行。
通过练习,掌握对表达式进行处理的一种方法。
(四)为了能设计好程序,注意以下事情:1.模块设计:将程序分成合理的多个模块(函数),每个模块做具体的同一事情。
SLR_分析报告表地生成以及分析报告程序
SLR 分析表的生成以及分析程序SLR语法分析自动生成程序实验文档1. 在程序中表示文法1.1 文法的输入和读取为了程序读取的方便,非/终结符相互间以空格分开。
例如应该输入:E -> E + TT -> T * F | TF -> ( E ) | idE -> T而不是输入:E->E+T|T……文法先保存到文件中然后程序读取文件。
1.2 文法的拓展为了在LR分析时能够指示分析器正确停止并接受输入,一般在所有输入文法前加上一个新的产生式,以上面文法为例,我们要保存的文法应该是如此:E’ -> E + TE -> T *F | T……1.3 文法的保存格式设计一个类Grammar来对文法进行各种处理。
首先把文件中的文法保存到一个序偶表中,以上面的文法为例子,我们保存的格式类似于下面的表非终结符产生试右部EE + TTTT * FTF( E )id也就是说,每一个项是一个2元组,记录了终结符,和产生式右部。
其中非终结符可以用字符串(string)类型表示,产生式右部可用字符串数组( vector<string > )表示。
而在保存的同时又可记录下文法的所有非终结符(因为文法的产生式左部会出现所有的非终结符),然后再对已经记录的文法的产生式右部再扫描一遍,记录下所有的终结符。
在本程序中,我虽然记录了原始的符号串,但是在具体过程处理时使用的是符号串对应的下标来进行的,因此再对原始形式的文法再扫描一遍,生成对应的以下标形式保存的文法。
同时我对终结符号和非终结符号的保存位于不同的数组中,于是下标就会产生冲突,我采用方式是建立一个下标数据结构 Index 来保存下标struct Index{int index; // [非终结符或者终结符的下标]bool teminal; // [为真表示该下标保存的是终结符]bool is_nonteminal(); // [返回! terminal]}现在往类Grammar 中加入数据成员为:vector< pair< string,vector<string > > > m_str_grammar ; // [记录以字符串形式保存的文法]vector< vector<vector<Index > > > m_idx_grammar; // [记录以下标保存的文法]MyCollection m_str_nonteminals; // [记录原始的非终结符号串]MyCollection m_str_terminals; // [记录原始的终结符号串]接下来要对文法进行相关处理了。
SLR[1]分析器设计实验报告
编译原理实验报告题目: SLR(1)分析器的设计 学 院 计算机科学与技术专 业 xxxxxxxxxxxxxxxxx学 号 xxxxxxxxxxxxx姓 名 宁剑指导教师 xx20xx 年xx 月xx 日SLR(1)分析器的设计一、实验目的装订线构造LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。
二、实验原理对下列文法,用LR(1)分析法对任意输入的符号串进行分析:S->EE->E+TE->TT->T*FT->FF->(E)F->i三、实验步骤1.总控程序,也可以称为驱动程序。
对所有的LR分析器总控程序都是相同的。
2.分析表或分析函数,不同的文法分析表将不同,同一个文法采用的LR分析器不同时,分析表将不同,分析表又可以分为动作表(ACTION)和状态转换(GOTO)表两个部分,它们都可用二维数组表示。
3.分析栈,包括文法符号栈和相应的状态栈,它们均是先进后出栈。
分析器的动作就是由栈顶状态和当前输入符号所决定。
LR分析器由三个部分组成:其中:SP为栈指针,S[i]为状态栈,X[i]为文法符号栈。
状态转换表用GOTO[i,X]=j表示,规定当栈顶状态为i,遇到当前文法符号为X时应转向状态j,X为终结符或非终结符。
ACTION[i,a]规定了栈顶状态为i时遇到输入符号a应执行。
动作有四种可能:(1)移进:action[i,a]= Sj:状态j移入到状态栈,把a移入到文法符号栈,其中i,j 表示状态号。
(2)归约:action[i,a]=rk:当在栈顶形成句柄时,则归约为相应的非终结符A,即文法中有A- B的产生式,若B的长度为R(即|B|=R),则从状态栈和文法符号栈中自顶向下去掉R 个符号,即栈指针SP减去R,并把A移入文法符号栈内,j=GOTO[i,A]移进状态栈,其中i 为修改指针后的栈顶状态。
SLR(1)分析法
• 已知文法GB:B → bB | dDb • D → aD | ε • 提示: .ε=ε.=. 且 |ε|=0 • ① 求出每个非终结符的First集、Follow集和 Select集;判定该文法是LL(1)文法。 • ② 构造GB的递归下降分析程序。 • ③ 构造GB的预测分析表。 • ④ 给出字符串bdab的LL(1)分析过程。
说明:产生式 编号可以不从1 开始,但是与归 约符r的下标必 须一致; SLR(1)表中 的行可以任意排 列,但是必须与 项目集编号一致。
• ⑥ SLR(1)分析表构造如下:
⑦ 显然项目集I3、I6中有“移进--归约”冲突,GB不是LR(0)文法。
因为SLR(1)分析表中无多重入口,所以GB是S范句型活前缀的自 动机。 ⑥ 构造SLR(1)分析表。 ⑦ GB是LR(0)文法吗?GB是SLR(1)文法吗?为什么? ⑧ 给出字符串bdab的SLR(1)分析过程。 解: 每个非终结符的First集、Follow集:
• ⑤ 识别GB拓广文法的所有LR(0)项目的DFA构造如下:
⑧字符串bdab的SLR(1)分析过程如下:
(完整word版)SLR(1)文法分析实验报告
《编译原理》课程设计报告—SLR(1)分析的实现学院计算机科学与技术专业计算机科学与技术学号学生姓名指导教师姓名2015年12月26日目录1.设计的目的与内容 (1)1。
1课程设计的目的 (1)1。
2设计内容 (1)1。
3设计要求 (1)1。
4理论基础 (1)2算法的基本思想 (2)2.1主要功能函数 (2)2.2算法思想 (3)SLR文法构造分析表的主要思想: (3)解决冲突的方法: (3)SLR语法分析表的构造方法: (4)3主要功能模块流程图 (5)3。
1主函数功能流程图 (5)4系统测试 (6)5 结论 (11)附录程序源码清单 (12)1.设计的目的与内容1.1课程设计的目的编译原理课程设计是计算机专业重要的教学环节,它为学生提供了一个既动手又动脑,将课本上的理论知识和实际有机的结合起来,独立分析和解决实际问题的机会.●进一步巩固和复习编译原理的基础知识.●培养学生结构化程序、模块化程序设计的方法和能力。
●提高学生对于编程语言原理的理解能力。
●加深学生对于编程语言实现手段的印象。
1.2设计内容构造LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。
1。
3设计要求1)SLR(1)分析表的生成可以选择编程序生成,也可选择手动生成;2)程序要求要配合适当的错误处理机制;3)要打印句子的文法分析过程。
1。
4理论基础由于大多数适用的程序设计语言的文法不能满足LR(0)文法的条件,即使是描述一个实数变量说明这样简单的文法也不一定是LR(0)文法.因此对于LR(0)规范族中有冲突的项目集(状态)用向前查看一个符号的办法进行处理,以解决冲突。
这种办法将能满足一些文法的需要,因为只对有冲突的状态才向前查看一个符号,以确定做那种动作,因而称这种分析方法为简单的LR(1)分析法,用SLR(1)表示。
12算法的基本思想2。
最新广东海洋大学编译原理LL(1)文法分析器实验(java)
GDOU-B-11-112广东海洋大学学生实验报告书(学生用表)实验名称实验3:语法分析课程名称编译原理课程号16242211 学院(系) 数学与计算机学院专业计算机科学与技术班级计科1141学生姓名学号实验地点科425 实验日期2017.4.21一、实验目的熟悉语法分析的过程;理解相关文法的步骤;熟悉First集和Follow集生成二、实验要求对于给定的文法,试编写调试一个语法分析程序:要求和提示:(1)可选择一种你感兴趣的语法分析方法(LL(1)、算符优先、递归下降、SLR(1)等)作为编制语法分析程序的依据。
(2)对于所选定的分析方法,如有需要,应选择一种合适的数据结构,以构造所给文法的机内表示。
(3)能进行分析过程模拟。
如输入一个句子,能输出与句子对应的语法树,能对语法树生成过程进行模拟;能够输出分析过程每一步符号栈的变化情况。
设计一个由给定文法生成First集和Follow集并进行简化的算法动态模拟。
三、实验过程1:文法:E->TE’E’->+TE’|εT->FT’T’->*FT’|εF->(E)|i:2程序描述(LL(1)文法)本程序是基于已构建好的某一个语法的预测分析表来对用户的输入字符串进行分析,判断输入的字符串是否属于该文法的句子。
基本实现思想:接收用户输入的字符串(字符串以“#”表示结束)后,对用做分析栈的一维数组和存放分析表的二维数组进行初始化。
然后取出分析栈的栈顶字符,判断是否为终结符,若为终结符则判断是否为“#”且与当前输入符号一样,若是则语法分析结束,输入的字符串为文法的一个句子,否则出错若不为“#”且与当前输入符号一样则将栈顶符号出栈,当前输入符号从输入字符串中除去,进入下一个字符的分析。
若不为“#”且不与当前输入符号一样,则出错。
四、程序流程图本程序中使用以下文法作对用户输入的字符串进行分析:E→TE’E’→+TE’|εT→FT’T’→*FT’|εF→i|(E)该文法的预测分析表为:五:结果及截图1、显示预测分析表,提示用户输入字符串2、输入的字符串为正确的句子:3、输入的字符串中包含了不属于终结符集的字符4、输入的字符串不是该文法能推导出来的句子程序代码:package complier;import java.io.*;public class LL {String Vn[] = { "E", "E'", "T", "T'", "F" }; // 非终结符集String Vt[] = { "i", "+", "*", "(", ")", "#" }; // 终结符集String P[][] = new String[5][6]; // 预测分析表String fenxi[] ; // 分析栈int count = 1; // 步骤int count1 = 1;//’分析栈指针int count2 = 0, count3 = 0;//预测分析表指针String inputString = ""; // 输入的字符串boolean flag;public void setCount(int count, int count1, int count2, int count3){ this.count = count;this.count1 = count1;this.count2 = count2;this.count3 = count3;flag = false;}public void setFenxi() { // 初始化分析栈fenxi = new String[20];fenxi[0] = "#";fenxi[1] = "E";}public void setP() { // 初始化预测分析表for (int i = 0; i < 5; i++) {for (int j = 0; j < 6; j++) {P[i][j] = "error";}}P[0][0] = "->TE'";P[0][3] = "->TE'";P[1][1] = "->+TE'";P[1][4] = "->ε";P[1][5] = "->ε";P[2][0] = "->FT'";P[2][3] = "->FT'";P[3][1] = "->ε";P[3][2] = "->*FT'";P[3][4] = "->ε";P[3][5] = "->ε";P[4][0] = "->i";P[4][3] = "->(E)";// 打印出预测分析表System.out.println(" 已构建好的预测分析表");System.out.println("----------------------------------------------------------------------");for (int i=0; i<6; i++) {System.out.print(" "+Vt[i]);}System.out.println();System.out.println("----------------------------------------------------------------------");for (int i=0; i<5; i++) {System.out.print(" "+Vn[i]+" ");for (int j=0; j<6; j++) {int l = 0;if (j>0) {l = 10-P[i][j-1].length();}for (int k=0; k<l; k++) {System.out.print(" ");}System.out.print(P[i][j]+" ");}System.out.println();}System.out.println("----------------------------------------------------------------------");}public void setInputString(String input) {inputString = input;}public boolean judge() {String inputChar = inputString.substring(0, 1); // 当前输入字符boolean flage = false;if (count1 >= 0) {for (int i=0; i<6; i++) {if (fenxi[count1].equals(Vt[i])) { // 判断分析栈栈顶的字符是否为终结符flage = true;break;}}}if (flage) {// 为终结符时if (fenxi[count1].equals(inputChar)) {if (fenxi[count1].equals("#")&&inputString.length()==1) { // 栈顶符号为结束标志时// System.out.println("最后一个");String fenxizhan = "";for (int i=0; i<=P.length; i++) { // 拿到分析栈里的全部内容(滤去null)if (fenxi[i] == null) {break;} else {fenxizhan = fenxizhan + fenxi[i];}}// 输出当前分析栈情况,输入字符串,所用产生式或匹配System.out.print(" " + count);String countToString = Integer.toString(count);int farWay = 14 - countToString.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.print(fenxizhan);farWay = 20 - fenxizhan.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.print(inputString);farWay = 25 - inputString.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.println("接受");flag = true;return true;} else {// 分析栈栈顶符号不为结束标志符号时String fenxizhan = "";for (int i=0; i<=P.length; i++) { // 拿到分析栈里的全部内容(滤去null)if (fenxi[i] == null) {break;} else {fenxizhan = fenxizhan + fenxi[i];}}// 输出当前分析栈情况,输入字符串,所用产生式或匹配System.out.print(" "+count);String countToString = Integer.toString(count);int farWay = 14 - countToString.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.print(fenxizhan);farWay = 20 - fenxizhan.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.print(inputString);farWay = 25 - inputString.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.println("\"" + inputChar + "\"" + "匹配");// 将栈顶符号出栈,栈顶指针减一fenxi[count1] = null;count1 -= 1;if (inputString.length() > 1) { // 当当前输入字符串的长度大于1时,将当前输入字符从输入字符串中除去inputString = inputString.substring(1, inputString.length());} else { // 当前输入串长度为1时inputChar = inputString;}// System.out.println(" "+count+" "+fenxizhan+"// "+inputString +" "+P[count3][count2]);// System.out.println(count + inputChar + "匹配 ");count++;judge();}}else { // 判断与与输入符号是否一样为结束标志System.out.println(" 分析到第" + count + "步时出错!");flag = false;return false;}} else {// 非终结符时boolean fla = false;for (int i=0; i<6; i++) { // 查询当前输入符号位于终结符集的位置if (inputChar.equals(Vt[i])) {fla = true;count2 = i;break;}}if(!fla){System.out.println(" 分析到第" + count + "步时出错!");flag = false;return false;}for (int i=0; i<5; i++) { // 查询栈顶的符号位于非终结符集的位置if (fenxi[count1].equals(Vn[i])) {count3 = i;break;}}if (P[count3][count2] != "error") { // 栈顶的非终结符与输入的终结符存在产生式时String p = P[count3][count2];String s1 = p.substring(2, p.length()); // 获取对应的产生式if (s1.equals("ε")) { // 产生式推出“ε”时String fenxizhan = "";for (int i=0; i<=P.length; i++) {if (fenxi[i] == null) {break;} else {fenxizhan = fenxizhan + fenxi[i];}}// 输出当前分析栈情况,输入字符串,所用产生式或匹配System.out.print(" " + count);String countToString = Integer.toString(count);int farWay = 14 - countToString.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.print(fenxizhan);farWay = 20 - fenxizhan.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.print(inputString);farWay = 25 - inputString.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.println(fenxi[count1] + P[count3][count2]);// 将栈顶符号出栈,栈顶指针指向下一个元素fenxi[count1] = null;count1 -= 1;count++;judge();} else { // 产生式不推出“ε”时int k = s1.length();String fenxizhan = "";for (int i=0; i<=P.length; i++) {if (fenxi[i] == null) {break;} else {fenxizhan = fenxizhan + fenxi[i];}}// 输出当前分析栈情况,输入字符串,所用产生式或匹配System.out.print(" "+count);String countToString = Integer.toString(count);int farWay = 14 - countToString.length();for (int o=0; o<farWay; o++) {System.out.print(" ");}System.out.print(fenxizhan);farWay = 20 - fenxizhan.length();for (int o=0; o<farWay; o++) {System.out.print(" ");}System.out.print(inputString);farWay = 25 - inputString.length();for (int o=0; o<farWay; o++) {System.out.print(" ");}System.out.println(fenxi[count1] + P[count3][count2]);for (int i=1; i<=k; i++) { // 将产生式右部的各个符号入栈String s2 = s1.substring(s1.length() - 1,s1.length());s1 = s1.substring(0, s1.length() - 1);if (s2.equals("'")) {s2= s1.substring(s1.length() - 1, s1.length())+ s2;i++;s1 = s1.substring(0, s1.length() - 1);}fenxi[count1] = s2;if (i < k)count1++;// System.out.println("count1=" + count1);}// System.out.println(" "+count+" "+fenxizhan+"// "+inputString +" "+P[count3][count2]);count++;// System.out.println(count);judge();}} else {System.out.println(" 分析到第" + count + "步时出错!");flag = false;return false;}}return flag;}public static void main(String args[]) {LL l = new LL();l.setP();String input = "";boolean flag = true;while (flag) {try {InputStreamReader isr = new InputStreamReader(System.in);BufferedReader br = new BufferedReader(isr);System.out.println();System.out.print("请输入字符串(输入exit退出):");input = br.readLine();} catch (Exception e) {e.printStackTrace();}if(input.equals("exit")){flag = false;}else{l.setInputString(input);l.setCount(1, 1, 0, 0);l.setFenxi();System.out.println();System.out.println("分析过程");System.out.println("----------------------------------------------------------------------");System.out.println(" 步骤 | 分析栈 | 剩余输入串 | 所用产生式 ");System.out.println("----------------------------------------------------------------------");boolean b = l.judge();System.out.println("----------------------------------------------------------------------");if(b){System.out.println("您输入的字符串"+input+"是该文发的一个句子");}else{System.out.println("您输入的字符串"+input+"有词法错误!");}}}}}六:实验心得通过本次实验基本掌握了语法分析的原理和LL(1)语法分析方法,以及预测分析表的构造,进一步熟悉了语法分析的详细过程,收获还是蛮大的,值得我们认真对待。
实验5---语法分析器(自下而上):LR(1)分析法
实验5---语法分析器(自下而上):LR(1)分析法实验5---语法分析器(自下而上):LR(1)分析法一、实验目的构造LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。
二、实验内容程序输入/输出示例(以下仅供参考):对下列文法,用LR(1)分析法对任意输入的符号串进行分析:(1)E->E+T(2)E->E—T(3)T->T*F(4)T->T/F(5)F-> (E)(6)F->i输出的格式如下:(1)LR(1)分析程序,编制人:姓名,学号,班级(2)输入一个以#结束的符号串(包括+—*/()i#):在此位置输入符号串(3)输出过程如下:3.对学有余力的同学,测试用的表达式事先放在文本文件中,一行存放一个表达式,同时以分号分割。
同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照。
三、实验方法1.实验采用C++程序语言进行设计,文法写入程序中,用户可以自定义输入语句;2.实验开发工具为DEV C++。
四、实验步骤1.定义LR(1)分析法实验设计思想及算法①若ACTION[sm , ai] = s则将s移进状态栈,并把输入符号加入符号栈,则三元式变成为:(s0s1…sm s , #X1X2…Xm ai , ai+1…an#);②若ACTION[sm , ai] = rj则将第j个产生式A->β进行归约。
此时三元式变为(s0s1…sm-r s , #X1X2…Xm-rA , aiai+1…an#);③若ACTION[sm , ai]为“接收”,则三元式不再变化,变化过程终止,宣布分析成功;④若ACTION[sm , ai]为“报错”,则三元式的变化过程终止,报告错误。
2.定义语法构造的代码,与主代码分离,写为头文件LR.h。
3.编写主程序利用上文描述算法实现本实验要求。
7.3 SLR(1)分析
SLR(1)是采用向前查看一个符号的办法来处理 是采用向前查看一个符号的办法来处理LR(0)规 是采用向前查看一个符号的办法来处理 规 范族中出现冲突的问题。它是最简单的LR(1)方法。 范族中出现冲突的问题。它是最简单的 方法。 方法 例1:已知拓展文法G’[S’]: (实数说明文法) 已知拓展文法 (0)S’→S (1)S→rD (2)D→D, i (3)D→i 构造文法G’的分析表 构造文法 的分析表
SLR(1)中冲突的解决方法 中冲突的解决方法
若LR(0)规范族含有m个移进项目 A1→α1·a1β1,A1→α2·a2β2,…, Am→αm·amβm 同时含有n个归约项目 B1→γ1·,B2→γ2·,…,Bn→γn· 则只要集合 1 , a2 ,…, am}和FOLLOW(B1), FOLLOW(B2) , …, 只要集合{a 只要集合 和 FOLLOW(Bn)两两交集都为空 两两交集都为空,那么上述规则仍可用于解决 两两交集都为空 LR(0)规范族中的冲突。 1) 若a∈{a1,a2,…, am},则移进。 2) 若a∈FOLLOW(Bi),i=1,2…n,则用Bi→γi进行归约。 3) 此外,报错。
SLR(1)分析表的构造 分析表的构造
改进:对所有归约项目都采取SLR(1)的处理思想 凡是归 的处理思想,凡是归 改进:对所有归约项目都采取 的处理思想
约项目仅当面临输入符号包含在该归约项目左部非终结符 集合中, 的FOLLOW集合中,才采取用该产生式归约的动作。 集合中 才采取用该产生式归约的动作。 改进的SLR(1)分析表的构造方法如下: 改进的 分析表的构造方法如下: 分析表的构造方法如下 假设已构造出文法的LR(0)项目集规范族C={I0,I1,…,In},令包 含S’→·S项目的集合Ik的下标k为分析器初态,求出所有非 终结符的FOLLOW集。则SLR(1)分析表构造步骤为
实验二--LL(1)分析法实验报告
实验二LL(1) 分析法一、实验目的通过完成预测分析法的语法分析程序,了解预测分析法和递归子程序法的区别和联系。
使学生了解语法分析的功能,掌握语法分析程序设计的原理和构造方法,训练学生掌握开发应用程序的基本方法。
有利于提高学生的专业素质,为培养适应社会多方面需要的能力。
二、实验内容及设计原理所谓LL (1)分析法,就是指从左到右扫描输入串(源程序) ,同时采用最左推导,且对每次直接推导只需向前看一个输入符号,便可确定当前所应当选择的规则。
实现LL (1)分析的程序又称为LL (1)分析程序或LL1 (1)分析器。
我们知道一个文法要能进行LL( 1 )分析,那么这个文法应该满足:无二义性,无左递归,无左公因子。
当文法满足条件后,再分别构造文法每个非终结符的FIRST 和FOLLOW 集合,然后根据FIRST 和FOLLOW 集合构造LL(1 ) 分析表,最后利用分析表,根据LL(1) 语法分析构造一个分析器。
LL (1 )的语法分析程序包含了三个部分,总控程序,预测分析表函数,先进先出的语法分析栈,本程序也是采用了同样的方法进行语法分析,该程序是采用了C++ 语言来编写,其逻辑结构图如下:LL (1 )预测分析程序的总控程序在任何时候都是按STACK栈顶符号X和当前的输入符号a做哪种过程的。
对于任何(X,a),总控程序每次都执行下述三种可能的动作之一:(1)若X = a = ‘ #',则宣布分析成功,停止分析过程。
(2)若X = a ‘ #',则把<从STACK栈顶弹出,让a指向下一个输入符号。
(3)若X是一个非终结符,则查看预测分析表M。
若M[A , a]中存放着关于X 的一个产生式,那么,首先把X 弹出STACK 栈顶,然后,把产生式的右部符号串按反序一一弹出STACK栈(若右部符号为£,则不推什么东西进STACK栈)。
若M[A ,a]中存放着“出错标志”,则调用出错诊断程序ERROR。
LR(1)分析法
LR(1)分析法SLR(1)⽅法的出现,解决了⼤部分的移进和规约冲突、规约和规约的冲突。
并且SLR(1)其优点是状态数⽬少,造表算法简单,⼤多数程序设计语⾔基本上都可⽤SLR(1)⽂法来描述。
但是仍然有⼀些⽂法,不能⽤SLR(1)解决。
例如:S->BB;B->aB;B->b;该⽂法我们可以看到,在S->BB中,第⼀个B和第⼆个B的follow集是不同的。
为了解决这个问题,于是诞⽣了LR(1)分析⽅法。
解决办法是在每个项⽬集的产⽣式后加上follow集。
⽐如:S-> ·BB, #B-> · aB, a/bB-> · b ,a/b这样就是是同⼀个⾮终结符,但是仍旧可以根据不同状态集内的产⽣式的follow集进⾏不冲突的规约和移进。
⽬前LR(1)分析法仍旧是应⽤⾮常⼴泛,是当前最⼀般的分析⽅法,⼏乎所有的上下⽂⽆关⽂法描述的程序设计语⾔都可以通过LR(1)分析法分析。
为了解决LR(1)分析法状态过多的问题,于是提出了LALR(1)分析法,将“⼼”相同的状态合并,从⽽减少状态数。
具体例⼦如下:⽂法G[E](0)S’->S(1)S->BB(2)B->Ab(3)B->b1、构造项⽬集2、构造LR(分析表)状态a b#S B0S3S4121Acc2S6S753S3S484R3R35R16S6S796S69 7R38R29R23、编程1 #include<bits/stdc++.h>2#define ROW 113#define COLUMN 64using namespace std;5//产⽣式6string products[4][2]={7 {"S'","S"},8 {"S","BB"},9 {"B","aB"},10 {"B","b"}11 };12//分析表13string actiontable[ROW][COLUMN]={14 {"","a","b","#","S","B"},15 {"0","s3","s4","","1","2"},16 {"1","","","acc","",""},17 {"2","s6","s7","","","5"},18 {"3","s3","s4","","","8"},19 {"4","r3","r3","","",""},20 {"5","","","r1","",""},21 {"6","s6","s7","","","9"},22 {"7","","","r3","",""},23 {"8","r2","r2","","",""},24 {"9","","","r2","",""}25 };26 stack<int> sstatus; //状态栈27 stack<char> schar; //符号栈28struct Node{29char type;30int num;31 };32//打印步骤33void print_step(int times){34 stack<char> tmp2;35 cout<<times<<setw(4);36while(!schar.empty()){37char t=schar.top();38 schar.pop();39 tmp2.push(t);40 cout<<t;41 }42while(!tmp2.empty()){43int t=tmp2.top();44 tmp2.pop();45 schar.push(t);46 }47 }48//查表49 Node Action_Goto_Table(int status,char a){50int row=status+1;51string tmp;52for(int j=1;j<COLUMN;j++){53if(a==actiontable[0][j][0]){54 tmp=actiontable[row][j];55 }56 }57 Node ans;58if(tmp[0]>='0'&&tmp[0]<='9'){59int val=0;60for(int i=0;i<tmp.length();i++){61 val=val*10+(tmp[i]-'0');62 }63 ans.num=val;64 ans.type='';65 }else if(tmp[0]=='s'){66int val=0;67for(int i=1;i<tmp.length();i++){68 val=val*10+(tmp[i]-'0');69 }70 ans.type='s';71 ans.num=val;72 }else if(tmp[0]=='r'){73int val=0;74for(int i=1;i<tmp.length();i++){75 val=val*10+(tmp[i]-'0');76 }77 ans.type='r';78 ans.num=val;79 }else if(tmp[0]=='a'){80 ans.type='a';81 }else{82 ans.type='';83 }84return ans;85 }86//LR(1)分析法87bool LR1(string input){88while(!sstatus.empty()){89 sstatus.pop();90 }91while(!schar.empty()){92 schar.pop();93 }94int times=0;95bool flag=true;96int st=0;97 sstatus.push(st);98 schar.push('#');99int i=0;100char a=input[i];101while(true){102 Node action=Action_Goto_Table(st,a); 103if(action.type=='s'){104 st=action.num;105 sstatus.push(st);106 schar.push(a);107 a=input[++i];108 print_step(++times);109 cout<<setw(10)<<'s'<<st<<endl; 110111 }else if(action.type=='r'){112int n=action.num;113string ls=products[n][0];114string rs=products[n][1];115for(int j=0;j<rs.length();j++){116 sstatus.pop();117 schar.pop();118 }119 schar.push(ls[0]);120 st=sstatus.top();121 action =Action_Goto_Table(st,ls[0]);122 st=action.num;123 sstatus.push(st);124 print_step(++times);125 cout<<setw(10)<<'r'<<""<<ls<<"->"<<rs<<endl; 126127 }else if(action.type=='a'){128 flag=true;129break;130 }else{131 flag=false;132break;133 }134 }135return flag;136 }137int main(){138string input;139while(cin>>input){140if(LR1(input)){141 cout<<"syntax correct"<<endl;142 }else{143 cout<<"syntax error"<<endl;144 }145 }146return0;147 }。
文法的实验报告
实验名称:文法分析实验实验日期:2023年4月10日实验地点:计算机实验室实验目的:1. 理解文法分析的基本概念和原理。
2. 掌握使用文法分析工具进行语法分析的方法。
3. 分析给定文本的语法结构,提高对自然语言处理的认知。
实验器材:1. 计算机2. 文法分析工具(如:LL(1)分析器、LR(1)分析器等)3. 实验教材和参考资料实验步骤:一、文法分析基本概念介绍1. 定义文法:文法是描述一组字符串集合的规则,用于判断一个字符串是否属于该集合。
2. 语法分析:语法分析是自然语言处理中的一项基本任务,旨在将自然语言文本转换为结构化表示,如抽象语法树(AST)。
3. 文法分类:根据文法生成的方法,文法可以分为正规文法和上下文无关文法。
二、文法分析工具使用1. LL(1)分析器:LL(1)分析器是一种自底向上的分析器,适用于分析上下文无关文法。
其特点是易于实现,但只能处理部分上下文无关文法。
2. LR(1)分析器:LR(1)分析器是一种自底向上的分析器,适用于分析上下文无关文法。
其特点是能够处理更广泛的上下文无关文法,但实现相对复杂。
三、实验内容1. 分析给定文本的语法结构,提取出其文法规则。
2. 使用文法分析工具对文本进行语法分析,生成抽象语法树(AST)。
实验过程:一、文法规则提取以英文句子“Hello, how are you?”为例,其文法规则如下:S → NP VPNP → Det NVP → V NPDet → 'a' | 'an' | 'the'N → 'Hello' | 'how' | 'are' | 'you'V → 'are'二、文法分析工具使用1. 使用LL(1)分析器对句子进行语法分析:输入:Hello, how are you?输出:S -> NP VPNP -> Det NVP -> V NPDet -> 'the'N -> 'Hello'V -> 'are'NP -> Det NVP -> V NPDet -> 'how'N -> 'are'V -> 'you'2. 使用LR(1)分析器对句子进行语法分析:输入:Hello, how are you?输出:S -> NP VPNP -> Det NVP -> V NPDet -> 'the'N -> 'Hello'V -> 'are'NP -> Det NVP -> V NPDet -> 'how'N -> 'you'实验结果分析:通过使用文法分析工具对给定文本进行语法分析,我们可以清晰地看到文本的语法结构。
SLR(1)语法分析
构造LR(0)分析表的方法 构造LR(0)分析表的方法
生成文法G LR(0)项目 生成文法G的LR(0)项目
对文法G的每个产生式右部添加一个圆点,称为G的一个LR(0) 对文法G的每个产生式右部添加一个圆点,称为G的一个LR(0) 项目(简称项目) 项目(简称项目)
由项目构成识别文法活前缀的DFA 由项目构成识别文法活前缀的DFA
LR分析器工作过程算法描述: LR分析器工作过程算法描述:
一个LR分析器的工作过程可看成是栈里的状态序列,已规约串和输入串 一个LR分析器的工作过程可看成是栈里的状态序列,已规约串和输入串 所构成的三元式的变化过程.分析开始时的初始三元式为 (s0, #, a1a2……an#) a1a2……an#) 其中,s0为分析器的初态;#为句子的左括号;a1a2……an为输入串;其后的 其中,s0为分析器的初态;#为句子的左括号;a1a2……an为输入串;其后的 #为结束符(句子右括号).分析过程每步的结果可表示为 (s0s1……sm, s0s1……sm, #X1X2……Xm #X1X2……Xm ai, ai+1……an#) ai+1……an#) 分析器的下一步动作是由栈顶状态sm和现行输入符号ai所唯一决定的.即,执 分析器的下一步动作是由栈顶状态sm和现行输入符号ai所唯一决定的.即,执 行ACTION(sm,ai)所规定的动作.经执行每种可能的动作之后,三元式的 ACTION(sm,ai)所规定的动作.经执行每种可能的动作之后,三元式的 变化情形是: 若ACTION(sm,ai)为移进,且s = GOTO(sm,ai),则三元式变成: ACTION(sm,ai)为移进,且s GOTO(sm,ai),则三元式变成: (s0s1……sm s, #X1X2……Xm ai, ai+1……an#) s0s1……sm s, #X1X2……Xm ai+1……an#) 若ACTION(sm,ai)= {A→β},则按照产生式A→β进行规约.此时三元式变为 ACTION(sm,ai) {A→β},则按照产生式A (s0s1……sm s, #X1X2……Xm A, ai ai+1……an#) s0s1……sm s, #X1X2……Xm ai+1……an#) 此处s GOTO(Sm此处s = GOTO(Sm-r,A),r为β的长度,β = Xm-r+1……Xm. ),r 的长度,β Xm-r+1……Xm. 若ACTION(sm,ai)为"接受",则三元式不再变化,变化过程终止,宣布 ACTION(sm,ai)为"接受" 分析成功. 若ACTION(sm,ai)为"报错",则三元式的变化过程终止,报告错误. ACTION(sm,ai)为"报错" 一个LR分析器的工作过程就是一步一步的变换三元式,直至执行"接受" 一个LR分析器的工作过程就是一步一步的变换三元式,直至执行"接受"或 "报错"为止. 报错"
LR(1)分析法
课程: 编译原理实验报告系专业班级姓名学号指导教师学年学期实验2.3 LR(1)分析法1.实验目的1.构造LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子.2.实验平台Windows + VC + Win32 Console范例程序: “4-LR1.c”3.实验过程和指导1. 调试范例程序范例程序目前还不能对所有输入串进行正确的分析.输出格式如下:步骤状态栈符号栈输入串Action Goto(1)请输出完整的分析过程。
即详细输出每一步骤状态栈和符号栈的变化情况.(2)请输出最终的分析结果, 即输入串“合法”或“非法”.2. 对一个新的文法实现LR(1)分析。
4.程序代码第一种文法#include<stdio.h>#include<string.h>char *action[10][3]={"S3#","S4#",NULL, /*ACTION表*/NULL,NULL,"acc","S6#","S7#",NULL,"S3#","S4#",NULL,"r3#","r3#",NULL,NULL,NULL,"r1#","S6#","S7#",NULL,NULL,NULL,"r3#","r2#","r2#",NULL,NULL,NULL,"r2#"};int goto1[10][2]={1,2, /*QOTO表*/0,0,0,5,0,8,0,0,0,0,0,9,0,0,0,0,0,0};char vt[3]={'a','b','#'}; /*存放非终结符*/ char vn[2]={'S','B'}; /*存放终结符*/ char *LR[4]={"E->S#","S->BB#","B->aB#","B->b#"};/*存放产生式*/int a[10];char b[10],c[10],c1;int top1,top2,top3,top,m,n;void main(){int g,h,i,j,k,l,p,y,z,count;char x,copy[10],copy1[10];top1=0;top2=0;top3=0;top=0;a[0]=0;y=a[0];b[0]='#';count=0;z=0;printf("请输入表达式\n");do{scanf("%c",&c1);c[top3]=c1;top3=top3+1;}while(c1!='#');printf("步骤\t状态栈\t\t符号栈\t\t输入串\t\tACTION\tGOTO\n");do{y=z;m=0;n=0; /*y,z指向状态栈栈顶*/g=top;j=0;k=0;x=c[top];count++;printf("%d\t",count);while(m<=top1){ /*输出状态栈*/printf("%d",a[m]);m=m+1;}printf("\t\t");while(n<=top2){ /*输出符号栈*/printf("%c",b[n]);n=n+1;}printf("\t\t");while(g<=top3){ /*输出输入串*/ printf("%c",c[g]);g=g+1;}printf("\t\t");while(x!=vt[j]&&j<=2) j++;if(j==2&&x!=vt[j]){printf("error\n");return;}if(action[y][j]==NULL){printf("error\n");return;}elsestrcpy(copy,action[y][j]);if(copy[0]=='S'){ /*处理移进*/ z=copy[1]-'0';top1=top1+1;top2=top2+1;a[top1]=z;b[top2]=x;top=top+1;i=0;while(copy[i]!='#'){printf("%c",copy[i]);i++;}printf("\n");}if(copy[0]=='r'){ /*处理归约*/ i=0;while(copy[i]!='#'){printf("%c",copy[i]);i++;}h=copy[1]-'0';strcpy(copy1,LR[h]);while(copy1[0]!=vn[k]) k++;l=strlen(LR[h])-4;top1=top1-l+1;top2=top2-l+1;y=a[top1-1];p=goto1[y][k];a[top1]=p;b[top2]=copy1[0];z=p;printf("\t");printf("%d\n",p);}}while(action[y][j]!="acc");printf("acc\n");getchar();}测试一(1)测试bb#(2)测试abb#(3)测试abbb#第二种文发#include<iostream>#include<stack>using namespace std; stack<char> symbol;stack<int> state;char sen[50];char sym[12][6]={//符号表{'s','e','e','s','e','e'},{'e','s','e','e','e','a'},{'r','r','s','r','r','r'},{'r','r','r','r','r','r'},{'s','e','e','s','e','e'},{'r','r','r','r','r','r'},{'s','e','e','s','e','e'},{'s','e','e','s','e','e'},{'e','s','e','e','s','e'},{'r','r','s','r','r','r'},{'r','r','r','r','r','r'},{'r','r','r','r','r','r'}};char snum[12][6]={//数字表{5,1,1,4,2,1},{3,6,5,3,2,0},{2,2,7,2,2,2},{4,4,4,4,4,4},{5,1,1,4,2,1},{6,6,6,6,6,6},{5,1,1,4,2,1},{5,1,1,4,2,1},{3,6,5,3,11,4},{1,1,7,1,1,1},{3,3,3,3,3,3},{5,5,5,5,5,5}};int go2[12][3]={//goto表{1,2,3},{0,0,0},{0,0,0},{0,0,0},{8,2,3},{0,0,0},{0,9,3},{0,0,10},{0,0,0},{0,0,0},{0,0,0},{0,0,0}};void action(int i,char *&a,char &how,int &num,char &A,int &b)//action函数[i,a] {int j;switch(*a){case 'i':j=0;break;case '+':j=1;break;case '*':j=2;break;case '(':j=3;break;case ')':j=4;break;case '#':j=5;break;default:j=-1;break;}if(j!=-1){how=sym[i][j];num=snum[i][j];if(how=='r'){switch(num){case 1:A='E',b=3;cout<<"按E->E+T规约"<<endl;break;case 2:A='E',b=1;cout<<"按E->T规约"<<endl;break;case 3:A='T',b=3;cout<<"按T->T*F规约"<<endl;break;case 4:A='T',b=1;cout<<"按T->F规约"<<endl;break;case 5:A='F',b=3;cout<<"按F->(E)规约"<<endl;break;case 6:A='F',b=1;cout<<"按F->id规约"<<endl;break;default:break;}}}}int go(int t,char A)//goto[t,A]{switch(A){case 'E':return go2[t][0];break;case 'T':return go2[t][1];break;case 'F':return go2[t][2];break;}}void error(int i,int j,char *&a)//error处理函数{cout<<"error"<<endl;switch(j){case 1://期望输入id或左括号,但是碰到+,*,或$,就假设已经输入id了,转到状态5 state.push(5);symbol.push('i');//必须有这个,如果假设输入id的话,符号栈里必须有....cout<<"缺少运算对象id"<<endl;break;case 2://从输入中删除右括号a++;cout<<"不配对的右括号"<<endl;break;case 3://期望碰到+,但是输入id或左括号,假设已经输入算符+,转到状态6 state.push(6);symbol.push('+');cout<<"缺少运算符"<<endl;break;case 4://缺少右括号,假设已经输入右括号,转到状态11 state.push(11);symbol.push(')');cout<<"缺少右括号"<<endl;break;case 5:a++;cout<<"*号无效,应该输入+号!"<<endl;case 6:a++;}}int main(){int s;char *a;char how;int num;int b;char A;while(1){cin>>sen;a=sen;state.push(0);//先输入0状态while(*a!='\0'){b=0;num=0;how='\0';A='\0';s=state.top();action(s,a,how,num,A,b);if(how=='s')//移进{cout<<"移进"<<endl;symbol.push(*a);state.push(num);// if(*a=='i')// a++;//在这里忽略i后面的da++;}else if(how=='r')//规约{for(int i=0;i<b;i++){if(!state.empty())state.pop();if(!symbol.empty())symbol.pop();}int t=state.top();symbol.push(A);state.push(go(t,A));}else if(how=='a')//接受break;else{error(s,num,a);//错误处理}}cout<<"成功接受"<<endl;}return 0;}文法二说明1. 使用如下文法:E → E+T | TT → T*F | FF → (E) | id2. 对于任意给定的输入串(词法记号流)进行语法分析,采用LR 分析器来完成。
SLR分析法
void describe()
{
printf("文法是:\n");
printf("E→TM\n");
printf("M→+TM|ε\n");
printf("T→FN\n");
printf("N→*FN|ε\n");
printf("F→i|(E)\n");
}
int lin(char a)
{
int i;
describe();
}
if(z==2)
{
char stack[100]={'#','E'};
int flog=1;
j=0;
top=1;
print();
m=str[0];
printf("步骤\t分析栈\t剩余输入串\t推导的文法");
while(1)
{
printf("\n%d\t",++j);
for(i=0;i<=top;i++) //输出当前栈的内容
for(i=0;i<(int)strlen(nofinal);i++)
{
if(nofinal[i]==a)
{
return i;
}
}
}
int col(char a)
{
int i;
for(i=0;i<(int)strlen(final);i++)
{
if(final[i]==a)
{
return i;
}
}
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
《编译原理》课程设计报告—SLR(1)分析的实现学院计算机科学与技术专业计算机科学与技术学号学生姓名指导教师姓名2015年12月26日目录1.设计的目的与内容 (1)1.1课程设计的目的 (1)1.2设计内容 (1)1.3设计要求 (1)1.4理论基础 (1)2算法的基本思想 (2)2.1主要功能函数 (2)2.2算法思想 (3)SLR文法构造分析表的主要思想: (3)解决冲突的方法: (3)SLR语法分析表的构造方法: (4)3主要功能模块流程图 (5)3.1主函数功能流程图 (5)4系统测试 (6)5 结论 (11)附录程序源码清单 (12)1.设计的目的与内容1.1课程设计的目的编译原理课程设计是计算机专业重要的教学环节,它为学生提供了一个既动手又动脑,将课本上的理论知识和实际有机的结合起来,独立分析和解决实际问题的机会。
●进一步巩固和复习编译原理的基础知识。
●培养学生结构化程序、模块化程序设计的方法和能力。
●提高学生对于编程语言原理的理解能力。
●加深学生对于编程语言实现手段的印象。
1.2设计内容构造LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。
1.3设计要求1)SLR(1)分析表的生成可以选择编程序生成,也可选择手动生成;2)程序要求要配合适当的错误处理机制;3)要打印句子的文法分析过程。
1.4理论基础由于大多数适用的程序设计语言的文法不能满足LR(0)文法的条件,即使是描述一个实数变量说明这样简单的文法也不一定是LR(0)文法。
因此对于LR(0)规范族中有冲突的项目集(状态)用向前查看一个符号的办法进行处理,以解决冲突。
这种办法将能满足一些文法的需要,因为只对有冲突的状态才向前查看一个符号,以确定做那种动作,因而称这种分析方法为简单的LR(1)分析法,用SLR(1)表示。
2算法的基本思想2.1主要功能函数class WF{WF(char s1[],char s2[],int x,int y)WF(const string& s1,const string& s2,int x,int y)bool operator<(const WF& a)constbool operator==(const WF& a)constvoid print()};class Closure{void print(string str)bool operator==(const Closure& a)const};void make_item()void dfs(const string& x)void make_first()void append(const string& str1,const string& str2)bool _check(const vector<int>& id,const string str)void make_follow()void make_set()void make_V()void make_cmp(vector<WF>& cmp1,int i,char ch)void make_go()void make_table()void print(string s1,string s2,string s3,string s4,string s5,string s6, string s7)stringget_steps(int x)stringget_stk(vector<T>stk)stringget_shift(WF& temp)void analyse(string src)2.2算法思想SLR文法构造分析表的主要思想:许多冲突性的动作都可能通过考察有关非终结符的FOLLOW集而获解决。
解决冲突的方法:解决冲突的方法是分析所有含A和B的句型,考察集合FOLLOW(A)和FOLLOW(B),如果这两个集合不相交,而且也不包含b,那么当状态I面临输入符号a时,我们可以使用如下策略:若a=b,则移进。
若a∈FOLLOW(A),则用产生式A→α进行归约;若a∈FOLLOW(B),则用产生式B→α进行归约;此外,报错*SLR的基本算法:假定LR(0)规范族的一个项目集I中含有m个移进项目A1→α•a1β1,A2→α•a2β2,…,Am→α•amβm;同时含有n个归约项目B1→α•,B2→α•,…,B3→α•,如果集合{ a1,…, am},FOLLOW(B1),…,FOLLOW(Bn)两两不相交(包括不得有两个FOLLOW 集合有#),则隐含在I中的动作冲突可以通过检查现行输入符号a属于上述n+1个集合中的哪个集合而活的解决:若a是某个ai,i=1,2,…,m,则移进。
若a∈FOLLOW(Bi),i=1,2,…,m,则用产生式Bi→α进行归约;此外,报错这种冲突的解决方法叫做SLR(1)解决办法。
SLR语法分析表的构造方法:首先把G拓广为G’,对G’构造LR(0)项目集规范族C和活前缀识别自动机的状态转换函数GO。
函数ACTION和GOTO可按如下方法构造:若项目A→α•bβ属于Ik,GO(Ik,a)= Ij,a为终结符,置ACTION[k,a]为“把状态j和符号a移进栈”,简记为“sj”;若项目A→α•属于Ik,那么,对任何非终结符a,a∈FOLLOW(A),置ACTION[k,a]为“用产生式A→α进行归约”,简记为“rj”;其中,假定A→α为文法G’的第j个产生式若项目S’→S•属于Ik,则置ACTION[k,#]为可“接受”,简记为“acc”;若GO(Ik, A)= Ij,A为非终结符,则置GOTO[k, A]=j;分析表中凡不能用规则1至4填入信息的空白格均填上“出错标志”。
语法分析器的初始状态是包含S’→•S的项目集合的状态SLR解决的冲突只是移进-规约冲突和规约-规约冲突3主要功能模块流程图3.1主函数功能流程图图3.1程序主要流程4系统测试图4.1输入图4.2项目表图4.3FIRST集图4.4 FOLLOW集图4.5CLOSURE表图4.6 EDGE表图4.7 LR(0)表图4.8文法分析步骤5结论LR分析法是一种自下而上进行规范归约的语法分析方法。
这里L是指从左到右扫描输入符号串。
R是指构造最右推倒的逆工程。
这种分析法比递归下降分析法、预测分析法和算符优先分析法对文法的限制要少得多。
附录程序源码清单#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <cctype>#include <vector>#include <string>#include <queue>#include <map>#include <set>#include <sstream>#define MAX 507//#define DEBUGusingnamespace std;#pragma warning(disable:4996)class WF{public:string left, right;int back;int id;WF(char s1[],char s2[],int x,int y){left= s1;right= s2;back= x;id= y;}WF(const string& s1,const string& s2,int x,int y)left= s1;right= s2;back= x;id= y;}bool operator<(const WF& a)const{if(left ==a.left)return right <a.right;return left <a.left;}bool operator==(const WF& a)const{return(left ==a.left)&&(right ==a.right);}void print(){printf("%s->%s\n",left.c_str(),right.c_str()); }};class Closure{public:vector<WF> element;void print(string str){printf("%-15s%-15s\n","",str.c_str());for(int i=0;i<element.size();i++)element[i].print();bool operator==(const Closure& a)const{if(a.element.size()!=element.size())returnfalse; for(int i=0;i<a.element.size();i++)if(element[i]==a.element[i])continue; elsereturnfalse;returntrue;}};struct Content{int type;int num;string out;Content(){ type =-1;}Content(int a,int b):type(a),num(b){}};vector<WF>wf;map<string, vector<int>>dic;map<string, vector<int>>VN_set;map<string,bool> vis;string start ="S";vector<Closure> collection;vector<WF> items;char CH ='$';int go[MAX][MAX];int to[MAX];vector<char> V;bool used[MAX];Content action[MAX][MAX];int Goto[MAX][MAX];map<string, set<char>> first;map<string, set<char>> follow;void make_item(){memset(to,-1,sizeof(-1));for(int i=0;i<wf.size();i++)VN_set[wf[i].left].push_back(i);for(int i=0;i<wf.size();i++)for(int j =0; j <=wf[i].right.length();j++){string temp =wf[i].right;temp.insert(temp.begin()+ j, CH);dic[wf[i].left].push_back(items.size());if(j)to[items.size()-1]=items.size();items.push_back(WF(wf[i].left, temp,i,items.size()));}#ifdef DEBUGputs("-------------------------项目表-------------------------"); for(int i=0;i<items.size();i++)printf("%s->%s back:%d id:%d\n", items[i].left.c_str(),items[i].right.c_str(), items[i].back, items[i].id);puts("--------------------------------------------------------");#endif}void dfs(const string& x){if(vis[x])return;vis[x]=1;vector<int>& id =VN_set[x];for(int i=0;i<id.size();i++){string& left =wf[id[i]].left;string& right =wf[id[i]].right;for(int j =0; j <right.length();j++)if(isupper(right[j])){dfs(right.substr(j,1));set<char>& temp = first[right.substr(j,1)]; set<char>::iterator it =temp.begin();bool flag =true;for(; it !=temp.end(); it++){if(*it =='~') flag =false;first[left].insert(*it);}if(flag)break;}else{first[left].insert(right[j]);break;}}}void make_first(){vis.clear();map<string, vector<int>>::iterator it2 =dic.begin();for(; it2 !=dic.end(); it2++)if(vis[it2->first])continue;else dfs(it2->first);#ifdef DEBUGputs("****************FIRST集***************************"); map<string, set<char>>::iterator it =first.begin();for(; it !=first.end(); it++){printf("FIRST(%s)={", it->first.c_str());set<char>& temp = it->second;set<char>::iterator it1 =temp.begin();bool flag =false;for(; it1 !=temp.end(); it1++){if(flag)printf(",");printf("%c",*it1);flag=true;}puts("}");}#endif}void append(const string& str1,const string& str2){set<char>& from = follow[str1];set<char>& to = follow[str2];set<char>::iterator it =from.begin();for(; it !=from.end(); it++)to.insert(*it);}bool _check(const vector<int>& id,const string str){for(int i=0;i<id.size();i++){int x = id[i];if(wf[x].right ==str)returntrue;}returnfalse;}void make_follow(){while(true){bool goon =false;map<string, vector<int>>::iterator it2 =VN_set.begin(); for(; it2 !=VN_set.end(); it2++){vector<int>& id = it2->second;for(int i=0;i<id.size();i++){bool flag =true;WF&tt=wf[id[i]];string& left =tt.left;const string& right =tt.right;for(int j =right.length()-1; j >=0; j--)if(isupper(right[j])){if(flag){int tx= follow[right.substr(j,1)].size(); append(left,right.substr(j,1));int tx1 = follow[right.substr(j,1)].size(); if(tx1 >tx) goon =true;if(_check(id,"~"))flag=false;}for(int k = j +1; k <right.length(); k++)if(isupper(right[k])){stringidd=right.substr(k,1);set<char>& from = first[idd];set<char>& to = follow[right.substr(j,1)]; set<char>::iterator it1 =from.begin();int tx= follow[right.substr(j,1)].size();for(; it1 !=from.end(); it1++)if(*it1 !='~')to.insert(*it1);int tx1 = follow[right.substr(j,1)].size(); if(tx1 >tx) goon =true;if(_check(id,"~"))break;}else{int tx= follow[right.substr(j,1)].size(); follow[right.substr(j,1)].insert(right[k]); int tx1 = follow[right.substr(j,1)].size(); if(tx1 >tx) goon =true;break;}}else flag =false;}}if(!goon)break;}#ifdef DEBUGputs("***************FOLLOW集*******************"); map<string, set<char>>::iterator it =follow.begin(); for(; it !=follow.end(); it++){printf("FOLLOW(%s)={", it->first.c_str());set<char>& temp = it->second;temp.insert('#');set<char>::iterator it1 =temp.begin();bool flag =false;for(; it1 !=temp.end(); it1++){if(flag)printf(",");printf("%c",*it1);flag=true;}puts("}");}#endif}void make_set(){bool has[MAX];for(int i=0;i<items.size();i++)if(items[i].left[0]=='S'&& items[i].right[0]== CH) {Closure temp;string&str= items[i].right;vector<WF>& element =temp.element;element.push_back(items[i]);size_t x =0;for(x =0; x <str.length(); x++)if(str[x]== CH)break;memset(has,0,sizeof(has));has[i]=1;if(x !=str.length()-1){queue<string> q;q.push(str.substr(x +1,1));while(!q.empty()){string u =q.front();q.pop();vector<int>& id =dic[u];for(size_t j =0; j <id.size();j++){int tx= id[j];if(items[tx].right[0]== CH){if(has[tx])continue;has[tx]=1;if(isupper(items[tx].right[1]))q.push(items[tx].right.substr(1,1));}}}}collection.push_back(temp);}for(size_t i=0;i<collection.size();i++){map<int, Closure> temp;for(size_t j =0; j < collection[i].element.size();j++){stringstr= collection[i].element[j].right;size_t x =0;for(; x <str.length(); x++)if(str[x]== CH)break;if(x ==str.length()-1)continue;int y =str[x +1];int ii;str.erase(str.begin()+ x);str.insert(str.begin()+ x +1, CH);WF cmp=WF(collection[i].element[j].left,str,-1,-1); for(size_t k =0; k <items.size(); k++)if(items[k]==cmp){ii= k;break;}memset(has,0,sizeof(has));vector<WF>& element = temp[y].element;has[ii]=1;x++;if(x !=str.length()-1){queue<string> q;q.push(str.substr(x +1,1));while(!q.empty()){string u =q.front();q.pop();vector<int>& id =dic[u];for(size_t j =0; j <id.size();j++){int tx= id[j];if(items[tx].right[0]== CH){if(has[tx])continue;has[tx]=1;if(isupper(items[tx].right[1]))q.push(items[tx].right.substr(1,1));element.push_back(items[tx]);}}}}}map<int, Closure>::iterator it =temp.begin(); for(; it !=temp.end(); it++)collection.push_back(it->second);for(size_t i=0;i<collection.size();i++)sort(collection[i].element.begin(), collection[i].element.end()); for(size_t i=0;i<collection.size();i++)for(size_t j =i+1; j <collection.size();j++)if(collection[i]== collection[j])collection.erase(collection.begin()+ j);}#ifdef DEBUGputs("-------------CLOSURE---------------------");stringstream sin;for(size_t i=0;i<collection.size();i++){sin.clear();string out;sin<<"closure-I"<<i;sin>> out;collection[i].print(out);}puts("");#endif}void make_V(){memset(used,0,sizeof(used));for(size_t i=0;i<wf.size();i++){string&str=wf[i].left;for(size_t j =0; j <str.length();j++){if(used[str[j]])continue;used[str[j]]=1;V.push_back(str[j]);}string& str1 =wf[i].right;for(size_t j =0; j < str1.length();j++){if(used[str1[j]])continue;used[str1[j]]=1;V.push_back(str1[j]);}}sort(V.begin(),V.end());V.push_back('#');}void make_cmp(vector<WF>& cmp1,int i,char ch){for(size_t j =0; j < collection[i].element.size();j++){stringstr= collection[i].element[j].right;size_t k;for(k =0; k <str.length(); k++)if(str[k]== CH)break;if(k !=str.length()-1&&str[k +1]==ch){str.erase(str.begin()+ k);str.insert(str.begin()+ k +1, CH);cmp1.push_back(WF(collection[i].element[j].left,str,-1,-1)); }}sort(cmp1.begin(), cmp1.end());}void make_go(){memset(go,-1,sizeof(go));int m =collection.size();for(size_t t =0; t <V.size(); t++){char ch= V[t];for(int i=0;i< m;i++){vector<WF> cmp1;make_cmp(cmp1,i,ch);#ifdef DEBUGcout<< cmp1.size()<<endl;#endifif(cmp1.size()==0)continue;for(int j =0; j < m;j++){vector<WF> cmp2;for(size_t k =0; k < collection[j].element.size(); k++){string&str= collection[j].element[k].right;size_t x;for(x =0; x <str.length(); x++)if(str[x]== CH)break;if(x &&str[x -1]==ch)cmp2.push_back(WF(collection[j].element[k].left,str,-1,-1));}sort(cmp2.begin(), cmp2.end());#ifdef DEBUGcout<< cmp2.size()<<endl;#endifbool flag =true;if(cmp2.size()!= cmp1.size())continue;#ifdef DEBUGcout<< cmp1.size()<<endl;#endiffor(size_t k =0; k < cmp1.size(); k++)if(cmp1[k]== cmp2[k])continue;else flag =false;#ifdef DEBUGcout<<"out "<<endl;#endifif(flag)go[i][ch]= j;}}}#ifdef DEBUGputs("---------------EDGE----------------------"); stringstream sin;string out;for(int i=0;i< m;i++)for(int j =0; j < m;j++)for(int k =0; k < MAX; k++)if(go[i][k]== j){sin.clear();sin<<"I"<<i<<"--"<<(char)(k)<<"--I"<< j;sin>> out;printf("%s\n",out.c_str());}#endif}void make_table(){memset(Goto,-1,sizeof(Goto));for(size_t i=0;i<collection.size();i++)for(size_t j =0; j <V.size();j++){char ch= V[j];int x = go[i][ch];if(x ==-1)continue;if(!isupper(ch))action[i][ch]= Content(0, x);elseGoto[i][ch]= x;}//write r and acc to the tablefor(int i=0;i<collection.size();i++)for(int j =0; j < collection[i].element.size();j++) {WF&tt= collection[i].element[j];if(tt.right[tt.right.length()-1]== CH){if(tt.left[0]=='S')action[i]['#']= Content(2,-1);elsefor(int k =0; k <V.size(); k++){int y = V[k];if(!follow[tt.left].count(V[k]))continue;action[i][y]= Content(1,tt.back);}}}#ifdef DEBUGputs("------------------------------------------LR(0)分析表--------------------------------------------------------"); printf("%10s%5c%5s","|", V[0],"|");for(int i=1;i<V.size();i++)printf("%5c%5s", V[i],"|");puts("");for(int i=0;i<(V.size()+1)*10;i++)printf("-");puts("");stringstream sin;for(int i=0;i<collection.size();i++){printf("%5d%5s",i,"|");for(int j =0; j <V.size();j++){char ch= V[j];if(isupper(ch)){if(Goto[i][ch]==-1)printf("%10s","|");elseprintf("%5d%5s",Goto[i][ch],"|");}else{sin.clear();if(action[i][ch].type ==-1)printf("%10s","|");else{Content& temp = action[i][ch]; if(temp.type==0)sin<<"S";if(temp.type==1)sin<<"R";if(temp.type==2)sin<<"acc";if(temp.num!=-1)sin<<temp.num;sin>>temp.out;printf("%7s%3s",temp.out.c_str(),"|");}}}puts("");}for(int i=0;i<(V.size()+1)*10;i++)printf("-");puts("");#endif}void print(string s1,string s2,string s3,string s4,string s5,string s6, string s7){printf("%-15s|%-15s%-15s%-20s|%-15s%-15s%-15s\n", s1.c_str(),s2.c_str(), s3.c_str(), s4.c_str(), s5.c_str(),s6.c_str(), s7.c_str());}stringget_steps(int x){stringstream sin;sin<< x;string ret;sin>> ret;return ret;}template<class T>stringget_stk(vector<T>stk){stringstream sin;for(int i=0;i<stk.size();i++)sin<<stk[i];string ret;sin>> ret;return ret;}stringget_shift(WF& temp){stringstream sin;sin <<"reduce("<<temp.left<<"->"<<temp.right<<")";string out;sin>> out;return out;}void analyse(string src){print("steps","op-stack","input","operation","state-stack","ACTION"," GOTO");vector<char>op_stack;vector<int>st_stack;src+="#";op_stack.push_back('#');st_stack.push_back(0);int steps =1;for(int i=0;i<src.length();i++){char u =src[i];int top =st_stack[st_stack.size()-1];Content& act =action[top][u];if(act.type==0){print(get_steps(steps++),get_stk(op_stack),src.substr(i),"shift",get_ stk(st_stack),act.out,"");op_stack.push_back(u);st_stack.push_back(act.num);}elseif(act.type==1){WF&tt=wf[act.num];int y =st_stack[st_stack.size()-tt.right.length()-1];int x =Goto[y][tt.left[0]];print(get_steps(steps++),get_stk(op_stack),src.substr(i),get_shift(tt ),get_stk(st_stack),act.out,get_steps(x));for(int j =0; j <tt.right.length();j++){st_stack.pop_back();op_stack.pop_back();}op_stack.push_back(tt.left[0]);st_stack.push_back(x);i--;}elseif(act.type==2){print(get_steps(steps++),get_stk(op_stack),src.substr(i),"Accept",get _stk(st_stack),act.out,"");}elsecontinue;}}int main(){int n;char s[MAX];while(~scanf("%d",&n)){for(int i=0;i< n;i++){scanf("%s", s);int len=strlen(s), j;for(j =0; j <len;j++)if(s[j]=='-')break;s[j]=0;wf.push_back(WF(s, s + j +2,-1,-1)); #ifdef DEBUGwf[wf.size()-1].print();#endif}make_item();make_first();make_follow();make_set();make_V();make_go();make_table();analyse("(i*i)+i");}}盛年不重来,一日难再晨。