1.算符优先的概念:
firstvt: 当A->a…或者A->Ba…. 的时候 将a属于Firstvt(A), 并且FirstVt(B)当中的元素也属于Firstvt(A),
lastvt:当A->…a或者A->….aB 的时候,则a属于lastvt(A) ,并且LastVt(B)当中的元素,也是属于LastVt(A)的。
对于A->…ac… 或者 …aBc… 的时候,a的优先级=c的优先级。
算符优先表是根据表达式来决定的,当遇到形如C->A+B ,由于匹配到A+,则,lastVt(A)的优先级 >(大于)+, 又匹配到+B, 则,+的优先级小于FirstVt(B)的所有的优先级。然后对于(E) ,则( = ),#E#(起始符之前添加),也是#的优先级也是等于#的 。
2. 话不多说,直接上代码:(复制粘贴即可使用)
主函数当中的调用,对于文法的表达如E->E+T 通过一个二维数组来表达的,表示为{“E”,“E+T”}
import java.util.*;
public class biaodashi {
public static void main(String[] args) {
Scanner cd=new Scanner(System.in);
Method method = new Method();
String[][] arr=new String[][]{{"E","E+T"},{"T","T*F"},{"T","F"},{"P","(E)"},{"P","i"},{"E","T"},
{"F","P^F"},{"F","P"}};
// String[][] arr=new String[][]{{"S","a"},{"S","@"},{"S","(T)"},{"T","T,S"},{"T","S"}};
// String[][] arr=new String[][]{{"E","E+E"},{"E","E*E"},{"E","i"}};
Map> firstVt = method.getFirstVt(arr);
System.out.println("======FirstVt========");
PrintUtil.printMap(firstVt);
Map> lastVt = method.getLastVt(arr);
System.out.println("======LastVt======");
PrintUtil.printMap(lastVt);
// 算符优先表
System.out.println("=======算符优先表=========");
Map> operator = method.getOperator(firstVt, lastVt, arr);
PrintUtil.printMap_Map(operator);
//设置一个根据右部推到左部的map,在最后的栈当中使用
Map toLeft = method.rightToLeft(arr);
Map map = method.getMap(arr);//初始化map
// System.out.println("=======righttoleft=====");
// System.out.println(toLeft);
// System.out.println("==========operator=======");
// System.out.println(map);
//对输入的式子判断是否合法
System.out.println("请输入你要进行验证的表达式:");
String line = cd.nextLine();
line=line+"#";
method.isTrue(line,operator,toLeft,map);
}
}
以下是对算符优先的主要的方法和函数:上述函数的调用都在底下的代码当中,如果大家有什么问题,可以给我留言。
也欢迎大家来纠正我的错误。
// 优先级表用Map>来表示 1 0 -1 class Method{ // 得到对应的firstvt public Map > getFirstVt(String[][] str) { Map > map=new HashMap<>(); // 进行循环,直到没有数据map没有发声改变 boolean flag=true; while(true) { if(!flag) break; //没有发声改变之后,退出循环 int sum=0; for(int i=0;i > map) { String key=str[0]; String value=str[1]; char[] valueChar = value.toCharArray(); boolean fg = false; if(!map.containsKey(key)) //没有这个key { HashSet set = new HashSet<>(); if(valueChar.length>0&&valueChar[0]>='A'&&valueChar[0]<='Z') //非终结符 { if(map.containsKey(valueChar[0]+"")) //已经有这个key的时候 { fg = set.addAll(map.get(valueChar[0] + "")); //当这个数组发生改变就是true,证明已经发生改变 if (valueChar.length > 2 && !(valueChar[1] >= 'A' && valueChar[1] <= 'Z')) { boolean add = set.add(valueChar[1] + ""); if (!fg) fg = add; } } } else //终结符 { fg = set.add(valueChar[0] + ""); } Set put = map.put(key, set); } else //包含这个key的时候 { Set set = map.get(key); if(valueChar.length>=1 &&valueChar[0]>='A'&&valueChar[0]<='Z') //非终结符 { if(map.containsKey(valueChar[0]+"")) //已经有这个key的时候 { fg = set.addAll(map.get(valueChar[0] + "")); //当这个数组发生改变就是true,证明已经发生改变 if (valueChar.length >= 2 && !(valueChar[1] >= 'A' && valueChar[1] <= 'Z')) { boolean add = set.add(valueChar[1] + ""); if (!fg) fg = add; } } } else //终结符 { fg = set.add(valueChar[0] + ""); } } return fg; } //计算lastvt集合 public static Map > getLastVt(String[][] str) { Map > map=new HashMap<>(); // 进行循环,直到没有数据map没有发声改变 boolean flag=true; while (true) { if(!flag) break; int num=0; for(int i=0;i > map) { String key=str[0]; String value=str[1]; char[] valueChar=value.toCharArray(); boolean fg=false; int length=valueChar.length; if(!map.containsKey(key)) { HashSet set = new HashSet<>(); if(valueChar.length>1) { if (valueChar[length - 1] >= 'A' && valueChar[length - 1] <= 'Z') { if (map.containsKey(valueChar[length - 1] + "")) { fg = set.addAll(map.get(valueChar[length-1] + "")); } if (valueChar.length >= 2 && !(valueChar[length - 2] >= 'A' && valueChar[length - 2] <= 'Z')) { boolean add = set.add(valueChar[length - 2] + ""); if (!fg) fg = add; } } else { //最后一个位小写 fg = set.add(valueChar[valueChar.length - 1] + ""); } } map.put(key,set); } else //当map当中包含这个key的时候 { Set set = map.get(key); if(valueChar.length>=1&&valueChar[length-1]>='A'&&valueChar[length-1]<='Z') { if(map.containsKey(valueChar[length-1]+"")) { fg = set.addAll(map.get(valueChar[0] + "")); } if(valueChar.length>=2&&!(valueChar[length-2]>='A'&&valueChar[length-2]<='Z')) { boolean add = set.add(valueChar[length-2] + ""); if(!fg) fg=add; } } else{ //最后一个位小写 fg = set.add(valueChar[valueChar.length - 1] + ""); } } return fg; } public Map > getOperator(Map > firstVt ,Map > lastVt,String[][] str) { String[][] add = new String[str.length+1][2]; for(int i=0;i > operator1 = getOperator1(firstVt, lastVt, add); return operator1; } // 算符优先表 0表示优先级相同,1表示前面大于后面 -1表示后面大于前面 public Map > getOperator1(Map > firstVt ,Map > lastVt,String[][] str) { Map > map=new HashMap<>(); // 遍历每一个右部,将数据添加进去 for(int i=0;i stringIntegerMap = map.get(valueChar[j] + ""); // if(stringIntegerMap.containsKey(valueChar[j+1]+"")) throw new RuntimeException("语法有错误,有冲突项,具有二义性"); stringIntegerMap.put(valueChar[j+1]+"",0); } else { HashMap map1 = new HashMap<>(); map1.put(valueChar[j + 1] + "", 0); map.put(valueChar[j] + "", map1); } } if(!isTerminal(valueChar[j])&&isTerminal(valueChar[j+1])) //前一个是非终结符,后一个是终结符,将前一个的lastvt》后一个的终结符 { String ch=valueChar[j]+""; if(lastVt.containsKey(ch)){ Set set = lastVt.get(ch); if(!set.isEmpty()) { Iterator iterator = set.iterator(); while (iterator.hasNext()) { String next = iterator.next(); //HashMap stringIntegerHashMap = new HashMap<>(); //stringIntegerHashMap.put(valueChar[j + 1] + "", 1); if(map.containsKey(next)) { Map map1 = map.get(next); if(map1.containsKey(valueChar[j+1]+"")) throw new RuntimeException("语法有错误,有冲突项,具有二义性"); map1.put(valueChar[j + 1] + "", 1); } else { HashMap map1 = new HashMap<>(); map1.put(valueChar[j+1]+"",1); map.put(next,map1); } } } } } if(isTerminal(valueChar[j])&&!isTerminal(valueChar[j+1])) //前一个是终结符,后一个是非终结符 《 { String ch=valueChar[j+1]+""; if(firstVt.containsKey(ch)) { Set set = firstVt.get(ch); // if((valueChar[j]+"").equals("+")) // { // System.out.println(ch+" set的结果:"+set); // } if (!set.isEmpty()) { Iterator iterator = set.iterator(); while (iterator.hasNext()) { String next = iterator.next(); if(map.containsKey(valueChar[j]+"")) { Map map1 = map.get(valueChar[j] + ""); if(map1.containsKey(valueChar[j+1]+"")) throw new RuntimeException("语法有错误,有冲突项,具有二义性"); map1.put(next,-1); } else { HashMap map1 = new HashMap<>(); map1.put(next, -1); map.put(valueChar[j] + "", map1); } } } } } } for(int j=0;j<=length-3;j++) //长度为三的时候 { if(isTerminal(valueChar[j])&&!isTerminal(valueChar[j+1])&&isTerminal(valueChar[j+2])) //中间是非终结符,两边是终结符 { if(map.containsKey(valueChar[j]+"")) { Map map1 = map.get(valueChar[j] + ""); if(map1.containsKey(valueChar[j+1]+"")) throw new RuntimeException("语法有错误,有冲突项,具有二义性"); map1.put(valueChar[j+2]+"",0); }else{ HashMap map1 = new HashMap<>(); map1.put(valueChar[j+2]+"",0); map.put(valueChar[0]+"",map1); } } } } return map; } // 判断是不是终结符 private boolean isTerminal(char ch) { if(ch>='A'&&ch<='Z') return false; return true; } //从右向左推导 public Map rightToLeft(String[][] arr) { Map map =new HashMap<>(); for(int i=0;i0) map.put(str,arr[i][0]); } return map; } private String reverse(String str) { StringBuilder bd=new StringBuilder(str); StringBuilder reverse = bd.reverse(); return reverse.toString(); } public Map getMap(String[][] arr) { Map map=new HashMap<>(); for(int i=0;i0) return s; else return null; } // 判断是不是合法的表达式: public void isTrue(String line,Map > operatorMap,Map rightToLeft, Map noOPerator) { Stack stack=new Stack<>(); //存储对应的元素 Stack operatorStack=new Stack<>(); //保存距离顶部的终结符 stack.push("#"); operatorStack.push("#"); line=line.trim(); //int idnex=0; //索引,指向对应的位置 for(int i=0;i ='A'&&sub<='Z') //如果是非终结符,直接加入到栈当中 { stack.push(sub+""); operatorStack.push(operatorStack.peek()); System.out.println(stack); } else //当前输入是终结符的时候 { Integer in = operatorMap.get(operatorStack.peek()).get(sub + ""); // System.out.println(operatorStack.peek()+" "+sub+" "+in); if(in==0){ stack.push(sub+""); operatorStack.push(sub+""); System.out.println(stack); } else if(in==1) //左边的运算符的优先级高于右边 { StringBuilder bd=new StringBuilder(); String pop; while (true) //找到第一个终结符 { pop = stack.pop(); operatorStack.pop(); bd.append(pop); if(isTerminal(pop.toCharArray()[0])) break; } a:while (true) { String peek = stack.peek(); if(peek.toCharArray()[0]>='A'&&peek.toCharArray()[0]<='Z') //非结符 { bd.append(stack.pop()); operatorStack.pop(); } else //终结符 { Integer integer = operatorMap.get(stack.peek()).get(pop); if(integer==0) { bd.append(stack.pop()); operatorStack.pop(); continue ; } else { break a; } } } String s = bd.toString(); s=reverse(s); String s1; s1 = rightToLeft.get(getOperator(s)); stack.push(s1); operatorStack.push(operatorStack.peek()); System.out.println(stack); i--; } else ///in==-1 { stack.push(sub+""); operatorStack.push(sub+""); System.out.println(stack); } } } } }
最终结果:
算符优先表的表示方法为一个Map
最后,值得注意的是,算符优先的计算和非终结符无关。



