实验原理LL1分析法
LL(1)语法分析程序实验报告

LL1实验报告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 ‘#’,则把X从STACK栈顶弹出,让a指向下一个输入符号。
(3)若X是一个非终结符,则查看预测分析表M。
若M[A,a]中存放着关于X的一个产生式,那么,首先把X弹出STACK栈顶,然后,把产生式的右部符号串按反序一一弹出STACK栈(若右部符号为ε,则不推什么东西进STACK栈)。
若M[A,a]中存放着“出错标志”,则调用出错诊断程序ERROR。
事实上,LL(1)的分析是根据文法构造的,它反映了相应文法所定义的语言的固定特征,因此在LL(1)分析器中,实际上是以LL(1)分析表代替相应方法来进行分析的。
2.分析LL ( 1) 分析表是一个二维表,它的表列符号是当前符号,包括文法所有的终结和自定义。
的句子结束符号#,它的表行符号是可能在文法符号栈SYN中出现的所有符号,包括所有的非终结符,所有出现在产生式右侧且不在首位置的终结符,自定义的句子结束符号#表项。
实验原理ll1分析法

实验原理ll1分析法
LL(1)分析法是一种语法分析方法,是从上到下递归分析的一种方式。
LL指的是“Left to right, leftmost derivation”,表示从左到右、最左派生。
1表示在当前读入符号下,只需要向前看一个符号即可确定使用哪个产生式进行推导。
其核心思想是通过预测分析表来进行语法分析,预测分析表是一个二维数组,横坐标是非终结符号,纵坐标是终结符号。
在分析过程中,根据当前读入的终结符号和栈顶的非终结符号,查找分析表中对应的表项,判断使用哪个产生式进行推导。
如果表项为空,则表示当前输入串不符合语法规则。
LL(1)分析法的优点是实现简单、可自动化,同时可以处理大部分常见的上下文无关文法,且分析的速度较快,适合在语法分析器中应用。
缺点是只能处理LL(1)文法,对于LL(k)文法或其他类型的文法稍显局限。
编译原理词法分析器-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)中。
编译原理实验二LL(1)语法分析实验报告

专题3_LL(1)语法分析设计原理与实现李若森 13281132 计科1301一、理论传授语法分析的设计方法和实现原理;LL(1) 分析表的构造;LL(1)分析过程;LL(1)分析器的构造。
二、目标任务实验项目实现LL(1)分析中控制程序(表驱动程序);完成以下描述算术表达式的 LL(1)文法的LL(1)分析程序。
G[E]:E→TE’E’→ATE’|εT→FT’T’→MFT’|εF→(E)|iA→+|-M→*|/设计说明终结符号i为用户定义的简单变量,即标识符的定义。
加减乘除即运算符。
设计要求(1)输入串应是词法分析的输出二元式序列,即某算术表达式“专题 1”的输出结果,输出为输入串是否为该文法定义的算术表达式的判断结果;(2)LL(1)分析程序应能发现输入串出错;(3)设计两个测试用例(尽可能完备,正确和出错),并给出测试结果。
任务分析重点解决LL(1)表的构造和LL(1)分析器的实现。
三、实现过程实现LL(1)分析器a)将#号放在输入串S的尾部b)S中字符顺序入栈c)反复执行c),任何时候按栈顶Xm和输入ai依据分析表,执行下述三个动作之一。
构造LL(1)分析表构造LL(1)分析表需要得到文法G[E]的FIRST集和FOLLOW集。
构造FIRST(α)构造FOLLOW(A)构造LL(1)分析表算法根据上述算法可得G[E]的LL(1)分析表,如表3-1所示:表3-1 LL(1)分析表主要数据结构pair<int, string>:用pair<int, string>来存储单个二元组。
该对照表由专题1定义。
map<string, int>:存储离散化后的终结符和非终结符。
vector<string>[][]:存储LL(1)分析表函数定义init:void init();功能:初始化LL(1)分析表,关键字及识别码对照表,离散化(非)终结符传入参数:(无)传出参数:(无)返回值:(无)Parse:bool Parse( const vector<PIS> &vec, int &ncol );功能:进行该行的语法分析传入参数:vec:该行二元式序列传出参数:emsg:出错信息epos:出错标识符首字符所在位置返回值:是否成功解析。
预测分析程序实验报告

