您的位置:首页 > 其它

编译作业——LL(1)文法的语法分析器

2016-11-17 14:40 579 查看
又一次的编译上机作业,做了些修改和注释,放到博客上来

注意:

以下代码的分析表是写死了的,所以仅仅只能针对文法:

E->TE'(1)
T->FT'(2)
E'->+TE'|e (3)
T'->*FT'|e (4)
F->(E)|id (5)
e代表空串


代码可能还有漏洞,使用还请通读

package SecondHW;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

public class SecondHw {
static String E="E",Ee="E'",T="T",Tt="T'",F="F",//代表各种非终结符
e="e",//表示空串
synch="synch",//同步记号,用于标记错误
id="id";//一个终结符
static Set<String> unLimitedSign=new HashSet<String>();
static{//初始化 非终结符的集合
unLimitedSign.add(E);
unLimitedSign.add(Ee);
unLimitedSign.add(T);
unLimitedSign.add(Tt);
unLimitedSign.add(F);
}
//创建分析预测表
public static Map<String,Map<String,List<String>>> staticTable(){
Map<String,Map<String,List<String>>> table=new HashMap<String, Map<String,List<String>>>();
Map<String,List<String>> tempMap=new HashMap<String, List<String>>();
List<String> tempList=null;
//表的第一行
//第一个、第二个
tempList=fullList(new String[]{T,Ee});
tempMap.put(id, tempList);//加入id列
tempMap.put("(",tempList);//加入(列
tempList=fullList(new String[]{synch});
tempMap.put(")",tempList);
tempMap.put("$",tempList);
table.put(E,tempMap);//加到E行
//表的第二行
tempMap=new HashMap<String, List<String>>();
tempList=fullList(new String[]{"+",T,Ee});
tempMap.put("+", tempList);
tempList=fullList(new String[]{e});
tempMap.put(")",tempList);
tempMap.put("$",tempList);
table.put(Ee,tempMap);
//第三行
tempMap=new HashMap<String, List<String>>();
tempList=fullList(new String[]{F,Tt});
tempMap.put(id,tempList);
tempMap.put("(",tempList);
tempList=fullList(new String[]{synch});
tempMap.put(")",tempList);
tempMap.put("$",tempList);
tempMap.put("+", tempList);
table.put(T,tempMap);
//第四行
tempMap=new HashMap<String, List<String>>();
tempList=fullList(new String[]{e});
tempMap.put("+", tempList);
tempMap.put(")",tempList);
tempMap.put("$",tempList);
tempList=fullList(new String[]{"*",F,Tt});
tempMap.put("*",tempList);
table.put(Tt,tempMap);
//第五行
tempMap=new HashMap<String, List<String>>();
tempList=fullList(new String[]{"id"});
tempMap.put(id,tempList);
tempList=fullList(new String[]{"(",E,")"});
tempMap.put("(",tempList);
tempList=fullList(new String[]{synch});
tempMap.put(")",tempList);
tempMap.put("$",tempList);
tempMap.put("+", tempList);
tempMap.put("*", tempList);
table.put(F,tempMap);
return table;
}
//废弃方法 本来是想实现Map的级联put,简化staticTable,发现不可能,如果要写需要创建新类覆盖Map方法或者包装Map
private static Map<String,List<String>> fullMap(String key,List<String> value){
Map<String,List<String>> temp=new HashMap<String, List<String>>();
temp.put(key,value);
return temp;
}
/**
* 传入一个数组,填充成一个List
* @param String []args
* @return List<String>
*/
private static List<String> fullList(String[] args){
List<String> temp=new ArrayList<String>();
for(String s: args){
temp.add(s);
}
return temp;
}
public static void main(String[] args){
Map<String,Map<String,List<String>>> analysisTable=staticTable();
LinkedList<String> stack=new LinkedList<String>();
stack.addFirst("$");
stack.addFirst(E);
/*
Scanner sc=new Scanner(System.in);
System.out.println("输入一个记号流的串,注意每个终结符需要以空格隔开 ");
String[] test=sc.nextLine().split(" ");
sc.close();
*/
//输入记号流
//三个测试用例
//String[] test=new String[]{id,"*",id,"+",id,"$"};
//String[] test=new String[]{id,"*",id,"+",")",id,"$"};
String[] test=new String[]{id,"*","+",")",id,"$"};
List<String> temp=new ArrayList<String>();
int point=0;
while((!stack.getFirst().equals("$")||stack.isEmpty())&&point<test.length){//循环终止的情况+出错的情况(栈空、输入记号流指针到头了)
if(stack.getFirst().equals(e)){//检测空串
stack.removeFirst();
System.out.println("弹出空串 ,栈内元素:"+stack);
}else if(stack.getFirst().equals(test[point])){//终结符匹配,弹出 且point++
System.out.println("匹配弹出"+stack.removeFirst()+" ,栈内元素:"+stack);
point++;
printString(test,point);
}else if(!unLimitedSign.contains(stack.getFirst())){//如果是终结符,且没有在上一步处理,说明出错
//对于右括号的特殊处理
//针对记号流中只有左括号,没有右括号的情况,将栈中右括号弹出
if(stack.getFirst().equals(")")){
System.out.println("出错1,没有匹配的括号,指出错误位置并略过");
error(test,point);
stack.removeFirst();
}else{
System.out.println("出错2,不能识别的终结符,略过这一个输入记号:"+test[point]);
error(test,point);
point++;
}
continue;
}else{//对非终结符进行推导+入栈
temp=analysisTable.get(stack.getFirst()).get(test[point]);
if(temp==null){//取得分析预测表对应记录,如果得到的是空集,代表出错了
System.out.println("出错3,没有匹配的产生式,略过这一个输入记号: "+test[point]);
error(test,point);
point++;
continue;
}
//处理匹配错误,这里比书上多加了对右括号的特殊处理
//针对输入记号流只有右括号的情况,略过右括号
//如果不将右括号单独处理,遇到右括号的同步记号,极有可能输入记号流经过若干次到e的推导,直接识别结束
else if(temp.get(0).equals("synch")){
if(test[point].equals(")")){
System.out.println("出错4,不匹配的),略过终结符:)");
error(test,point);
point++;
}else{
System.out.println("出错5,不能识别的终结符,弹出栈顶:"+stack.removeFirst());
error(test,point);
}
}else{
stack.removeFirst();
for(int i=temp.size()-1;i>=0;i--){
stack.addFirst(temp.get(i));
}
System.out.println("产生式推导,新栈内 :"+stack);
}
}
}
//这是记号流没识别完
if(point<test.length-1){
System.out.println("记号流输入有误,此后串不再识别");
error(test,point);
}
//这是栈没弹完
if(!stack.getFirst().equals("$")){
System.out.println("记号流输入有误,栈中还剩元素");
System.out.println(stack);
}
System.out.println("记号流已经识别完毕");
}
/**
* 用于从指定位置输出一个数组的一部分
* @param args 要输出的数组
* @param index 指定的输出起点
*/
public static void printString(String[] args,int index){
System.out.print("串中还剩:");
for(int i=index;i<args.length;i++){
System.out.print(args[i]);
}
System.out.println();
}
/**
* 用于展示输入记号流的出错位置
* @param args 输入的记号流,终结符的数组
* @param index 出错的位置
*/
public static void error(String[] args,int index){
for(int i=0;i<args.length;i++){
System.out.print(args[i]+"\t");
}
System.out.println();
for(int i=0;i<args.length;i++){
if(i==index){
System.out.print("↑这里有错");
}else System.out.print("\t");
}
System.out.println();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: