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]分析器设计实验报告](https://img.taocdn.com/s3/m/7dfc78b1ba0d4a7302763a5c.png)
编译原理实验报告题目: 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)分析过程如下:
- 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)string get_steps(int x)string get_stk(vector<T> stk)string get_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.3 FIRST集图4.4 FOLLOW集图4.5 CLOSURE表图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 DEBUGusing namespace 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())return false;for(int i =0; i < a.element.size(); i++)if(element[i]== a.element[i])continue;else return false;return true;}};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)return true;}return false;}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])){string idd = 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));element.push_back(items[tx]);}}}}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++){string str = 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;element.push_back(items[ii]);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++){string str = 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("");#endifvoid 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());}string get_steps(int x){stringstream sin;sin << x;string ret;sin >> ret;return ret;}template<class T>string get_stk(vector<T> stk){stringstream sin;for(int i =0; i < stk.size(); i++)sin << stk[i];string ret;sin >> ret;return ret;}string get_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);}else if(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--;}else if(act.type ==2){print(get_steps(steps++), get_stk(op_stack), src.substr(i), "Accept", get_stk(st_stack), act.out,"");}else continue;}}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");}}。