预测分析程序实验报告题⽬:预测分析法⼀、实验⽬的1、通过实验要学会⽤消除左递归和消除回溯的⽅法来使⽂法满⾜进⾏确定⾃顶向下分析的条件;2、学会⽤C/C++⾼级程序设计语⾔编写⼀个LL(1)分析法程序⼆、实验内容及要求LL(1)预测分析程序的总控程序在任何时候都是按STACK栈顶符号X和当前的输⼊符号a做哪种过程的。
对于任何(X,a),总控程序每次都执⾏下述三种可能的动作之⼀:(1)若X = a =‘#’,则宣布分析成功,停⽌分析过程。
(2)若X = a ‘#’,则把X从STACK栈顶弹出,让a指向下⼀个输⼊符号。
(3)若X是⼀个⾮终结符,则查看预测分析表M。
若M[A,a]中存放着关于X的⼀个产⽣式,那么,⾸先把X弹出STACK栈顶,然后,把产⽣式的右部符号串按反序⼀⼀弹出STACK栈(若右部符号为ε,则不推什么东西进STACK栈)。
若M[A,a]中存放着“出错标志”,则调⽤出错诊断程序ERROR。
1、给定⽂法S -> a | b | (T)T -> SH | dH -> ,SH | ε2、该⽂法对应的预测分析表3、编写预测分析程序对句⼦进⾏分析三、试验程序设计说明1、相关函数说明分析栈可以采取许多的存储⽅法来设计,在这⾥采⽤的顺序栈。
根据预测分析原理,LL(1)分析程序的实现关键在于分析栈和分析表是采⽤何种数据结构来实现。
分析表是⼀个矩阵,当我们要调⽤分析表来分析时,就根据栈顶的⾮终结符和当前输⼊的终结符来决定执⾏哪种过程。
具体设计思想如下:printStack()输出分析栈内内容;printinputString()输出⽤户输⼊的字符串;Pop()弹出栈顶元素;Push()向栈内添加⼀个元素;Search()查找⾮终结符集合VT 中是否存在输⼊的⾮终结符;yuCeFenXi()进⾏输⼊串的预测分析的主功能函数;M(char A, char a)查看预测分析表M[A,a]中是否存在相应产⽣式。
编译原理实验LL1分析

实验三语法分析---LL(1)分析器
一
(
1.用程序的方法实现语法分析的LL(1)方法。
}
void put_setence()
{
char ch;
int i=0;
while((ch=cin.get()) != '#') {
analyz_sentence[i] = ch;
i++;
}
analyz_sentence[i] = '#';
}
void init_stack()
{
stack[0] = '#';
return i;
}
return -1;
}
void reve()
{
strcpy(s, tp);
int i,j;
char t;
i=0;
while (s[i] != '\0')
++i;
--i;
if (s[i] == '\n')
--i;
j=0;
while (j<i)
{
t = s[j];
s[j] = s[i];
cout << "=>";
if (top == 'u')
pop();
}
void pop()
{
计算机编译原理实验报告

编译原理实验报告实验一词法分析设计一、实验功能:1、对输入的txt文件内的内容进行词法分析:2、由文件流输入test.txt中的内容,对文件中的各类字符进行词法分析3、打印出分析后的结果;二、程序结构描述:(源代码见附录)1、分别利用k[],s1[],s2[],s3[]构造关键字表,分界符表,算术运算符表和关系运算符表。
2、bool isletter(){} 用来判断其是否为字母,是则返回true,否则返回false;bool isdigit(){} 用来判断其是否为数字,是则返回true,否则返回false;bool iscalcu(){} 用来判断是否为算术运算符,是则返回true,否则返回false;bool reserve(string a[]){} 用来判断某字符是否在上述四个表中,是则返回true,否则返回false;void concat(){} 用来连接字符串;void getn(){} 用来读取字符;void getb(){} 用来对空格进行处理;void retract(){}某些必要的退格处理;int analysis(){} 对一个单词的单词种别进行具体判断;在主函数中用switch决定输出。
三、实验结果四、实验总结词法分析器一眼看上去很复杂,但深入的去做就会发现并没有一开始想象的那么困难。
对于一个字符的种别和类型可以用bool函数来判断,对于关键字和标示符的识别(尤其是3b)则费了一番功夫,最后对于常数的小数点问题处理更是麻烦。
另外,这个实验要设定好时候退格,否则将会导致字符漏读甚至造成字符重复读取。
我认为,这个实验在程序实现上大体不算困难,但在细节的处理上则需要好好地下功夫去想,否则最后的程序很可能会出现看上去没有问题,但实际上漏洞百出的状况。
将学过的知识应用到实际中并不简单,只有自己不断尝试将知识转化成程序才能避免眼高手低,对于知识的理解也必将更加深刻。
实验二LL(1)分析法一、实验原理:1、写出LL(1)分析法的思想:当一个文法满足LL(1)条件时,我们就可以为它构造一个不带回溯的自上而下的分析程序,这个分析程序是有一组递归过程组成的,每个过程对应文法的一个非终结符。
编译原理中LL(1)文法的源代码汇总

一. 实验目的1.掌握LL(1分析法的基本原理2.掌握LL(1分析表的构造方法3.掌握LL(1驱动程序的构造方法二. 实验内容及要求根据某一文法编制调试LL(1)分析程序,以便对任意输入的符号串进行分析。
本次实验的目的主要是加深对预测分析LL(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输出的格式如下:(1LL(1)分析程序,编制人:姓名,学号,班级(2输入一以#结束的符号串(包括+—*/()i#:在此位置输入符号串(3输出过程如下:步骤分析栈剩余输入串所用产生式1 E i+i*i# E->TG(4输入符号串为非法符号串(或者为合法符号串备注:(1在“所用产生式”一列中如果对应有推导则写出所用产生式;如果为匹配终结符则写明匹配的终结符;如分析异常出错则写为“分析出错”;若成功结束则写为“分析成功”。
(2 在此位置输入符号串为用户自行输入的符号串。
(3上述描述的输出过程只是其中一部分的。
注意:1.表达式中允许使用运算符(+-*/)、分割符(括号)、字符i,结束符#;2.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好);3.对学有余力的同学,测试用的表达式事先放在文本文件中,一行存放一个表达式,同时以分号分割。
同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照;4.可采用的其它的文法。
三. 实验过程LL(1分析法的实验源程序代码如下:#include#include#include#includechar 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[5];/*产生式右边字符 */int length;/*字符个数 */}type;type e,t,g,g1,s,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 输出对齐符 */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;g1.origin='G';g1.array[0]='^';g1.length=1;s.origin='S';strcpy(s.array,"*FS";s.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<=5;n++C[m][n].origin='N';/*全部赋为空*//*填充分析表*/C[0][0]=e;C[0][3]=e;C[1][1]=g;C[1][4]=g1;C[1][5]=g1;C[2][0]=t;C[2][3]=t;C[3][1]=s1;C[3][2]=s;C[3][4]=C[3][5]=s1;C[4][0]=f1;C[4][3]=f;printf("提示:本程序只能对由'i','+','*','(',''构成的以'#'结束的字符串进行分析,\n"; printf("请输入要分析的字符串:";do/*读入分析串*/{scanf("%c",&ch;if ((ch!='i' &&(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"; do{x=A[top--];/*x为当前栈顶字符*/printf("%d",k++;printf("\t\t";for(j=0;j<=5;j++/*判断是否为终结符*/if(x==v1[j]{flag=1;break;}if(flag==1/*如果是终结符*/{if(x=='#'{finish=1;/*结束标记*/printf("acc!\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<=5;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;jprintf("%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*/程序的运行结果如下:四. 实验心得经过这个实验的练习,通过对程序的分析,让我进一步了解LL(1)算法的思想以及它的进一步程序实现,让我对它的了解从简单的理论上升到程序实现的级别,有理论上升到实际,让我更清楚它的用途。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
flag=0; }
x=n[j].getselect().find('#');
if(k==ENODE.length()-1&&x<n[j].getselect().length()&&x>-1)
实验报告
实验名称
LL1分析法
专业
计算机科学与技术
课程名称
编译原理
指导老师
赵智超
班级
计算机一班
姓名
学号
12103140102
评分
实验地点
1C26217
实验日期
2014-04-30
一、实验目的
1.掌握LL(1)分析法的基本原理;2.掌握LL(1)分析表的构造方法;3.掌握LL(1)驱动程序的构造方法。
二、实验原理
for(i=0;i<ENODE.length();i++)
{ if(ENODE[i]!='@') { outfu(10," "); cout<<ENODE[i]; } }
outfu(10," "); cout<<"#"<<endl; int x;
for(i=0;i<NODE.length();i++) { outfu(4," "); cout<<NODE[i]; outfu(5," ");
{ char ch,a; int x,i,j,k; b++; cout<<endl<<" "<<b;
if(b>9) outfu(8," "); else outfu(9," ");
cout<<fenxi; outfu(26-chuan.length()-fenxi.length()," "); cout<<chuan;
{ s=NODE.find(ni.getrg()[i]); if(s<NODE.length()&&s>-1)
if(i<ni.getrlen()-1) for(j=0;j<SUM;j++)
if(n[j].getlf().find(ni.getrg()[i])==0)
{ if(NODE.find(ni.getrg()[i+1])<NODE.length())
n[j].newfollow(ni.getfollow()); } }
else { str.erase(); str+=ni.getrg()[i+1]; n[j].newfollow(str);} }} }
void select(edge &ni,edge *n){ int i,j;
if(ENODE.find(ni.getro())<ENODE.length())
{ ni.newselect(ni.getro()); if(ni.getro()=="@") ni.newselect(ni.getfollow());}
else for(i=0;i<ni.getrlen();i++)
{ for(j=0;j<SUM;j++) if(ni.getrg()[i]==n[j].getlf()[0])
if(pipei(chuan,fenxi,yc,b)) return 1;
elsereturn 0; }
else return 0;} } }
void main()
{ edge *n; string str,(*yc)[50]; int i,j,k; bool flag=0;
cout<<"请输入上下文无关文法的总规则数:"<<endl; cin>>SUM;
if(n[j].getfirst().find("@")>n[j].getfirst().length())
{ n[i].delfirst();break; } } } } }
cout<<"请输入具体规则(格式:左部右部,@为空):"<<endl;
n=new edge[SUM]; for(i=0;i<SUM;i++)
for(j=0;j<n[i].getrlen();j++){str=n[i].getrg();
if(NODE.find(str[j])>NODE.length()&&ENODE.find(str[j])>ENODE.length())
{for(k=1;k<n[i].getrlen();k++)
{if(NODE.find(n[i].getrg()[k])<NODE.length())
{for(j=0;j<SUM;j++)
{if(n[i].getrg()[k]==n[j].getlf()[0])
{ n[i].newfirst(n[j].getfirst()); break;} }
void edge::newselect(string w) { int i; for(i=0;i<w.length();i++)
if(select.find(w[i])>select.length()&&w[i]!='@') select+=w[i]; }
void edge::delfirst() {int i=first.find('@');first.erase(i,1); }
string edge::getro() {string str;str+=right[0];return str; }
int edge::getrlen() {return right.length();}
void edge::newfirst(string w) { int i; for(i=0;i<w.length();i++)
if(first.find(w[i])>first.length()) first+=w[i]; }
void edge::newfollow(string w) { int i; for(i=0;i<w.length();i++)
if(follow.find(w[i])>follow.length()&&w[i]!='@') follow+=w[i]; }
int SUM; string NODE,ENODE;
void first(edge ni,edge *n,int x) {int i,j;for(j=0;j<SUM;j++)
{ if(ni.getlf()==n[j].getlf())
{ if(NODE.find(n[j].getro())<NODE.length())
string edge::getrg() {return right; }
string edge::getfirst() {return first; }
string edge::getfollow() { return follow; }
string edge::getselect() { return select; }
ENODE+=str[j]; }
for(i=0;i<SUM;i++){ first(n[i],n,i); }
for(i=0;i<SUM;i++)
if(n[i].getfirst().find("@")<n[i].getfirst().length())
{if(NODE.find(n[i].getro())<NODE.length())
{ cout<<"->"<<n[j].getrg(); yc[i][j]=n[j].getrg(); } } }
if(flag&&ENODE[k]!='@') outfu(11," "); } cout<<endl; } }
int pipei(string &chuan,string &fenxi,string (*yc)[50],int &b)
{ for(k=0;k<SUM;k++) if(n[k].getlf().find(ni.getrg()[i+1])==0)
{ n[j].newfollow(n[k].getfirst());
if(n[k].getfirst().find("@")<n[k].getfirst().length())
else j=ENODE.find(a); if(yc[i][j].length()) { cout<<NODE[i]<<"->"<<yc[i][j];
fenxi.erase(fenxi.length()-1,1); for(k=yc[i][j].length()-1;k>-1;k--)