LL1 first follow集

合集下载

编译原理课程设计LL(1)文法

编译原理课程设计LL(1)文法

本次课程设计主要是介绍LL(1)文法的一般原理,根据给定的一文法编制调试LL(1)文法语法分析程序,以便对任意输入的符号串进行分析。

本次课程设计的目的主要是加深对预测分析LL(1)文法语法分析的理解,加深对自顶向下语法分析方法的认识。

具体如下:1、对语法规则有明确的定义;2、编写的分析程序能够对给定文法进行正确的语法分析;3、对输入给定的文法,手工计算First、Follow集合以及各产生式的Select 集合,再根据Select集合构造出预测分析表;4、对于输入串,应能根据预测分析表判断识别该输入串是否为给定文法的句子;5、对于遇到的错误,给出简单的错误信息提示,保证能够顺利完成语法分析过程。

前言------------------------------------------------------------- Ⅰ目录------------------------------------------------------------- Ⅱ一、系统分析------------------------------------------------------ 11.1 判断LL(1)文法---------------------------------------------- 11.2 构造预测分析表---------------------------------------------- 1二、系统设计------------------------------------------------------ 22.1 基本设计---------------------------------------------------- 22.2 程序流程图-------------------------------------------------- 2三、系统实现------------------------------------------------------ 33.1 程序主要函数------------------------------------------------ 33.2 程序主要代码------------------------------------------------ 3四、系统测试------------------------------------------------------ 7五、总结---------------------------------------------------------- 8 参考文献---------------------------------------------------------- 9一、系统分析有文法G[E]:E->TG T->FSG->+TG|ε S->*FS|ε F->(E)|i 1.1 判断LL(1)文法当我们需选用自顶向下分析技术时,首先必须判别所给文法是否是LL(1)文法,分析所给文法可知文法中不含左公因子,也不存在左递归,因而再对给定文法计算First 集、Follow 集以及Select 集,对于求出的每个产生式的Select 集,看对于同一个左部非终结符是否存在交集,如果它们的交为空则表示所给文法是LL(1)文法,否则不是L(1)文法。

【编译原理】语法分析LL(1)分析法的FIRST和FOLLOW集

【编译原理】语法分析LL(1)分析法的FIRST和FOLLOW集

【编译原理】语法分析LL(1)分析法的FIRST和FOLLOW集 近来复习编译原理,语法分析中的⾃上⽽下LL(1)分析法,需要构造求出⼀个⽂法的FIRST和FOLLOW集,然后构造分析表,利⽤分析表+⼀个栈来做⾃上⽽下的语法分析(递归下降/预测分析),可是这个FIRST集合FOLLOW集看得我头⼤。

教课书上的规则如下,⽤我理解的语⾔描述的:任意符号α的FIRST集求法:1. α为终结符,则把它⾃⾝加⼊FIRSRT(α)2. α为⾮终结符,则:(1)若存在产⽣式α->a...,则把a加⼊FIRST(α),其中a可以为ε(2)若存在⼀串⾮终结符Y1,Y2, ..., Yk-1,且它们的FIRST集都含空串,且有产⽣式α->Y1Y2...Yk...,那么把FIRST(Yk)-{ε}加⼊FIRST(α)。

如果k-1抵达产⽣式末尾,那么把ε加⼊FIRST(α) 注意(2)要连续进⾏,通俗地描述就是:沿途的Yi都能推出空串,则把这⼀路遇到的Yi的FIRST集都加进来,直到遇到第⼀个不能推出空串的Yk为⽌。

重复1,2步骤直⾄每个FIRST集都不再增⼤为⽌。

任意⾮终结符A的FOLLOW集求法:1. A为开始符号,则把#加⼊FOLLOW(A)2. 对于产⽣式A-->αBβ: (1)把FIRST(β)-{ε}加到FOLLOW(B) (2)若β为ε或者ε属于FIRST(β),则把FOLLOW(A)加到FOLLOW(B)重复1,2步骤直⾄每个FOLLOW集都不再增⼤为⽌。

⽼师和同学能很敏锐地求出来,⽽我只能按照规则,像程序⼀样⼀条条执⾏。

于是我把这个过程写成了程序,如下:数据元素的定义:1const int MAX_N = 20;//产⽣式体的最⼤长度2const char nullStr = '$';//空串的字⾯值3 typedef int Type;//符号类型45const Type NON = -1;//⾮法类型6const Type T = 0;//终结符7const Type N = 1;//⾮终结符8const Type NUL = 2;//空串910struct Production//产⽣式11 {12char head;13char* body;14 Production(){}15 Production(char h, char b[]){16 head = h;17 body = (char*)malloc(strlen(b)*sizeof(char));18 strcpy(body, b);19 }20bool operator<(const Production& p)const{//内部const则外部也为const21if(head == p.head) return body[0] < p.body[0];//注意此处只适⽤于LL(1)⽂法,即同⼀VN各候选的⾸符不能有相同的,否则这⾥的⼩于符号还要向前多看⼏个字符,就不是LL(1)⽂法了22return head < p.head;23 }24void print() const{//要加const25 printf("%c -- > %s\n", head, body);26 }27 };2829//以下⼏个集合可以再封装为⼀个⼤结构体--⽂法30set<Production> P;//产⽣式集31set<char> VN, VT;//⾮终结符号集,终结符号集32char S;//开始符号33 map<char, set<char> > FIRST;//FIRST集34 map<char, set<char> > FOLLOW;//FOLLOW集3536set<char>::iterator first;//全局共享的迭代器,其实觉得应该⽤局部变量37set<char>::iterator follow;38set<char>::iterator vn;39set<char>::iterator vt;40set<Production>::iterator p;4142 Type get_type(char alpha){//判读符号类型43if(alpha == '$') return NUL;//空串44else if(VT.find(alpha) != VT.end()) return T;//终结符45else if(VN.find(alpha) != VN.end()) return N;//⾮终结符46else return NON;//⾮法字符47 }主函数的流程很简单,从⽂件读⼊指定格式的⽂法,然后依次求⽂法的FIRST集、FOLLOW集1int main()2 {3 FREAD("grammar2.txt");//从⽂件读取⽂法4int numN = 0;5int numT = 0;6char c = '';7 S = getchar();//开始符号8 printf("%c", S);9 VN.insert(S);10 numN++;11while((c=getchar()) != '\n'){//读⼊⾮终结符12 printf("%c", c);13 VN.insert(c);14 numN++;15 }16 pn();17while((c=getchar()) != '\n'){//读⼊终结符18 printf("%c", c);19 VT.insert(c);20 numT++;21 }22 pn();23 REP(numN){//读⼊产⽣式24 c = getchar();25int n; RINT(n);26while(n--){27char body[MAX_N];28 scanf("%s", body);29 printf("%c --> %s\n", c, body);30 P.insert(Production(c, body));31 }32 getchar();33 }3435 get_first();//⽣成FIRST集36for(vn = VN.begin(); vn != VN.end(); vn++){//打印⾮终结符的FIRST集37 printf("FIRST(%c) = { ", *vn);38for(first = FIRST[*vn].begin(); first != FIRST[*vn].end(); first++){39 printf("%c, ", *first);40 }41 printf("}\n");42 }4344 get_follow();//⽣成⾮终结符的FOLLOW集45for(vn = VN.begin(); vn != VN.end(); vn++){//打印⾮终结符的FOLLOW集46 printf("FOLLOW(%c) = { ", *vn);47for(follow = FOLLOW[*vn].begin(); follow != FOLLOW[*vn].end(); follow++){48 printf("%c, ", *follow);49 }50 printf("}\n");51 }52return0;53 }主函数其中⽂法⽂件的数据格式为(按照平时做题的输⼊格式设计的):第⼀⾏:所有⾮终结符,⽆空格,第⼀个为开始符号;第⼆⾏:所有终结符,⽆空格;剩余⾏:每⾏描述了⼀个⾮终结符的所有产⽣式,第⼀个字符为产⽣式头(⾮终结符),后跟⼀个整数位候选式的个数n,之后是n个以空格分隔的字符串为产⽣式体。

ll1文法的三个条件

ll1文法的三个条件

ll1文法的三个条件
LL(1)文法是一种常用的上下文无关文法,它具有一些特殊的性质,可以方便地进行语法分析。

LL(1)文法需要满足以下三个条件: 1.左递归和间接左递归消除:LL(1)文法不允许存在左递归或者间接左递归的情况,因为这样会导致分析器无法正确地判断应该使用哪一个产生式来推导符号串。

2.First集不相交:对于每一个非终结符号A,任意两个以A为左部的产生式的First集必须没有交集。

如果存在交集,则在进行预测分析时无法确定使用哪一个产生式进行推导,从而导致分析失败。

3.Follow集合并:对于每一个非终结符号A,将所有以A为左部的产生式的Follow集合并起来,得到的结果就是A的Follow集。

在进行预测分析时,需要用到Follow集来确定何时结束某个非终结符的展开,以及应该采用哪个产生式进行推导。

以上三个条件都是LL(1)文法必须满足的基本要求,只有同时满足才能保证分析的准确性和可行性。

编译原理课程设计-LL1文法分析器设计C++语言实现

编译原理课程设计-LL1文法分析器设计C++语言实现

集美大学计算机工程学院编译原理课程设计报告选题名称:LL(1)文法分析院(系):计算机工程学院专业:计算机科学与技术班级:计算1412指导教师:付永刚学年学期:2016 ~ 2017 学年第 2 学期2017 年06 月29 日摘要:选题要求:根据某一文法编制调试LL(1) 文法语法分分析程序,以便对任意输入的符号串进行分析。

本次课程设计的目的主要是加深对预测分析LL(1)文法语法分析法的理解。

具体如下:1、对语法规则有明确的定义;2、编写的分析程序能够对给定文法进行正确的语法分析;3、对输入给定的文法,手工计算FIRST、FOLLOW集合和select集合,应能判断识别是否为给定文法的句子,并给出推导过程。

4、对输入给定的文法,由程序自动构造FIRST、FOLLOW集合。

