编译原理实验之LL(1)型文法
这个实验是我们编译原理的一个作业,我花了不少时间,问了很多同学,参考了老师给的文档终于把实验做了出来,在这里我打算把整个实验解决的过程来分享一下,也希望大家分享更好,更优质的算法和代码。这个实验我最早打算用C语言去写,但是后来发现如果用C语言写会非常麻烦,所以后来右改用了Java,但是算法思路是一样的。然后就是实验过程。
package Then;
import java.util.*;
public class Main {
public static void main(String[] args) {//主函数,用于程序的基本运行
grammar gra = new grammar();//声明一个grammar类,这个类里边有所有需要用到的数据结构,方法。
gra.find_empty();//首先进行判空
gra.find_first();//找first 集
gra.find_follow();//找follow 集
gra.find_select();//找select集
System.out.print("Select:");//输出select集
System.out.println(gra.select_map);
System.out.println();//输出换行,格式需求
System.out.println();
System.out.println();
System.out.println();
System.out.print("First:");//输出first 集
System.out.println(gra.first_map);
System.out.println();
System.out.println();
System.out.println();
System.out.println();
System.out.print("Follow:");//输出follow 集
System.out.println(gra.follow_map);
System.out.println();
System.out.println();
System.out.println();
System.out.println();
System.out.print("判空:");//输出判空情况
System.out.println(gra.empty_map);
gra.get_it();//进行预测分析
}
}
class grammar{//grammar类的定义,里面有存储结构,各种方法
Scanner sc = new Scanner(System.in);
List<String> gram = new ArrayList<String>();
Map <String,Integer> empty_map = new HashMap<String, Integer>();
Map <Character,Set<Character>> first_map = new HashMap<Character,Set<Character>>();
Map <Character,Set<Character>> follow_map = new HashMap<Character,Set<Character>>();
Map <String,Set<Character>> select_map = new HashMap<String,Set<Character>>();
List <Character> unend = new ArrayList<Character>();
List <Character> end = new ArrayList<Character>();
public grammar(){
System.out.print("请输入文法:");
int n = sc.nextInt();
for(int i=0;i<n;i++){
String a_gram = sc.next();
gram.add(a_gram);
Set<Character> list2 = new HashSet<Character>();
select_map.put(a_gram, list2);
for(int j=0;j<a_gram.length();j++){
if(a_gram.charAt(j)>='A'&&a_gram.charAt(j)<='Z'){
String ch = Character.toString(a_gram.charAt(j));
empty_map.put(ch, 2);
Set<Character> list = new HashSet<Character>();
//list.add('#');
Set<Character> list1 = new HashSet<Character>();
//list1.add('#');
first_map.put(a_gram.charAt(j), list);
follow_map.put(a_gram.charAt(j),list1);
if(!this.unend.contains(a_gram.charAt(j)))
unend.add(a_gram.charAt(j));
}
else if(a_gram.charAt(j)!='-'&&a_gram.charAt(j)!='>'&&a_gram.charAt(j)!='@'){
if(!this.end.contains(a_gram.charAt(j)))
end.add(a_gram.charAt(j));
}
}
}
this.follow_map.get(this.gram.get(0).charAt(0)).add('#');
}
public void out_put(){
for(int i=0;i<this.gram.size();i++){
System.out.println(this.gram.get(i));
}
}
public void find_empty(){//判空方法
int flag_buff=0,bf=1;
int flag_sing_empty=0,fse=0;
int point=3;
char b;
while (flag_buff!=bf) {
flag_buff = bf;
for(int i=0;i<this.gram.size();i++){
if(flag_sing_empty!=fse){
point++;
b = this.gram.get(i).charAt(point);
}
else{
point=3;
b = this.gram.get(i).charAt(point);
}
if(this.empty_map.get(Character.toString(this.gram.get(i).charAt(0)))==0){
continue;
}
if(b=='@'){
if(this.empty_map.get(Character.toString(this.gram.get(i).charAt(0)))!=0){
this.empty_map.put(Character.toString(this.gram.get(i).charAt(0)),0);
flag_buff++;
}
flag_sing_empty=fse;
}
else if(b>='a'&&b<='z'){
if(this.empty_map.get(Character.toString(this.gram.get(i).charAt(0)))==2){
this.empty_map.put(Character.toString(this.gram.get(i).charAt(0)),1);
flag_buff++;
}
flag_sing_empty=fse;
}
else if (b>='A'&&b<='Z') {
if(this.empty_map.get(Character.toString(b))==2){
flag_sing_empty=fse;
}
else if(this.empty_map.get(Character.toString(b))==1){
if(this.empty_map.get(Character.toString(this.gram.get(i).charAt(0)))==2){
this.empty_map.put(Character.toString(this.gram.get(i).charAt(0)),1);
flag_buff++;
}
flag_sing_empty = fse;
}
else if(this.empty_map.get(Character.toString(b))==0){
flag_sing_empty++;
i--;
}
}
else if(b=='#'){
if(this.empty_map.get(Character.toString(this.gram.get(i).charAt(0)))!=0){
this.empty_map.put(Character.toString(this.gram.get(i).charAt(0)),0);
flag_buff++;
}
flag_sing_empty = fse;
}
}
}
for (String key : empty_map.keySet()) {
if(empty_map.get(key)==2){
empty_map.put(key, 0);
}
}
}
public void find_first(){//找first集的方法
int flag=0,fg=1;
int nu=3;
char point;
for(int j=0;j<this.gram.size();j++){
flag=fg;
for(int i=0;i<this.gram.size();i++){
if(flag!=fg){
nu++;
point=this.gram.get(i).charAt(nu);
}
else {
nu=3;
point = this.gram.get(i).charAt(nu);
}
if(point>='a'&&point<='z'){
this.first_map.get(this.gram.get(i).charAt(0)).add(point);
flag=fg;
}
else if(point=='@'){
this.first_map.get(this.gram.get(i).charAt(0)).add('@');
}
else if(point>='A'&&point<='Z'){
this.first_map.get(this.gram.get(i).charAt(0)).addAll(this.first_map.get(point));
this.first_map.get(this.gram.get(i).charAt(0)).remove('@');
if(this.empty_map.get(Character.toString(point))==0){
flag++;
i--;
}
else {
flag=fg;
}
}
else if(point=='#'){
this.first_map.get(this.gram.get(i).charAt(0)).add('@');
flag=fg;
}
}
}
}
public void find_follow(){//找follow集的方法
int flag_buff=0,fb=1;
int number;
for(int z=0;z<this.gram.size();z++){//最外层的状态判断
for(int i=0;i<this.gram.size();i++){//单次循环,一次对每个产生式进行一次操作
for(int j=3;j<this.gram.get(i).length();j++){//产生式操作
char p = this.gram.get(i).charAt(j);
if(p>='A'&&p<='Z'){
number = j+1;
char ls;
while(true){
ls = this.gram.get(i).charAt(number);
if(ls>='a'&&ls<='z'){
this.follow_map.get(p).add(ls);
//flag_buff++;
break;
}
else if(ls>='A'&&ls<='Z'){
Set<Character> ls1 = this.first_map.get(ls);
ls1.remove('@');
this.follow_map.get(p).addAll(ls1);
//flag_buff++;
if(this.empty_map.get(Character.toString(ls))==0){
number++;
}
else {
break;
}
}
else if (ls=='#') {
this.follow_map.get(p).addAll(this.follow_map.get(this.gram.get(i).charAt(0)));
//flag_buff++;
break;
}
}
}
}
}
}
}
public void find_select(){//找select集的方法
int flag=1,fg=0;
int point=3;
char p;
for(int j=0;j<this.gram.size();j++){
flag=fg;
for(int i=0;i<this.gram.size();i++){
if(flag!=fg){
point++;
p = this.gram.get(i).charAt(point);
}
else{
point=3;
p = this.gram.get(i).charAt(point);
}
if(p>='a'&&p<='z'){
this.select_map.get(this.gram.get(i)).add(p);
flag=fg;
}
else if(p=='@'){
this.select_map.get(this.gram.get(i)).addAll(this.follow_map.get(this.gram.get(i).charAt(0)));
flag=fg;
}
else if(p>='A'&&p<='Z'){
this.select_map.get(this.gram.get(i)).addAll(this.first_map.get(p));
this.select_map.get(this.gram.get(i)).remove('@');
if(this.empty_map.get(Character.toString(p))==0){
//i--;
flag=fg;
}
else
flag=fg;
}
else if(p=='#'){
this.select_map.get(this.gram.get(i)).addAll(this.follow_map.get(this.gram.get(i).charAt(0)));
flag=fg;
}
}
}
}
public void get_it() {//预测表生成及预测分析
int a = this.end.size();
int b = this.unend.size();
for(int i=0;i<this.end.size();i++) {
System.out.print(this.end.get(i)+" ");
}
System.out.println("");
String[][] yuce = new String[b][a];
for(int i=0;i<this.unend.size();i++) {
for (String key : this.select_map.keySet()) {
if(key.charAt(0)==this.unend.get(i)) {
for(int j=0;j<this.end.size();j++) {
if(this.select_map.get(key).contains(this.end.get(j))) {
yuce[i][j] = key;
}
}
}
}
}
for(int i=0;i<b;i++) {
for(int j=0;j<a;j++) {
System.out.print(yuce[i][j]+" ");
}
System.out.println("");
}
//开始进行分析
System.out.println("请输入你要进行分析的句子");
String abc1 = sc.nextLine();//由于输入问题
String abc = sc.nextLine();
Stack<Character> fenxi = new Stack<Character>();
fenxi.push('#');
fenxi.push(this.gram.get(0).charAt(0));
int i=0;
char A = abc.charAt(i);
while(true) {
System.out.print(fenxi+" ");
System.out.println(abc.substring(i));
char X = fenxi.pop();//栈顶符号放入X
if(this.end.contains(X)) {//X在终结符里吗
if(X==A) {//X等于临时输入符
i++;
if(i==abc.length())
break;
A = abc.charAt(i);//读入下一符号,重复
}else {
System.out.print("cuo");
break;//否则出错
}
}//以上是在非终结符里的情况
else {
if (X=='#') {
if(X==A) {
System.out.print("END!");
break;
}
else {
System.out.print("cuo");
break;
}
}
else {
int h,l;
h = this.unend.indexOf(X);
l = this.end.indexOf(A);
String ls = yuce[h][l];
if(this.gram.contains(ls)) {//是一个产生式
for(int k=ls.length()-2;k>=3;k--) {
if(ls.charAt(k)!='@')
fenxi.push(ls.charAt(k));
}
}
else {
System.out.println("cuo");
break;
}
}
}
}
}
}
/*测试用例1
S->AB#
S->bC#
A->@#
A->b#
B->@#
B->aD#
C->AD#
C->b#
D->aS#
D->c#
测试用例2
E->TZ#
Z->aTZ#
Z->@#
T->FN#
N->bFN#
N->@#
F->i#
F->cEd#
*/