5、对于遇到的语法错误,能够做出简单的错误处理,给出简单的错误提示,保证顺利完成语法分析过程。

关键词:语法分析;FIRST集合;FOLLOW集合;分析表一、设计内容及要求(1) 基于PL/0语言,通过编程判断该文法是否为LL(1)文法;(2)计算出文法的First() Follow()(3)构造相应文法的预测分析表(4)对某个输入句子进行语法分析二、实现原理1.LL(1)文法LL(1)文法是一类可以进行确定的自顶向下语法分析的文法。

就是要求描述语言的文法是无左递归的和无回溯的。

根据LL(1)文法的定义,对于同一非终结符A的任意两个产生式A:=a和A:=b,都要满足:SELECT(A:=a )∩SELECT(A:=b)=Ø。

(1)文法的左递归当一个文法是左递归文法时,采用自顶向下分析法会使分析过程进入无穷循环之中。

所以采用自顶向下语法分析需要消除文法的左递归性。

文法的左递归是指若文法中对任一非终结符A有推导AÞA…,则称该文法是左递归的。

左递归又可以分为直接左递归和间接左递归。

●直接左递归若文法中的某一产生式形如A→Aα,α∈V*,则称该文法是直接左递归的。

编译原理 FIRST集和FOLLOW集的求法

编译原理  FIRST集和FOLLOW集的求法

First集合的求法:First集合最终是对产生式右部的字符串而言的,但其关键是求出非终结符的First集合,由于终结符的First集合就是它自己,所以求出非终结符的First集合后,就可很直观地得到每个字符串的First集合。

1. 直接收取:对形如U-a…的产生式(其中a是终结符),把a收入到First(U)中2. 反复传送:对形入U-P…的产生式(其中P是非终结符),应把First(P)中的全部内容传送到First(U)中。

Follow集合的求法:Follow集合是针对非终结符而言的,Follow(U)所表达的是句型中非终结符U所有可能的后随终结符号的集合,特别地,“#”是识别符号的后随符。

1. 直接收取:注意产生式右部的每一个形如“…Ua…”的组合,把a直接收入到Follow(U)中。

2.直接收取:对形如“…UP…”(P是非终结符)的组合,把First(P)除ε直接收入到Follow(U)中。

3.反复传送:对形如P-…U的产生式(其中U是非终结符),应把Follow(P)中的全部内容传送到Follow(U)中。

(或 P-…UB且First(B)包含ε,则把First(B)除ε直接收入到Follow(U)中,并把Follow(P)中的全部内容传送到Follow(U)中)例1:判断该文法是不是LL(1)文法,说明理由 S→ABc A→a|ε B→b|ε?First集合求法就是:能由非终结符号推出的所有的开头符号或可能的ε,但要求这个开头符号是终结符号。

如此题A可以推导出a和ε,所以FIRST(A)={a,ε};同理FIRST (B)={b,ε};S可以推导出aBc,还可以推导出bc,还可以推导出c,所以FIRST(S)={a,b,c}。

Follow集合的求法是:紧跟随其后面的终结符号或#。

但文法的识别符号包含#,在求的时候还要考虑到ε。

具体做法是把所有包含你要求的符号的产生式都找出来,再看哪个有用。

编译原理第5章 LL(1)文法及其分析程序

编译原理第5章  LL(1)文法及其分析程序

}
else error( )
}
}
27
5.2 预测分析程序(Predictive
parser)无回溯的自顶向下分析程序
特征——根据下一个(几个)输入符号为当前要处理 的非终结符选择产生式
要求——文法是LL(1)的 第一个L 从左到右扫描输入串 第二个L 生成的是最左推导 1 向前看一个输入符号(lookahead)
第5章 LL(1)文法及其分析程序
5.1 自上而下的语法分析 5.2 预测分析程序
递归下降子程序 表驱动的预测分析程序 5.3 LL(1)分析程序的生成
LL(1)文法 FIRST和FOLLOW集 定义和计算 5.4 非LL(1)文法的改造
1
5.1自上而下的语法分析
1语法分析概念 2自上而下的语法分析的一般过程 3自上而下的语法分析面临的问题
到分析结束。
5
分析算法分类
分析算法可分为:
自上而下分析法:
从文法的开始符号出发,寻找与输入符号 串匹配的推导,或者说,为输入串寻找一 个最左推导。
自下而上分析法:
从输入符号串开始,逐步进行归约,直至 归约到文法的开始符号。
6
两种方法反映了语法树的两种构 造过程。
自上而下方法是从文法符号开始,将它做为语法
SaASaSbASaabASaabbaSaabbaa
SaASaSbASaSbAaaabAaaabbaa
4
语法分析
在语言的编译实现中,把句子分析的过程称
为语法分析,即完成这个任务的程序称为 语法分析程序或称为识别程序。分析算法 又称识别算法。 从左到右的分析算法,即总是从左到右地识 别输入符号串,首先识别符号串中的最左 符号,进而依次识别右边的一个符号,直

编译原理实验LL1分析

编译原理实验LL1分析
编译原理实验ll1分析基本的功能下面主要采用了ll1分析方法来进行语法分析先通过判断该文法是不是ll1文法如果不是先将其改写成ll1文法再将ll1文法改造成等价形式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. 什么是语法分析?语法分析是编译器中的一个重要模块,它的主要任务是根据给定的语法规则,对输入的源代码进行分析和解释。

语法分析器会根据语法规则构建一个语法树,用于表示源代码的结构和含义。

常用的语法分析方法有递归下降法、LL(1)分析法和LR分析法等。

2. 什么是LL(1)文法?LL(1)文法是一种特殊的上下文无关文法,它具有以下两个特点:(1) 对于任何一个句子,最左推导和最右推导是唯一的。

(2) 在预测分析过程中,只需要向前看一个输入符号就可以确定所采用的产生式。

LL(1)文法是一种常用的文法形式,它适用于递归下降法和LL(1)分析法。

3. 什么是FIRST集合和FOLLOW集合?FIRST集合是指对于一个文法符号,它能够推导出的终结符号的集合。

FOLLOW 集合是指在一个句型中,某个非终结符号的后继终结符号的集合。

计算FIRST集合和FOLLOW集合可以帮助我们进行语法分析,特别是LL(1)分析。

4. 什么是递归下降语法分析法?递归下降语法分析法是一种基于产生式的自顶向下的语法分析方法。

它的基本思想是从文法的开始符号开始,递归地根据产生式进行分析,直到推导出输入符号串或发现错误。

递归下降语法分析法的实现比较简单,但对于某些文法可能会出现回溯现象,影响分析效率。

5. 什么是LR分析法?LR分析法是一种自底向上的语法分析方法,它的基本思想是从输入符号串开始,逐步构建语法树,直到推导出文法的开始符号。

LR分析法具有较好的分析效率和广泛的适用性,常用的LR分析方法有LR(0)、SLR(1)、LR(1)和LALR(1)等。

LL1语法分析,first集,follow集,分析表Java实现

LL1语法分析,first集,follow集,分析表Java实现

import java.awt.*;import java.awt.event.*;import javax.swing.*;import javax.swing.table.DefaultTableModel;import java.sql.*;import java.util.Vector;public class LL1 extends JFrame implements ActionListener { /****/private static final long serialVersionUID = 1L;JTextField tf1;JTextField tf2;JLabel l;JButton b0;JPanel p1, p2, p3;JTextArea t1, t2, t3;JButton b1, b2, b3;JLabel l0, l1, l2, l3, l4;JTable table;Statement sta;Connection conn;ResultSet rs;DefaultTableModel dtm;String Vn[] = null;Vector<String> P = null;int firstComplete[] = null;// 存储已判断过first的数据char first[][] = null;// 存储最后first结果int followComplete[] = null;// 存储已判断过follow的数据char follow[][] = null;// 存储最后follow结果char select[][] = null;// 存储最后select结果int LL = 0;// 标记是否为LL(1)String vt_tou[] = null;// 储存VtObject shuju[][] = null;// 存储表达式数据char yn_null[] = null;// 存储能否推出空LL1() {setLocation(100, 0);setSize(700, 780);tf1 = new JTextField(13);tf2 = new JTextField(13);l = new JLabel(">>");l0 = new JLabel("输入字符串:");l1 = new JLabel("输入的文法为:");l2 = new JLabel(" ");l3 = new JLabel("分析的结果:");l4 = new JLabel("预测分析表:");// p1=new JPanel();p2 = new JPanel();p3 = new JPanel();t1 = new JTextArea(24, 20);t2 = new JTextArea(1, 30);t3 = new JTextArea(24, 40);b0 = new JButton("确定(S为开始)");b1 = new JButton(" 判断文法 ");b2 = new JButton("输入");b3 = new JButton("清空");table = new JTable();JScrollPane jp1 = new JScrollPane(t1);JScrollPane jp2 = new JScrollPane(t2);JScrollPane jp3 = new JScrollPane(t3);p2.add(tf1);p2.add(l);p2.add(tf2);p2.add(b0);p2.add(b1);p2.add(l0);p2.add(l2);p2.add(jp2);p2.add(b2);p2.add(b3);p2.add(l1);p2.add(l3);p2.add(jp1);p2.add(jp3);p3.add(l4);p3.add(new JScrollPane(table));add(p2, "Center");add(p3, "South");b0.addActionListener(this);b1.addActionListener(this);b2.addActionListener(this);b3.addActionListener(this);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);table.setPreferredScrollableViewportSize(new Dimension(660, 200));setVisible(true);}////////////////////界面设计public void actionPerformed(ActionEvent e) {if (e.getSource() == b0) {String a = tf1.getText();String b = tf2.getText();t1.append(a + '→' + b + '\n');}if (e.getSource() == b1) {t3.setText("");int Vnnum = 0, k;Vn = new String[100];P = new Vector<String>();String s[] = t1.getText().split("\n");for (int i = 0; i < s.length; i++) {if (s.length < 2) {t3.setText("文法输入有误,请重新输入");// 判断长度是否符合return;}if (s[i].charAt(0) <= 'Z' && s[i].charAt(0) >= 'A'&& s[i].charAt(1) == '→') {for (k = 0; k < Vnnum; k++) {if (Vn[k].equals(s[i].substring(0, 1))) {break;}}if (Vnnum == 0 || k >= Vnnum) {Vn[Vnnum] = s[i].substring(0, 1);// 存入Vn数据Vnnum++;}P.add(s[i]);} else {t3.setText("文法输入有误,请重新输入");return;}}yn_null = new char[100];first = new char[Vnnum][100];int flag = 0;String firstVn[] = null;firstComplete = new int[Vnnum];for (int i = 0; Vn[i] != null; i++) // 依次求 FIRST**{flag = 0;firstVn = new String[20];if ((flag = add_First(first[i], Vn[i], firstVn, flag)) == -1) return;firstComplete[i] = 1;}t3.append("first集:" + "\n"); // 显示FIRST**for (int i = 0; Vn[i] != null; i++) {t3.append("first(" + Vn[i] + ")={ ");for (int j = 0; first[i][j] != '\0'; j++) {t3.append(first[i][j] + " , ");}t3.append("}" + "\n");}follow = new char[Vnnum][100];String followVn[] = null;followComplete = new int[Vnnum];for (int i = 0; Vn[i] != null; i++) // 求FOLLOW**{flag = 0;followVn = new String[20];if(i==0){}else if ((flag = tianjiaFollow(follow[i], Vn[i], followVn, flag)) == -1)return;followComplete[i] = 1;}t3.append("follow集:" + "\n"); // 显示FOLLOW**for (int i = 0; Vn[i] != null; i++) {t3.append("follow(" + Vn[i] + ")={ ");for (int j = 0; follow[i][j] != '\0'; j++) {t3.append(follow[i][j] + " , ");}t3.append("}" + "\n");}select = new char[P.size()][100];for (int i = 0; i < P.size(); i++) // 求SELECT**{flag = 0;tianjiaSelect(select[i], (String) P.elementAt(i), flag);}t3.append("select集:" + "\n"); // 显示SELECT**for (int i = 0; i < P.size(); i++) {t3.append("select(" + (String) P.elementAt(i) + ")={ ");for (int j = 0; select[i][j] != '\0'; j++) {t3.append(select[i][j] + " , ");}t3.append("}" + "\n");}for (int i = 0; Vn[i] != null; i++)// 判断select交集是否为空{int biaozhi = 0;char save[] = new char[100];for (int j = 0; j < P.size(); j++) {String t = (String) P.elementAt(j);if (t.substring(0, 1).equals(Vn[i])) {for (k = 0; select[j][k] != '\0'; k++) {if (puanduanChar(save, select[j][k])) {save[biaozhi] = select[j][k];biaozhi++;} else// 当有交集时,不为LL(1)文法{t3.append("不是LL(1)文法!!" + "\n");return;}}}}}char Vt[] = new char[100];int biaozhi = 0;for (int i = 0; i < P.size(); i++) {String t = (String) P.elementAt(i);for (int j = 2; j < t.length(); j++)// 提取表达式右侧的终结符存入Vt{if (t.charAt(j) > 'Z' || t.charAt(j) < 'A') {if (puanduanChar(Vt, t.charAt(j))) {Vt[biaozhi] = t.charAt(j);biaozhi++;}}}}if (puanduanChar(Vt, '#'))// 若可推出空集,则将#加入Vt。

LL1文法java实现

LL1文法java实现

题目:给定任意一个LL1文法,计算first集合,follow集合,分析表,并对输入的字符串进行分析,输出分析过程代码:首先是定义文法一行的类,输入时可用输入|,文法开始符要单独输入,根据提示输入大写就行package bianyi;/*** 存储产生式,左边作为一个字符,右边作为一个字符数组* @author Pu**/publicclass Formula {char left;char[] right;publicchar getLeft() {return left;}publicvoid setLeft(char left) {this.left = left;}publicchar[] getRight() {return right;}publicvoid setRight(char[] right) {this.right = right;}public Formula(char left, char[] right) {this.left = left;this.right = right;}public Formula() {// TODO Auto-generated constructor stub}/*** 按需要重写toString方法,且不能直接使用Array.toString(),因为这个方法会在输出的结果的外面添加[],会有混淆* 所以使用for循环手动的添加到result,并且result定义为StringBuffer类型,增加*/@Overridepublic String toString() {StringBuffer result = new StringBuffer();result.append("Formula: ");result.append(left);result.append("->");for(int i = 0; i<right.length; i++){result.append(right[i]);}return result.toString();}}然后是LL1的主要类,更具方法名字可识别作用,都有注释package bianyi;import java.util.ArrayList;import java.util.Arrays;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Scanner;import java.util.Stack;public class LL1 {private char start;private String str;public List<Formula> formulas;private Map<Character, ArrayList<Character>> first;private Map<Character, ArrayList<Character>> follow;private Map<String, Formula> analysisTable;public static final List<Character> VT = Arrays.asList('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',':','=');public static final List<Character> VN = Arrays.asList('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');public LL1() {formulas = new ArrayList<Formula>();first = new HashMap<Character, ArrayList<Character>>();follow = new HashMap<Character, ArrayList<Character>>();analysisTable = new HashMap<String, Formula>();}/*** 1、若有产生式X->a,则把a加入到FIRST(X)中,如存在X->$,则将$也加入到FIRST(X)中* 2、若有X->Y...,则将FIRST(Y)中的所有非$元素都加入到FIRST(X)中,若有X->Y1Y2 (i)* 且Y1~Yi的候选是都有$存在,则把$也加入到FIRST(X)中*/public void computeFirst() {for(Formula f : formulas) {first.put(f.left, new ArrayList<Character>());}boolean flag;ArrayList<Character> list;while(true) {flag = true;for(Formula f : formulas) {list = first.get(f.left);int i;for(i = 0; i < f.right.length; i++) {//X->Y1Y2Y3...,必须first还有$才能继续循环if(VN.contains(f.right[i])) {ArrayList<Character> rlist = first.get(f.right[i]);for(char c : rlist) {if(c != '$' && !list.contains(c)) {list.add(c);first.put(f.left, list);analysisTable.put(f.left + "->" + c, f);flag = false;}}if(!rlist.contains('$')) {break;}} else {if(!list.contains(f.right[i])) {list.add(f.right[i]);first.put(f.left, list);analysisTable.put(f.left + "->" + f.right[i], f);flag = false;}break;}}//若X->ABC...F,若右边每个非终结符first都有$,则将$加入first(X)if(i == f.right.length && !list.contains('$')) {list.add('$');first.put(f.left, list);flag = false;}}if(flag) {break;}}}/*** 1、若有A->aBb(b可为空),则将FOLLOW(b)/{$}加入到FOLLOW(B)中* 2、若有A->aB货A->aBb,且b=*>$,即($属于FIRST(b)),则把FOLLOW(A)加到FOLLOW(B)中*/public void computeFollow() {for(Formula f : formulas) {if(f.left == start) {ArrayList<Character> list = new ArrayList<Character>();list.add('#');follow.put(f.left, list);} else {follow.put(f.left, new ArrayList<Character>());}}boolean flag;ArrayList<Character> list;while(true) {flag = true;for(Formula f : formulas) {for(int j = 0; j < f.right.length; j++) {if(VN.contains(f.right[j])) {list = follow.get(f.right[j]);for(int i = j + 1; i < f.right.length; i++) {//X->...AB...if(VN.contains(f.right[i])) {ArrayList<Character> rlist = first.get(f.right[i]);for(char c : rlist) {if(c != '$' && !list.contains(c)) {list.add(c);follow.put(f.right[j], list);flag = false;}}if(!rlist.contains('$')) {break;}} else {//X->...Aa...if(!list.contains(f.right[i])) {list.add(f.right[i]);follow.put(f.right[j], list);flag = false;}break;}}}}ArrayList<Character> rlist;//X->...Afor(int i = f.right.length - 1; i >= 0; i--) {if(VN.contains(f.right[i])) {rlist = follow.get(f.right[i]);for(char c : follow.get(f.left)) {if(!rlist.contains(c)) {rlist.add(c);follow.put(f.right[i], rlist);flag = false;}}if(!first.get(f.right[i]).contains('$')) {break;}} else {break;}}}if(flag) {break;}}}/*** 1、对买个终结符a属于FIRST(A),把A->b加入到M[A,a],其中b为含有首字母a的候选式或者唯一的候选式。

编译原理课程设计-LL(1)文法的判定

编译原理课程设计-LL(1)文法的判定

课程设计报告课程:编译原理课程设计学号:姓名:班级:教师:时间:计算机科学与技术系结果与分析(可以加页):1、输入一个LL(1)进行测试,测试文法,测试结果如下图所示G(Z):Z->dAZ | bAcA->aA|ε图4 输入LL(1)文法并测试2、输入上述文法的一个句型进行测试,测试结果如下图所示待测试的句型1: bac图5 测试满足指定文法的句型待测试句型2:abc图6 测试不满足指定文法的句型3、测试一个非LL(1)文法图7 测试非LL(1)文法设计体会与建议:近一个月的设计过程,虽然题目早已经布下,但当时正在学习中,看到题目仅是一头雾水,没有一点头绪。

刚拿到题目的时候,乍看很简单,但当真正入手做的时候,觉得设计一个合理的数据结构不是一件很容易的事。

因为一个好的软件设计,应该考虑到它的健壮性和可扩充性,而且能够做的比较完善,对于系统运行中可能遇到的问题能够给出人性化的提示。

这需要在问题分析和题目设计的过程中逐渐改进。

就本次设计而言,要构造预测分析表,就要考虑输入的文法是否是LL(1)文法,对检测的结果应该给予适当的处理。

经过查找资料和他人的耐心答疑,我终于设计处理较为合理的程序,达到了预期的课程设计目的。

随着课程的深入,逐渐了解到一点解题的方法,但对于上机实践还是没有什么想法,后来到图书馆和网上找了很多资料,才了解到大致的实现方法,有根据以前的一点编程经验,于是开始一个模块一个模块的去实现,然后在进行整合,合并成一个完整的程序。

通过本次课程设计,使学到的理论知识得到了实践,清晰地看到了LL(1)分析的全过程,掌握了first,follow,select的机上实现方法,掌握了分析表的构造过程和方法,但遗憾的是,对于一些实现方法,例如句型分析的跟踪过程,仍是参考的网上的源程序,感到了自己的不足,还需更加努力!附录:程序代码#include<stdlib.h>#include<stdio.h>#include<string.h>/*******************************************/int count=0; /*分解的产生式的个数*/int number; /*所有终结符和非终结符的总数*/char start; /*开始符号*/char termin[50]; /*终结符号*/char non_ter[50]; /*非终结符号*/char v[50]; /*所有符号*/char left[50]; /*左部*/char right[50][50]; /*右部*/char first[50][50],follow[50][50]; /*各产生式右部的FIRST和左部的FOLLOW集合*/ char first1[50][50]; /*所有单个符号的FIRST集合*/char select[50][50]; /*各单个产生式的SELECT集合*/char f[50],F[50]; /*记录各符号的FIRST和FOLLOW是否已求过*/char empty[20]; /*记录可直接推出^的符号*/char TEMP[50]; /*求FOLLOW时存放某一符号串的FIRST集合*/int validity=1; /*表示输入文法是否有效*/int ll=1; /*表示输入文法是否为LL(1)文法*/int M[20][20]; /*分析表*/char choose; /*用户输入时使用*/char empt[20]; /*求_emp()时使用*/char fo[20]; /*求FOLLOW集合时使用*//*******************************************判断一个字符是否在指定字符串中********************************************/int in(char c,char *p){int i;if(strlen(p)==0)return(0);for(i=0;;i++){if(p[i]==c)return(1); /*若在,返回1*/if(i==strlen(p))return(0); /*若不在,返回0*/}}/*******************************************得到一个不是非终结符的符号********************************************/char c(){char c='A';while(in(c,non_ter)==1)c++;return(c);}/*******************************************分解含有左递归的产生式********************************************/void recur(char *point){ /*完整的产生式在point[]中*/int j,m=0,n=3,k;char temp[20],ch;ch=c(); /*得到一个非终结符*/k=strlen(non_ter);non_ter[k]=ch;non_ter[k+1]='\0';for(j=0;j<=strlen(point)-1;j++){if(point[n]==point[0]){ /*如果‘|’后的首符号和左部相同*/ for(j=n+1;j<=strlen(point)-1;j++){while(point[j]!='|'&&point[j]!='\0')temp[m++]=point[j++];left[count]=ch;memcpy(right[count],temp,m);right[count][m]=ch;right[count][m+1]='\0';m=0;count++;if(point[j]=='|'){n=j+1;break;}}}else{ /*如果‘|’后的首符号和左部不同*/ left[count]=ch;right[count][0]='^';right[count][1]='\0';count++;for(j=n;j<=strlen(point)-1;j++){if(point[j]!='|')temp[m++]=point[j];else{left[count]=point[0];memcpy(right[count],temp,m);right[count][m]=ch;right[count][m+1]='\0';printf(" count=%d ",count);m=0;count++;}}left[count]=point[0];memcpy(right[count],temp,m);right[count][m]=ch;right[count][m+1]='\0';count++;m=0;}}}/*******************************************分解不含有左递归的产生式********************************************/void non_re(char *point){int m=0,j;char temp[20];for(j=3;j<=strlen(point)-1;j++){if(point[j]!='|')temp[m++]=point[j];else{left[count]=point[0];memcpy(right[count],temp,m);right[count][m]='\0';m=0;count++;}}left[count]=point[0];memcpy(right[count],temp,m);right[count][m]='\0';count++;m=0;}/*******************************************读入一个文法********************************************/char grammer(char *t,char *n,char *left,char right[50][50]){char vn[50],vt[50];char s;char p[50][50];int i,j,k;printf("请输入文法的非终结符号串:");scanf("%s",vn);getchar();i=strlen(vn);memcpy(n,vn,i);n[i]='\0';printf("请输入文法的终结符号串:");scanf("%s",vt);getchar();i=strlen(vt);memcpy(t,vt,i);t[i]='\0';printf("请输入文法的开始符号:");scanf("%c",&s);getchar();printf("请输入文法产生式的条数:");scanf("%d",&i);getchar();for(j=1;j<=i;j++){printf("请输入文法的第%d条(共%d条)产生式:",j,i);scanf("%s",p[j-1]);getchar();}for(j=0;j<=i-1;j++)if(p[j][1]!='-'||p[j][2]!='>'){ printf("\ninput error!");validity=0;return('\0');} /*检测输入错误*/for(k=0;k<=i-1;k++){ /*分解输入的各产生式*/if(p[k][3]==p[k][0])recur(p[k]);elsenon_re(p[k]);}return(s);}/*******************************************将单个符号或符号串并入另一符号串********************************************/void merge(char *d,char *s,int type){ /*d是目标符号串,s是源串,type=1,源串中的‘ ^ ’一并并入目串;type=2,源串中的‘ ^ ’不并入目串*/int i,j;for(i=0;i<=strlen(s)-1;i++){if(type==2&&s[i]=='^');else{for(j=0;;j++){if(j<strlen(d)&&s[i]==d[j])break;if(j==strlen(d)){d[j]=s[i];d[j+1]='\0';break;}}}}}/*******************************************求所有能直接推出^的符号********************************************/void emp(char c){ /*即求所有由‘ ^ ’推出的符号*/ char temp[10];int i;for(i=0;i<=count-1;i++){if(right[i][0]==c&&strlen(right[i])==1){temp[0]=left[i];temp[1]='\0';merge(empty,temp,1);emp(left[i]);}}}/*******************************************求某一符号能否推出‘ ^ ’********************************************/int _emp(char c){ /*若能推出,返回1;否则,返回0*/ int i,j,k,result=1,mark=0;char temp[20];temp[0]=c;temp[1]='\0';merge(empt,temp,1);if(in(c,empty)==1)return(1);for(i=0;;i++){if(i==count)return(0);if(left[i]==c) /*找一个左部为c的产生式*/{j=strlen(right[i]); /*j为右部的长度*/if(j==1&&in(right[i][0],empty)==1)return(1);else if(j==1&&in(right[i][0],termin)==1)return(0);else{for(k=0;k<=j-1;k++)if(in(right[i][k],empt)==1)mark=1;if(mark==1)continue;else{for(k=0;k<=j-1;k++){result*=_emp(right[i][k]);temp[0]=right[i][k];temp[1]='\0';merge(empt,temp,1);}}}if(result==0&&i<count)continue;else if(result==1&&i<count)return(1);}}}/*******************************************判断读入的文法是否正确********************************************/int judge(){int i,j;for(i=0;i<=count-1;i++){if(in(left[i],non_ter)==0){ /*若左部不在非终结符中,报错*/ printf("\nerror1!");validity=0;return(0);}for(j=0;j<=strlen(right[i])-1;j++){if(in(right[i][j],non_ter)==0&&in(right[i][j],termin)==0&&right[i][j]!='^'){ /*若右部某一符号不在非终结符、终结符中且不为‘ ^ ’,报错*/printf("\nerror2!");validity=0;return(0);}}}return(1);}/*******************************************求单个符号的FIRST********************************************/void first2(int i){ /*i为符号在所有输入符号中的序号*/char c,temp[20];int j,k,m;char ch='^';c=v[i];emp(ch);if(in(c,termin)==1) /*若为终结符*/{first1[i][0]=c;first1[i][1]='\0';}else if(in(c,non_ter)==1) /*若为非终结符*/{for(j=0;j<=count-1;j++){if(left[j]==c){if(in(right[j][0],termin)==1||right[j][0]=='^'){temp[0]=right[j][0];temp[1]='\0';merge(first1[i],temp,1);}else if(in(right[j][0],non_ter)==1){if(right[j][0]==c)continue;for(k=0;;k++)if(v[k]==right[j][0])break;if(f[k]=='0'){first2(k);f[k]='1';}merge(first1[i],first1[k],2);for(k=0;k<=strlen(right[j])-1;k++){empt[0]='\0';if(_emp(right[j][k])==1&&k<strlen(right[j])-1){for(m=0;;m++)if(v[m]==right[j][k+1])break;if(f[m]=='0'){first2(m);f[m]='1';}merge(first1[i],first1[m],2);}else if(_emp(right[j][k])==1&&k==strlen(right[j])-1){temp[0]='^';temp[1]='\0';merge(first1[i],temp,1);}elsebreak;}}}}}f[i]='1';}/*******************************************求各产生式右部的FIRST********************************************/void FIRST(int i,char *p){int length;int j,k,m;char temp[20];length=strlen(p);if(length==1) /*如果右部为单个符号*/ {if(p[0]=='^'){if(i>=0){first[i][0]='^';first[i][1]='\0';}else{TEMP[0]='^';TEMP[1]='\0';}}else{for(j=0;;j++)if(v[j]==p[0])break;if(i>=0){memcpy(first[i],first1[j],strlen(first1[j]));first[i][strlen(first1[j])]='\0';}else{memcpy(TEMP,first1[j],strlen(first1[j]));TEMP[strlen(first1[j])]='\0';}}}else /*如果右部为符号串*/{for(j=0;;j++)if(v[j]==p[0])break;if(i>=0)merge(first[i],first1[j],2);elsemerge(TEMP,first1[j],2);for(k=0;k<=length-1;k++){empt[0]='\0';if(_emp(p[k])==1&&k<length-1){for(m=0;;m++)if(v[m]==right[i][k+1])break;if(i>=0)merge(first[i],first1[m],2);elsemerge(TEMP,first1[m],2);}else if(_emp(p[k])==1&&k==length-1){temp[0]='^';temp[1]='\0';if(i>=0)merge(first[i],temp,1);elsemerge(TEMP,temp,1);}else if(_emp(p[k])==0)break;}}}/*******************************************求各产生式左部的FOLLOW********************************************/ void FOLLOW(int i){int j,k,m,n,result=1;char c,temp[20];c=non_ter[i]; /*c为待求的非终结符*/ temp[0]=c;temp[1]='\0';merge(fo,temp,1);if(c==start){ /*若为开始符号*/temp[0]='#';temp[1]='\0';merge(follow[i],temp,1);}for(j=0;j<=count-1;j++){if(in(c,right[j])==1) /*找一个右部含有c的产生式*/{for(k=0;;k++)if(right[j][k]==c)break; /*k为c在该产生式右部的序号*/for(m=0;;m++)if(v[m]==left[j])break; /*m为产生式左部非终结符在所有符号中的序号*/ if(k==strlen(right[j])-1){ /*如果c在产生式右部的最后*/if(in(v[m],fo)==1){merge(follow[i],follow[m],1);continue;}if(F[m]=='0'){FOLLOW(m);F[m]='1';}merge(follow[i],follow[m],1);}else{ /*如果c不在产生式右部的最后*/for(n=k+1;n<=strlen(right[j])-1;n++){empt[0]='\0';result*=_emp(right[j][n]);}if(result==1){ /*如果右部c后面的符号串能推出^*/if(in(v[m],fo)==1){ /*避免循环递归*/merge(follow[i],follow[m],1);continue;}if(F[m]=='0'){FOLLOW(m);F[m]='1';}merge(follow[i],follow[m],1);}for(n=k+1;n<=strlen(right[j])-1;n++)temp[n-k-1]=right[j][n];temp[strlen(right[j])-k-1]='\0';FIRST(-1,temp);merge(follow[i],TEMP,2);}}}F[i]='1';}/*******************************************判断读入文法是否为一个LL(1)文法********************************************/int ll1(){int i,j,length,result=1;char temp[50];for(j=0;j<=49;j++){ /*初始化*/first[j][0]='\0';follow[j][0]='\0';first1[j][0]='\0';select[j][0]='\0';TEMP[j]='\0';temp[j]='\0';f[j]='0';F[j]='0';}for(j=0;j<=strlen(v)-1;j++)first2(j); /*求单个符号的FIRST集合*/ printf("\nfirst1:");for(j=0;j<=strlen(v)-1;j++)printf("%c:%s ",v[j],first1[j]);printf("\nempty:%s",empty);printf("\n_emp:");for(j=0;j<=strlen(v)-1;j++)printf("%d ",_emp(v[j]));for(i=0;i<=count-1;i++)FIRST(i,right[i]); /*求FIRST*/for(j=0;j<=strlen(non_ter)-1;j++){ /*求FOLLOW*/if(fo[j]==0){fo[0]='\0';FOLLOW(j);}}printf("\nfirst:");for(i=0;i<=count-1;i++)printf("%s ",first[i]);printf("\nfollow:");for(i=0;i<=strlen(non_ter)-1;i++)printf("%s ",follow[i]);for(i=0;i<=count-1;i++){ /*求每一产生式的SELECT集合*/ memcpy(select[i],first[i],strlen(first[i]));select[i][strlen(first[i])]='\0';for(j=0;j<=strlen(right[i])-1;j++)result*=_emp(right[i][j]);if(strlen(right[i])==1&&right[i][0]=='^')result=1;if(result==1){for(j=0;;j++)if(v[j]==left[i])break;merge(select[i],follow[j],1);}}printf("\nselect:");for(i=0;i<=count-1;i++)printf("%s ",select[i]);memcpy(temp,select[0],strlen(select[0]));temp[strlen(select[0])]='\0';for(i=1;i<=count-1;i++){ /*判断输入文法是否为LL(1)文法*/ length=strlen(temp);if(left[i]==left[i-1]){merge(temp,select[i],1);if(strlen(temp)<length+strlen(select[i]))return(0);}else{temp[0]='\0';memcpy(temp,select[i],strlen(select[i]));temp[strlen(select[i])]='\0';}}return(1);}/*******************************************构造分析表M********************************************/void MM(){int i,j,k,m;for(i=0;i<=19;i++)for(j=0;j<=19;j++)M[i][j]=-1;i=strlen(termin);termin[i]='#'; /*将#加入终结符数组*/termin[i+1]='\0';for(i=0;i<=count-1;i++){for(m=0;;m++)if(non_ter[m]==left[i])break; /*m为产生式左部非终结符的序号*/ for(j=0;j<=strlen(select[i])-1;j++){if(in(select[i][j],termin)==1){for(k=0;;k++)if(termin[k]==select[i][j])break; /*k为产生式右部终结符的序号*/ M[m][k]=i;}}}}/*******************************************总控算法********************************************/ void syntax(){int i,j,k,m,n,p,q;char ch;char S[50],str[50];printf("请输入该文法的句型:");scanf("%s",str);getchar();i=strlen(str);str[i]='#';str[i+1]='\0';S[0]='#';S[1]=start;S[2]='\0';j=0;ch=str[j];while(1){if(in(S[strlen(S)-1],termin)==1){if(S[strlen(S)-1]!=ch){printf("该符号串不是文法的句型!");return;}else if(S[strlen(S)-1]=='#'){printf("该符号串是文法的句型.");return;}else{S[strlen(S)-1]='\0';j++;ch=str[j];}}else{for(i=0;;i++)if(non_ter[i]==S[strlen(S)-1])break;for(k=0;;k++){if(termin[k]==ch)break;if(k==strlen(termin)){printf("词法错误!");return;}}if(M[i][k]==-1){printf("语法错误!");return;}else{m=M[i][k];if(right[m][0]=='^')S[strlen(S)-1]='\0';else{p=strlen(S)-1;q=p;for(n=strlen(right[m])-1;n>=0;n--)S[p++]=right[m][n];S[q+strlen(right[m])]='\0';}}}printf("S:%s str:",S);for(p=j;p<=strlen(str)-1;p++)printf("%c",str[p]);printf(" \n");}}/*******************************************一个用户调用函数********************************************/ void menu(){syntax();printf("\n是否继续?(y or n):");scanf("%c",&choose);getchar();while(choose=='y'){menu();}}/*******************************************主函数********************************************/void main(){int i,j;start=grammer(termin,non_ter,left,right); /*读入一个文法*/ printf("count=%d",count);printf("\nstart:%c",start);strcpy(v,non_ter);strcat(v,termin);printf("\nv:%s",v);printf("\nnon_ter:%s",non_ter);printf("\ntermin:%s",termin);printf("\nright:");for(i=0;i<=count-1;i++)printf("%s ",right[i]);printf("\nleft:");for(i=0;i<=count-1;i++)printf("%c ",left[i]);if(validity==1)validity=judge();printf("\nvalidity=%d",validity);if(validity==1){ll=ll1();printf("\nll=%d",ll);if(ll==0)printf("\n该文法不是一个LL1文法!");else{MM();printf("\n");for(i=0;i<=19;i++)for(j=0;j<=19;j++)if(M[i][j]>=0)printf("M[%d][%d]=%d ",i,j,M[i][j]);menu();}}}。

第五章 语法分析(自上而下分析法)

第五章 语法分析(自上而下分析法)

解: 这里P=exp , α 1=+term , α 2=-term, β =term 改写: exp → term exp' , exp' → +term exp' | - term exp' | ε
(3)间接左递归的消除 例如文法G(S): S→Qc|c Q→Rb|b R→Sa|a
虽没有直接左递归,但S、Q、R都是左递归的
例:简单的表达式文法 exp → exp addop term | term 消除其左递归。 解:属于格式P → Pα | β 这里 P=exp , α =addop term , β =term 改写: exp → term exp' exp' → addop term exp' | ε
例 文法G(E): E→E+T | T T→T*F | F F→(E) | i 经消去直接左递归后变成: E→TE′ E′→+TE′ | ε T→FT′ T′→*FT′ | ε F→(E) | i 不变
例1 假定有文法G(S): (1) S→xAy (2) A→** | * 分析输入串x*y(记为α)。 ① 按文法的开始符号产生语法树的根节点S,根据规 则,S有三个子孙,于是此时的语法树如图所示; 并把指示器IP指向串α的第一个符号x x*y IP S x*y IP S x A y
把语法树的子节点从左至右对IP所指向的符号进行匹 配。第一符号匹配,于是,IP向后移动一个符号。
是递归下降分析法和预测分析法的基础
LL(1)分析法
构造不带回溯的自上而下分析算法 要消除文法的左递归性 克服回溯
1 左递归的消除
(1)简单直接左递归 直接消除见诸于产生式中的左递归:假定关于非 终结符P的规则为

《编译原理》构造LL(1)分析表的步骤-例题解析

《编译原理》构造LL(1)分析表的步骤-例题解析

《编译原理》构造LL(1)分析表的步骤-例题解析《编译原理》构造 LL(1) 分析表的步骤 - 例题解析易错点及扩展:1、求每个产⽣式的 SELECT 集2、注意区分是对谁 FIRST 集 FOLLOW 集3、开始符号的 FOLLOW 集包含 #4、各集合对对应的对象以及含义集对象含义FIRST 集是对产⽣式右部右部内部的所有终结符集,可能为εFOLLOW 集是对产⽣式左部(⾮终结符)⾮终结符后⾯紧跟的终结符,可能为 #,和该⾮终结符推导出的右部⽆关(因为LL(1)⽂法不包含递归,所以右部不会再有该⾮终结符,所以不能通过该右部判断该⾮终结符后跟集合)SELECT集是对产⽣式需要考虑产⽣式右部的不同情况,进⼀步确定是根据 FIRST 集还是 FOLLOW 集5、SELECT 集的定义注:注意区分 FIRST 集 FOLLOW 时是对α还是 A给定⽂法 G,对于产⽣式 A→α,α∈ V*,则可选集 SELECT(A→α) 有:(1)若α ≠ ε,且α ≠+> ε,则 SELECT(A→α) = FIRST(α)(2)若α ≠ ε,但α =+> ε,则 SELECT(A→α) = FIRST(α) ∪ FOLLOW(A)(3)若α = ε,则 SELECT(A→α) = FOLLOW(A)描述:第 1 条是,当α ≠ ε,且通过1次或多次推不出ε,SELECT(A→α) = FIRST(α)第 2 条是,当α ≠ ε,但α经有限步可推出ε,SELECT(A→α) = FIRST(α) ∪ FOLLOW(A)(注意是⼀个α,⼀个 A)第 3 条是,当α = ε,SELECT 集就等于左部 A 的 FOLLOW 集解题时,先判断是否为ε,是则⽤第(3)条,否则再判断能否通过1次或多次推出ε,是则⽤第(2)条,否则⽤第(1)条求 FIRST,FOLLOW,SELECT 集详细例题可参考:6、LL(1) 分析表的结构分析表是⼀个⼆维数组 M[A,a],其中 A 表⽰⾏,是⾮终结符,a 表式列是终结符或 #。

FIRST集合、FOLLOW集合及LL(1)文法求法

FIRST集合、FOLLOW集合及LL(1)文法求法

FIRST集合、FOLLOW集合及LL(1)⽂法求法FIRST集合定义可从α推导得到的串的⾸符号的集合,其中α是任意的⽂法符号串。

规则计算⽂法符号 X 的 FIRST(X),不断运⽤以下规则直到没有新终结符号或ε可以被加⼊为⽌:(1)如果 X 是⼀个终结符号,那么 FIRST(X) = X。

(2)如果 X 是⼀个⾮终结符号,且 X ->Y1 Y2 … Y k是⼀个产⽣式,其中 k≥1,那么如果对于某个i,a在 FIRST(Y1)、FIRST(Y2)… FIRST(Y i-1)中,就把a加⼊到 FIRST(X) 中。

(3)如果 X ->ε是⼀个产⽣式,那么将ε加⼊到 FIRST(X)中。

以上是书上的官⽅规则,不仅读起来很拗⼝,理解也很累。

下⾯看⼀下精简版的规则(从别⼈ @ 那⾥看来的,感觉很棒,这⾥引⽤⼀下):(1)如果X是终结符,则FIRST(X) = { X } 。

(2)如果X是⾮终结符,且有产⽣式形如X → a…,则FIRST( X ) = { a }。

(3)如果X是⾮终结符,且有产⽣式形如X → ABCdEF…(A、B、C均属于⾮终结符且包含ε,d为终结符),需要把FIRST( A )、FIRST( B )、FIRST( C )、FIRST( d )加⼊到 FIRST( X )中。

(4)如果X经过⼀步或多步推导出空字符ε,将ε加⼊FIRST( X )。

实践记得,曾经有⼈说过:只读,就会⽩给下⾯以这个⽂法为例讲解⼀波,会⽤精简版规则,更容易理解⼀些:E -> T E'E' -> + T E' | εT -> F T'T' -> * F T' | εF -> ( E ) | id12345FIRST(E) = FIRST(T)根据规则3,很容易理解,这⾥要注意的由于T不含ε,所以遍历到T就停⽌了,E’不会加⼊进来FIRST(E’) = FIRST(+) ∪ FIRST(ε)= { +, ε }根据规则2和4,,很好理解FIRST(T) = FIRST(F)根据规则3,和第⼀条推导过程⼀样FIRST(T’) = FIRST() ∪ FIRST(ε)= { , ε }根据规则2和4,和第⼆条推导⼀样FIRST(F) = FIRST( ( ) ∪ FIRST(id)= { ( , id }根据规则2结果:FIRST(E) = FIRST(T) = FIRST(F) = { ( , id }FIRST(E') = FIRST(+) ∪ FIRST(ε)= { + , ε }FIRST(E') = FIRST(*) ∪ FIRST(ε)= { * , ε }123FOLLOW集合定义对于⾮终结符号A,FOLLOW(A)被定义为可能在某些句型中紧跟在A右边的终结符号集合。

最新广东海洋大学编译原理LL(1)文法分析器实验(java)

最新广东海洋大学编译原理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)语法分析方法,以及预测分析表的构造,进一步熟悉了语法分析的详细过程,收获还是蛮大的,值得我们认真对待。

ll1文法的判定条件

ll1文法的判定条件

ll1文法的判定条件
LL(1)文法是一种上下文无关文法,用于描述一类非常有限的语言结构。

LL(1)文法有以下几个判定条件:
1. 无左递归:LL(1)文法不能包含直接左递归。

直接左递归是指产生式右部的第一个符号是产生式的左部非终结符本身。

2. 消除间接左递归:如果存在间接左递归,即产生式右部可以通过一系列的推导最终回到产生式左部的情况,需要将间接左递归转化为直接左递归,使得文法不包含间接左递归。

3. 消除左公因子:在LL(1)文法中,产生式右部的第一个符号不能相同。

如果存在左公因子,即产生式右部的某个前缀相同,需要对左公因子进行提取,得到新的产生式。

4. First集不相交:对于文法中每个非终结符A,其First集合与其他非终结符的First集合应该互斥,即不相交。

First集合是从一个非终结符开始的所有可能的终结符的集合。

5. Follow集不相交:同样,对于文法中的每个非终结符A,其Follow集合与其他非终结符的Follow集合应该互斥,即不相交。

Follow集合是在一个推导过程中,紧跟在非终结符后面的所有可能的终结符的集合。

通过满足以上五个条件,我们可以确定一个文法是否为LL(1)文法。

LL(1)文法具有预测性,即在每个输入符号位置,根据当前的输入符号和推导栈中的符号,就可以确定接下来使用哪个产生式进行推导。

这种特性使得LL(1)文法适用于递归下降分析法和预测分析表的构建。

LL(1)文法的判定条件包括无左递归、消除间接左递归、消除左公因子、First集不相交和Follow集不相交。

满足这些条件的文法可以被用于构建预测分析表,实现语法分析。

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

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文法

又E’ε, ∴ FOLLOW(E’)加入FOLLOW(T)
FOLLOW(T’)= FOLLOW(T)= {+,),#}
∵T → FT’ ∴ FOLLOW(T)加入FOLLOW(T’)
FOLLOW(F)={*,+,),#}
∵T → FT’ ∴ FOLLOW(F)=FIRST(T’)-{ε}
又T’ε ∴ FOLLOW(T)加入FOLLOW(F)
注意:要顺序往下做,一旦不满足条件, 过程就要中断进行
2024/7/20 编 译 原 理
2024年7月20日
4
FIRST(F)={(,i} FIRST(T’)={*,ε} FIRST(T)=FIRST(F)-{ε}={(,i} FIRST(E’)={+,ε} FIRST(E)= FIRST(T)-{ε}={(,i}
FOLLOW(E)={#,)} ∵E是开始符号∴#∈FOLLOW(E)
又F →(E)
∴ )∈FOLLOW(E)
FOLLOW(E’)={#,)} ∵E → TE’ ∴FOLLOW(E)加入 FOLLOW(E’)
FOLLOW(T)={+,),#} ∵E’ → +TE’ ∴FIRST(E’)-{ε}加入FOLLOW(T)
2024/7/20 编 译 原 理
2024年7月20日
5
2. FOLLOW集
对于文法G的非终结符的后继符号集称为 FOLLOW集,定义如下:
FOLLOW(A) ={a|S …Aa…,a ∈VT} 若S …A,则规定#∈FOLLOW(A) FOLLOW(A):是所有句型中紧接A之后的终结符号或#
E→TE' E'→+TE'| T→FT' T'→*FT'| F→(E)|i
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

课程名称: LL1文法的判别年级/专业/班: 11级计算机类(二)班姓名: 徐勇兵学号: E01114278import java.util.Vector;import javax.swing.JOptionPane;class Tools{public Vector<String> protection(Vector<String> vs){Vector<String> newvector=new Vector<String>();for(int i=0;i<vs.size();i++)newvector.add(vs.get(i));return newvector;}public Vector<Vector<String>> doubleprotection(Vector<Vector<String>> vs){ Vector<Vector<String>> newvector=new Vector<Vector<String>>();for(int i=0;i<vs.size();i++){Vector<String> produce=(Vector<String>)vs.get(i);Vector<String> temp=new V ector<String>();for(int j=0;j<produce.size();j++){temp.add((String)produce.get(j));}//for jnewvector.add(temp);}//for ireturn newvector;}}class Elements{Vector<String> end=new V ector<String>();//表示终结符Vector<String> noend=new Vector<String>();//表示非终结符Vector<Vector<String>> produce=new Vector<Vector<String>>();//产生式public void setend(){//终结符元素添加while(true){String s=JOptionPane.showInputDialog(null,"请输入终结符");if(s==null){ return;}//ifend.add(s);}//while}//public void addend(){//元素添加public void setnoend(){//非终结符元素添加while(true){String s=JOptionPane.showInputDialog(null,"非请输入终结符");if(s==null){ return;}//ifnoend.add(s);}//while}//public void addnoend(){//public void setproduce(){while(true){String s=JOptionPane.showInputDialog(null,"请输入产生式,->隔开");if(s==null)return;Vector<String> temp=new Vector<String>();temp.add(s.split("->")[0]);temp.add(s.split("->")[1]);produce.add(temp);}//while}//public void addproduce()public Vector<String> getend(){return end;}public Vector<String> getnoend(){return noend;}public Vector<Vector<String>> getproduce(){return this.produce;}public void run(){/*************************TEST********************************/ end.add("a");end.add("b");end.add("c");end.add("e");noend.add("S");noend.add("A");noend.add("B");noend.add("C");noend.add("D");Vector<String> temp=new Vector<String>();temp.add("S");temp.add("AB");produce.add(temp);/*************************/Vector<String> temp1=new Vector<String>();temp1.add("S");temp1.add("bC");produce.add(temp1);/*************************/Vector<String> temp2=new Vector<String>();temp2.add("A");temp2.add("e");produce.add(temp2);/*************************/Vector<String> temp3=new Vector<String>();temp3.add("A");temp3.add("b");produce.add(temp3);/*************************/Vector<String> temp4=new Vector<String>();temp4.add("B");temp4.add("e");produce.add(temp4);/*************************/Vector<String> temp5=new Vector<String>();temp5.add("B");temp5.add("aD");produce.add(temp5);/*************************/Vector<String> temp6=new Vector<String>();temp6.add("C");temp6.add("AD");produce.add(temp6);/*************************/Vector<String> temp7=new Vector<String>();temp7.add("C");temp7.add("b");produce.add(temp7);/*************************/Vector<String> temp8=new Vector<String>();temp8.add("D");temp8.add("aS");produce.add(temp8);/*************************/Vector<String> temp9=new Vector<String>();temp9.add("D");temp9.add("c");produce.add(temp9);/*************************/// System.out.println("produce.size()="+produce.size());/***********************TEST**********************************///this.setend();//this.setnoend();//this.setproduce();}public boolean Iscontainend(String s)//正则表达式判断s1是否在END的闭包里面正则忘了怎么写了{int length=s.length();for(int i=0;i<length;i++){String a=""+s.charAt(i);if(end.contains(a))return true;else continue;}//forreturn false;}//public boolean isRGPcontain(String s)public boolean IsNoENd(String s){String ss=""+s.charAt(0);if(! Iscontainend(ss))//如果不含有终结符,则为非终结符return true;return false;}// public boolean}//class Elementsclass Follow{Vector<String> end=new V ector<String>();//表示终结符Vector<String> noend=new Vector<String>();//表示非终结符Vector<Vector<String>> produce=new Vector<Vector<String>>();//产生式Vector<Vector<String>> emptytable=new Vector<V ector<String>>();Elements elements;First first;Vector<Vector<String>> flagtable=new Vector<Vector<String>>();Vector<Vector<String>> followtable=new Vector<Vector<String>>();public void showfollowtable(){for(int i=0;i<followtable.size();i++){System.out.println();Vector<String> temp=followtable.get(i);System.out.print(temp.get(0)+"的Follow集:");for(int j=1;j<temp.size();j++){System.out.print(temp.get(j)+",");}}}//public void showfollowtable(){public Vector<String> getAppointfollow(String s){Vector<String> temp=new V ector<String>();for(int i=0;i<followtable.size();i++){temp=followtable.get(i);if(temp.get(0).equals(s))return temp;}//forreturn temp;}// public Vector<String> getAppointfollow(String s)public void init_flagtableAndfollowtable(){for(int i=0;i<noend.size();i++){Vector<String> temp=new V ector<String>();temp.add(noend.get(i));temp.add("no");flagtable.add(temp);}//forfor(int i=0;i<noend.size();i++){Vector<String> temp=new V ector<String>();temp.add(noend.get(i));followtable.add(temp);}//for}//public void init_flagtableAndfollowtablepublic void show_flagtableAndfollowtable(){System.out.println();System.out.println("flagtable is shown as follows:");for(int i=0;i<flagtable.size();i++){Vector<String> temp=flagtable.get(i);System.out.print(temp.get(0)+":"+temp.get(1));System.out.println();}//forSystem.out.println("followtable is shown as follows:");for(int i=0;i<followtable.size();i++){System.out.println();Vector<String> temp=followtable.get(i);System.out.print(temp.get(0)+":");for(int j=1;j<temp.size();j++){System.out.print(temp.get(j));}}//for}public String getFlagTable(String s){for(int i=0;i<flagtable.size();i++){Vector<String> temp=flagtable.get(i);if(temp.get(0).equals(s)){return temp.get(1);}}//forreturn "no";}// public String getFlagTable(String s)public void setFlagTable(String s){for(int i=0;i<flagtable.size();i++){Vector<String> temp=flagtable.get(i);if(temp.get(0).equals(s)){temp.set(1,"yes");}}//for}// public String setFlagTable(String s)public boolean Isindicateempty(String s){for(int i=0;i<emptytable.size();i++){Vector<String> temp=emptytable.get(i);if(temp.get(0).equals(s)){if(temp.get(1).equals("yes"))return true;elsereturn false;}//if 外层}//forreturn false;}// public boolean Isindicatefull(String s)public Vector<Vector<String>> getFirsrtandFollow(String s){//获得非终结符s的要加入的Follw(A)和First(a)的a和A//System.out.println("欲求"+s+"的相关信息");Vector<Vector<String>>vs=new Vector<Vector<String>>();Vector<String> first=new Vector<String>();Vector<String> follow=new Vector<String>();for(int i=0;i<produce.size();i++){Vector<String> temp=produce.get(i);String left=temp.get(0);String right=temp.get(1);//获取产生式的右部int index=right.indexOf(s);if(index!=(-1)){//如果右部含有次非终结符的话if(right.length()==(index+1)){//D->aS型(S为所求)follow.add(left);}else{String nextchar=""+right.charAt(index+1);first.add(nextchar);if(Isindicateempty(nextchar)){//如果此非终结符可以产生空的话follow.add(left);}}}//if(index!=(-1))}//for/*if(first.isEmpty()==false){//如果不空System.out.println(s+"firsr为:");for(int i=0;i<first.size();i++){System.out.println();String sb=(String)first.get(i);System.out.print(sb);}//for}else{//System.out.println(s+"的first为空");}if(follow.isEmpty()==false){//如果不空System.out.println();System.out.print(s+"的follow为:");for(int i=0;i<follow.size();i++){String sb=(String)follow.get(i);System.out.print(sb);}//for}else{//System.out.println(s+"的follow为空");}*/vs.add(first);vs.add(follow);return vs;}public Vector<String> addElements(Vector<String> vs,Vector<String>temp){ for(int i=0;i<temp.size();i++){if(!vs.contains(temp.get(i)))vs.add(temp.get(i));}//forreturn vs;}//public Vector<String> addElements(Vector<String> vs,Vector<String>temp){ public Vector<String> getFollow(String s){Vector<String> follow=getAppointfollow(s);//System.out.println(s+"的flagtable对应的是"+getFlagTable(s));if(getFlagTable(s).equals("yes")){/*System.out.println("返回follow集,防止死循环");System.out.println("返回follow集签先输出查看");for(int i=0;i<follow.size();i++){System.out.print(follow.get(i)+",");}System.out.println();*/Vector<String> kk=new V ector<String>();for(int i=1;i<follow.size();i++){kk.add(follow.get(i));}return kk;}setFlagTable(s);//将flagtable的对应表项置为yesString Start_Characrter="S";if(s.equals(Start_Characrter)){//System.out.println("follow加入了#");follow.add("#");}Vector<Vector<String>> vs=getFirsrtandFollow(s);//show_flagtableAndfollowtable();Vector<String> firstcharacter=vs.get(0);Vector<String> followcharacter=vs.get(1);System.out.println();//System.out.println("111111111111111111");if(firstcharacter.isEmpty()==false){//如果不空for(int i=0;i<firstcharacter.size();i++){String sb=(String)firstcharacter.get(i);Vector<String> vv= first.getFirst(sb);follow=addElements(follow,vv);}//for}if(followcharacter.isEmpty()==false){//如果不空for(int i=0;i<followcharacter.size();i++){String sb=(String)followcharacter.get(i);Vector<String> vv= getFollow(sb);follow=addElements(follow,vv);}//for}follow.remove("e");Vector<String> kk=new V ector<String>();for(int i=1;i<follow.size();i++){kk.add(follow.get(i));}//return follow;return kk;}public Follow(Elements _elements,Vector<Vector<String>> _emptytable,First _first){ this.elements=_elements;this.emptytable=_emptytable;this.first=_first;this.end=elements.getend();this.noend=elements.getnoend();this.produce=elements.getproduce();init_flagtableAndfollowtable();}}//class followclass First{Vector<String> end=new V ector<String>();//表示终结符Vector<String> noend=new Vector<String>();//表示非终结符Vector<Vector<String>> produce=new Vector<Vector<String>>();//产生式Vector<Vector<String>> emptytable=new Vector<V ector<String>>();Elements elements;public First(Elements _elements,Vector<Vector<String>> _emptytable){ this.elements=_elements;this.emptytable=_emptytable;this.end=elements.getend();this.noend=elements.getnoend();this.produce=elements.getproduce();}public Vector<String> getRight(String left){Vector<String> right=new Vector<String>();for(int i=0;i<produce.size();i++){Vector<String>temp=produce.get(i);if(temp.get(0).equals(left)){right.add(temp.get(1));}}//forreturn right;}//public String[] getRight(String left)public Vector<String> addElements(Vector<String> vs,Vector<String>temp){ for(int i=0;i<temp.size();i++){if(!vs.contains(temp.get(i)))vs.add(temp.get(i));}//forreturn vs;}//public Vector<String> addElements(Vector<String> vs,Vector<String>temp){ public boolean Isindicateempty(String s){for(int i=0;i<emptytable.size();i++){Vector<String> temp=emptytable.get(i);if(temp.get(0).equals(s)){if(temp.get(1).equals("yes"))return true;elsereturn false;}//if 外层}//forreturn false;}// public boolean Isindicatefull(String s)public boolean IsNoENd(String s){String ss=""+s.charAt(0);if(! elements.Iscontainend(ss))//如果不含有终结符,则为非终结符return true;return false;}// public booleanpublic boolean IsStartWithEnd(String s){//判断是否以终结符开头String ss=""+s.charAt(0);if( elements.Iscontainend(ss))return true;return false;}public Vector<String> getFirst(String s){Vector<String> vs=new Vector<String>();int ii=0;if(IsStartWithEnd(s)){vs.add(""+s.charAt(0));}if(s.length()==1&&IsNoENd(s)){//形如Fisst(A)Vector<String> temp=getRight(s);for(int i=0;i<temp.size();i++){vs=addElements(vs,getFirst(temp.get(i)));}//for}//ifif(s.length()!=1){//形如First(AB)或者First(AaB)for(ii=0;ii<s.length();ii++){String ss=""+s.charAt(ii);if(Isindicateempty(ss)){//如果能退出空Vector<String> temp=getFirst(ss);if(temp.contains("e")){//如果有空则删除temp.remove("e");}vs=addElements(vs,temp);}//ifelse{vs=addElements(vs,getFirst(ss));break;}} //forif(ii==s.length()){//如果所有的非终结符都能退出空,则将e加入vs.add("e");}}//if if(s.length()!=1){//形如First(AB)或者First(AaB)return vs;}}//class Firstclass Select{Elements elements;First first;Follow follow;Emptytable emptytable;Vector<String> end;Vector<String> noend;Vector<Vector<String>> produce;Vector<Vector<String>> flagtable=new Vector<Vector<String>>();Vector<Vector<String>> followtable=new Vector<Vector<String>>();public Select(Elements _elements,Emptytable _emptytable,First _first,Follow _follow){ this.elements=_elements;this.emptytable=_emptytable;this.end=elements.getend();this.noend=elements.getnoend();this.produce=elements.getproduce();this.first=_first;this.follow=_follow;init_flagtable();}public void showselecttable(){for(int i=0;i<produce.size();i++){Vector<String> temp=produce.get(i);System.out.println();System.out.print("产生式"+temp.get(0)+"->"+temp.get(1)+"的select集是:");Vector<String> select=getselect(temp);for(int j=0;j<select.size();j++){System.out.print(select.get(j)+",");}}}public Vector<String> addElements(Vector<String> vs,Vector<String>temp){for(int i=0;i<temp.size();i++){if(!vs.contains(temp.get(i)))vs.add(temp.get(i));}//forreturn vs;}//public Vector<String> addElements(Vector<String> vs,Vector<String>temp){public Vector<Vector<String>> getallproduces(String left){//返回以left为左部的所有产生式Vector<Vector<String>> vs=new Vector<Vector<String>>();for(int i=0;i<produce.size();i++){Vector<String> temp=produce.get(i);if(temp.get(0).equals(left))vs.add(temp);}return vs;}public void init_flagtable(){for(int i=0;i<noend.size();i++){Vector<String> temp=new V ector<String>();temp.add(noend.get(i));temp.add("no");flagtable.add(temp);}//for}//public void init_flagtablepublic String getFlagTable(String s){for(int i=0;i<flagtable.size();i++){Vector<String> temp=flagtable.get(i);if(temp.get(0).equals(s)){return temp.get(1);}}//forreturn "no";}// public String getFlagTable(String s)public void setFlagTable(String s){for(int i=0;i<flagtable.size();i++){Vector<String> temp=flagtable.get(i);if(temp.get(0).equals(s)){temp.set(1,"yes");}}//for}// public String setFlagTable(String s)public boolean IsIndicateEmpty(String right){//判断产生式右部是否可以推出空for(int i=0;i<right.length();i++){String vv=""+right.charAt(i);if(vv.equals("e"))//如A->econtinue;if(elements.Iscontainend(vv)){//如果含有除e以外的终结符//System.out.println();return false;}if(elements.IsNoENd(vv)){//如果是个非终结符if(emptytable.whattag(vv).equals("yes"))continue;if(emptytable.whattag(vv).equals("no"))return false;}}return true;}// IsIndicateEmpty(String right){public Vector<String> getselect(Vector<String> temp){//返回某条产生式的select集合Vector<String> combination=new Vector<String>();String left=temp.get(0);String right=temp.get(1);if( IsIndicateEmpty(right)){//如果右部可以推出空的话Vector<String> firstcollection=first.getFirst(right);Vector<String> followcollection=follow.getFollow(left);combination=addElements(firstcollection,followcollection);combination.remove("e");return combination;}//ifelse{Vector<String> firstcollection=first.getFirst(right);return firstcollection;}//return combination;}// public Vector<String> getselect(Vector<String> temp)public Vector<Vector<String>> getcollectionOfselect(Vector<Vector<String>> allproduce){//返回有相同左部的产生式的select集的集合Vector<Vector<String>> selectcollection=new Vector<Vector<String>>();for(int i=0;i<allproduce.size();i++){Vector<String> temp=allproduce.get(i);selectcollection.add( getselect(temp));}return selectcollection;}// public Vector<Vector<String>> getcollectionOfselect(Vector<Vector<String>> allproduce)public boolean IsIntersection( Vector<V ector<String>> selectcollection){for(int i=0;i<selectcollection.size();i++){Vector<String> temp=selectcollection.get(i);for(int j=0;j<temp.size();j++){String s=temp.get(i);for(int m=i+1;m<selectcollection.size();m++){Vector<String> vv=selectcollection.get(m);if(vv.contains(s));System.out.println();System.out.println("产生交集"+s+"不是LL1,程序即将结束");return true;}//for m}// for j}// for ireturn false;}// public boolean IsIntersectionpublic boolean Judge(){for(int i=0;i<produce.size();i++){Vector<String> temp=produce.get(i);String left=temp.get(0);String right=temp.get(1);if(getFlagTable(left).equals("yes"))continue;setFlagTable(left);Vector<Vector<String>> allproduce=getallproduces(left);Vector<Vector<String>> selectcollection= getcollectionOfselect( allproduce);if(IsIntersection( selectcollection)==true){System.out.println("以"+left+"为左部的产生式有交集,所以不是LL1");return false;}}//forreturn true;}}//class Selectclass Emptytable{Tools tools=new Tools();Elements elements;Vector<String> end;Vector<String> noend;Vector<Vector<String>> produce;Vector<String> newend;Vector<String> newnoend;Vector<Vector<String>> newproduce;Vector<Vector<String>> emptytable=new Vector<V ector<String>>();public Vector<Vector<String>> getemptytable(){return emptytable;}public void shownewinforamtion(){System.out.print("emptytable产生式输出如下:");for(int i=0;i<produce.size();i++){System.out.println(" ");Vector<String> temp=(Vector<String>)produce.get(i);System.out.print((String)temp.get(0)+"->"+(String)temp.get(1));}System.out.println();System.out.println("****************");if(newproduce.isEmpty()){System.out.println("newproduce has been cleared");return;}System.out.print("新的产生式输出如下:");for(int i=0;i<newproduce.size();i++){System.out.println(" ");Vector<String> temp=(Vector<String>)newproduce.get(i);System.out.print((String)temp.get(0)+"->"+(String)temp.get(1));}System.out.println(" ");}public String whattag(String noendcharacter ){//判断某个非终结符在表中的状态,只有yes,no unsure三种for(int i=0;i<emptytable.size();i++){Vector<String> temp=( Vector<String>)emptytable.get(i);if(temp.get(0).equals(noendcharacter)){return (String)temp.get(1);}//if}//forreturn "error";}public void initial_table(){for(int i=0;i<noend.size();i++){Vector<String> temp=new V ector<String>();temp.add((String)noend.get(i));temp.add("unsure");emptytable.add(temp);}//for}//public void initial_table(){public void updatetable(String left,String tag){for(int i=0;i<emptytable.size();i++){Vector<String> temp=(Vector<String>)emptytable.get(i);if(temp.get(0).equals(left)){temp.set(1,tag);//System.out.println("表格已被更新为:"+temp.get(0)+" "+temp.get(1));}}//for}//public void updatetable(String left,String tag)public void delete(String left,String right){//删除某条特定的产生式//System.out.println("欲删除产生式:"+left+"->"+right);Vector<String> temp=new V ector<String>();temp.add(left);temp.add(right);if(newproduce.remove(temp)){//System.out.println(left+"->"+right+" produce has deleted successfuly");}else{System.out.println("fail to remove this produce:"+left+"->"+right);}}//public void delete(String left,String right)public void deleteall(String left){//删除以某个字符为左部的所有产生式boolean flag=true;BlockB:while(flag){flag=false;for(int i=0;i<newproduce.size();i++){Vector<String> temp=newproduce.get(i);if(temp.get(0).equals(left)){if(newproduce.remove(temp)){//System.out.println("以"+left+"为左部的产生式被删除");}else{//System.out.println("fail to remove this produce:"+"以"+left+"为左部的产生式");}flag=true;continue BlockB;}//if}//for}//while()}//public void deleteall(String left)public boolean Isleftempty(String left){//判断以某个左部为产生式是否为空for(int i=0;i<newproduce.size();i++){Vector<String> temp=(Vector<String>)newproduce.get(i);if(temp.get(0).equals(left)){return false;}}//forreturn true;}//public boolean Isleftempty(String left)public void firststep(){//第一步(删除某条产生式之后向量的长度会变短,再用get(i)会取不到数据,所以要用到BLOCK)Boolean flag=true;BlockA:while(flag==true){flag=false;for(int i=0;i<newproduce.size();i++){Vector<String> temp=newproduce.get(i);String left=temp.get(0);String right=temp.get(1);if(elements.Iscontainend(right)){//如果产生式的右部含有终结符则删除//System.out.println("产生式的右部为:"+right);delete(left,right);if(Isleftempty(left)){//如果以此为左部的产生式都被删除了,则将表格对应的修改为noupdatetable(left,"no");}//内层ifflag=true;continue BlockA;}//if 外层} //for}//while()}//public void firststep()public void secondstep(){//第二步Boolean flag=true;BlockC:while(flag==true){flag=false;for(int i=0;i<newproduce.size();i++){Vector<String> temp=newproduce.get(i);String left=temp.get(0);String right=temp.get(1);String kong=""+"e";if(right.equals(kong)){//如果右部是空updatetable(left,"yes");deleteall(left);flag=true;continue BlockC;}}//for}//while()}//public void secondstep()public void thirdstep(){boolean flag=true;BlockD:while(flag==true){flag=false;for(int i=0;i<newproduce.size();i++){Vector<String> temp=(Vector<String>)newproduce.get(i);String left=temp.get(0);String _right=temp.get(1);StringBuffer right=new StringBuffer(_right);for(int j=0;j<right.length();j++){String s=""+right.charAt(j);//System.out.println("终结符S为"+s);StringBuffer tag=new StringBuffer(whattag(s));String _tag=tag.toString();//System.out.println(s+"的tag="+tag);if(_tag.equals("yes")){//如果该非终结符是yes的话,删除该非终结符int index=right.indexOf(s);if(index!=-1){//System.out.println("index="+index);right.deleteCharAt(index);if(right.length()==0){//如果该产生式的右部为空的话//System.out.println("第三步。

相关文档
最新文档