一、 字符集定義
1. <字符> → <數字>│<單界符>│.
2. <數字> → 0│<非零數字>
3. <非零數字>→ 1│2│…│9
4. <單界符> →<運算符>│(│)
5. <運算符> → +│-│*│/
二、 單詞集定義
6.<單詞> → <單界符>│<常數>
7.<常數> → <無符號整數>│<無符號浮點數>
8.<無符號整數> →0│<非零整數>
9.<非零整數> → <非零數字> <數字串>
10.<數字串> → <數字> <數字串>│NULL
11.<無符號浮點數> →<無符號整數>. <數字> <數字串>
三、 數據類型定義
12.<類型> → int│double
四、 表達式定
13.<算術表達式> → <項> + <算術表達式>│<項> - <算術表達式>│<項>
14.<項> → <因子> * <項>│<因子> / <項>│<因子>
15.<因子> → <算數量>│- <因子>
16.<算術量> → <常數>│( <算術表達式> )
E T E E T T
<算術表達式> → <項> + <算術表達式>│<算術表達式>-<項>│<項>
T F T F T F
<項> → <因子> * <項>│<因子> / <項>│<因子>
F i F
<因子> → <常數>│- <因子>
核心代碼:
(詞法分析類Build.java)
1 package util; 2 3 4 5 6 public class Build { 7 //下標 8 private int i; 9 10 //存儲讀取的字符 11 private char ch; 12 13 //將輸入自符串轉為字符數組 14 private char[] input_array; 15 16 //截取存儲字符串 17 private String s; 18 //記錄上一次運算符出現的位置 19 private int lastSingle; 20 private String input; 21 public Build(String input){ 22 this.input_array = input.toCharArray(); 23 this.input=input; 24 ch=input_array[0]; 25 this.i=0; 26 this.lastSingle=-1; 27 } 28 29 30 31 //詞法分析函數 32 public int getsym(){ 33 34 35 36 //i=0時,首字符為小數點,+,-,*,/拋出錯誤 37 if(BuildUtils.throwFirstSigleError(ch)){ 38 //將此次非法標識符出現的位置存儲到lastSingle 39 lastSingle=0; 40 i++; 41 } 42 43 44 while(i<input.length()){//外層循環用於判斷是何種別的單詞 45 46 ch=input_array[i]; 47 while(ch==' '||ch==10||ch==13||ch==9){//換行,空格,回車和tab 48 49 ch=input_array[i++];//取下一個字符到ch 50 51 } 52 53 if(ch>='0'&&ch<='9'){ //檢測是否為數字,如果為數字測需要分段存儲數字串 54 if(ch=='0'){//如果為0 55 i++; 56 if(i<input.length()) ch=input_array[i];//取下一個字符到ch 57 else{ 58 BuildUtils.getEndSingle(input, lastSingle, i);break; 59 } 60 if(ch=='.'){//為小數點 61 i++; 62 if(i<input.length()) ch=input_array[i]; 63 else{ 64 BuildUtils.getEndSingle(input, lastSingle, i);break; 65 }//取下一個字符到ch 66 if(ch>='0'&&ch<='9'){//取下一個字符到ch//小數點后面的數字 67 i++; 68 if(i<input.length()) ch=input_array[i]; 69 else{ 70 BuildUtils.getEndSingle(input, lastSingle, i);break; 71 }//取下一個字符到ch//小數點后面的后面 72 if(ch>='0'&&ch<='9'){ 73 while(ch>='0'&&ch<='9') { 74 i++; 75 if(i<input.length()) ch=input_array[i]; 76 else{ 77 BuildUtils.getEndSingle(input, lastSingle, i);break; 78 } 79 80 }//當1-9后面字符為0-9時自動機一直空轉循環 81 82 }else{ 83 continue;//提前返回至for循環,判斷下次輸入(最后轉至終態) 84 } 85 86 87 }else{//在小數點后面出現了非法字符 88 System.out.println("ERROR:\n小數點后出現了字符"+String.valueOf(ch)); 89 Analyze.lastAnayScuccess=false; 90 lastSingle=i; 91 continue; 92 } 93 }else{//不為小數點 94 continue; 95 } 96 97 98 99 }else{//如果為1-9 100 i++; 101 if(i<input.length()) ch=input_array[i];//取下一個字符到ch//1-9的下一個字符 102 else{ 103 BuildUtils.getEndSingle(input, lastSingle+1, i);break; 104 } 105 if(ch>='0'&&ch<='9'){ 106 while(ch>='0'&&ch<='9') { 107 i++; 108 if(i<input.length()) ch=input_array[i]; 109 else { 110 if(lastSingle==-1) {BuildUtils.getEndSingle(input, 0, i); break;} 111 else 112 {BuildUtils.getEndSingle(input, lastSingle, i); break;} 113 } 114 }//當1-9后面字符為0-9時自動機一直空轉循環 115 116 117 118 }else if(ch=='.'){ 119 i++; 120 if(i<input.length()) ch=input_array[i];//取下一個字符到ch 121 if(ch>='0'&&ch<='9'){//取下一個字符到ch//小數點后面的數字 122 123 i++; 124 if(i<input.length())ch=input_array[i];//取下一個字符到ch//小數點后面的后面 125 else{ 126 BuildUtils.getEndSingle(input, lastSingle, i); break; 127 } 128 129 if(ch>='0'&&ch<='9'){ 130 while(ch>='0'&&ch<='9') { 131 i++; 132 if(i<input.length()) ch=input_array[i]; 133 else{ 134 BuildUtils.getEndSingle(input, lastSingle, i); break; 135 } 136 }//當1-9后面字符為0-9時自動機一直空轉循環 137 }else{ 138 continue;//提前返回至for循環,判斷下次輸入(最后轉至終態) 139 } 140 141 142 }else{//在小數點后面出現了非法字符 143 System.out.println("ERROR:\n小數點后出現了字符"+String.valueOf(ch)); 144 Analyze.lastAnayScuccess=false; 145 lastSingle=i; 146 i++; 147 continue; 148 } 149 150 }else{ 151 continue;//提前返回至外層循環,判斷此次輸入(最后轉至終態) 152 } 153 154 155 156 } 157 158 159 160 161 }else if(ch=='.'){ 162 i++; 163 if(i<input.length()) ch=input_array[i];//取下一個字符到ch 164 if(ch>='0'&&ch<='9'){//取下一個字符到ch//小數點后面的數字 165 166 i++; 167 if(i<input.length())ch=input_array[i];//取下一個字符到ch//小數點后面的后面 168 else{ 169 BuildUtils.getEndSingle(input, lastSingle, i); break; 170 } 171 172 if(ch>='0'&&ch<='9'){ 173 while(ch>='0'&&ch<='9') { 174 i++; 175 if(i<input.length()) ch=input_array[i]; 176 else{ 177 BuildUtils.getEndSingle(input, lastSingle, i); break; 178 } 179 }//當1-9后面字符為0-9時自動機一直空轉循環 180 }else{ 181 continue;//提前返回至for循環,判斷下次輸入(最后轉至終態) 182 } 183 184 185 }else{//在小數點后面出現了非法字符 186 System.out.println("ERROR:\n小數點后出現了字符"+String.valueOf(ch)); 187 Analyze.lastAnayScuccess=false; 188 lastSingle=i; 189 i++; 190 continue; 191 } 192 193 } 194 195 196 197 198 199 200 201 else{//不是數字 202 203 //取下的為運算符 204 if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='('||ch==')'){ 205 if(i!=0){ 206 207 if(lastSingle==-1) s=input.substring(0, i); 208 else s=input.substring(lastSingle+1, i); 209 //將此次運算符出現的位置存儲到lastSingle 210 lastSingle=i; 211 if(!s.isEmpty()){ 212 BuildUtils.parsertoIntOrDouble(s); 213 } 214 215 BuildUtils.parsertoSingle(ch); 216 i++; 217 continue;//繼續判斷下一字符 218 }else{ 219 BuildUtils.parsertoSingle(ch); 220 lastSingle=i; 221 i++; 222 continue;//繼續判斷下一字符 223 } 224 }else{//否則出錯,但需要同時記錄出錯字符的位置以便獲取數字串 225 226 //將此次非法標識符出現的位置存儲到lastSingle 227 lastSingle=i; 228 //在任何位置出現了非法字符 229 System.out.println("ERROR:\n出現非法標識符"+String.valueOf(ch)); 230 i++; 231 continue; 232 233 234 } 235 236 237 238 239 240 } 241 242 243 } 244 245 return 0; 246 247 } 248 249 250 }
(語法法分析類:Analyze.java)
package util; import java.util.ArrayList; import bean.Node; public class Analyze { private Node particularNode=new Node(null, "#", null, null); private ArrayList<Node> inputStack=new ArrayList<Node>();//輸入串 private ArrayList<Node> inputQueue=new ArrayList<Node>();//輸入棧 private ArrayList<Node> singleQueue=new ArrayList<Node>();//符號棧 private ArrayList<Integer> analyzeQueue=new ArrayList<Integer>();//分析棧(狀態棧) private static Analyze analyze=null; private int statuSum=16;//該文法涉及了16個狀態 private int Action=8;//8個動作 private int Turn=3;//3個轉移 public static boolean lastAnayScuccess=true; int act = 0 ;//動作 int turn=0;//轉移 int status=0;//初始狀態 int actionIndex=-1; int turnIndex=-1; int index;//輸入串的字符下標 int SUCCESS=0; int FAILE=1; int sindex; int aindex; Node reduceNode = null;//規約后壓入符號棧的單詞結點 private Analyze(){ this.inputQueue.add(particularNode);//輸入串在進行語法分析前要先將結束符壓入棧底 this.singleQueue.add(particularNode);//符號棧初始狀態下為# this.analyzeQueue.add(0); //result = new StringBuilder(); } public static Analyze getAnalyze(){ if(analyze==null){ analyze=new Analyze(); } return analyze; } public void addNode(Node node){//初始化輸入串 inputStack.add(node); } public void shiftNode(Node node){//將待匹配的node移進符號棧 singleQueue.add(node); } public void addNodeToSQ(Integer Istatus){//狀態棧添加狀態 analyzeQueue.add(Istatus); } public int divceProgram(){//驅動程序 exchange(inputStack, inputQueue); index=inputQueue.size()-1; int ti=1;//t1,t2,t3... if(lastAnayScuccess){//在上一步詞法分析沒有出錯的情況下往下進行語法分析 System.out.println("開始進行語法分析"); while(true){ //從輸入串的首單詞開始判斷是否移入符號棧 //該單詞節點執行的狀態跳轉 while(turnIndex<Turn){ if(index>=0){ for(int j=0;j<Turn;j++){ if(inputQueue.get(index).getKey().equals(ParserType.vn[j].getSingle())){ turnIndex=j; break; } } } if(turnIndex!=-1){ turn=ParserType.go[status][turnIndex];//true是goto表中的元素值 if(turn>0){ status=turn;//狀態跳轉到goto表true所對應的值 turnIndex=-1; index--;//跳轉到turn步驟之后匹配下一個輸入單詞 System.out.println("輸入串剩余長度"+index); break; }else{//等於0時出錯 ProcError(); return FAILE; } }else { break; } } //該單詞節點執行的動作 while(actionIndex<Action){ if(index>0){ for(int i=1;i<Action;i++){ if(inputQueue.get(index).getKey().equals(ParserType.vt[i].getSingle())){ actionIndex=i; break; } } if(inputQueue.get(index).getBeanTpye().equals("int")||inputQueue.get(index).getBeanTpye().equals("double")){ actionIndex=0; } } if(index==0){ actionIndex=7; } if(actionIndex!=-1){ System.out.println("狀態"+status); System.out.println("動作下標"+actionIndex); act=ParserType.action[status][actionIndex];//動作 if (act == ParserType.BLANK) { ProcError(); System.out.println("語法錯誤"); return FAILE; }else if(act==ParserType.ACC){ System.out.println("該輸入串符合語法要求並已被接收"); System.out.println("計算結果:"+singleQueue.get(1).getValue()); return SUCCESS; }else if(act>0){//進行移進操作,然后轉向狀態act //移進操作,將待分析的單詞壓入符號棧 singleQueue.add(inputQueue.get(index)); analyzeQueue.add(act); System.out.println(inputQueue.get(index)+"加入符號棧"); System.out.println(act+"加入狀態棧"); System.out.println("符號棧:"+singleQueue.toString()); System.out.println("狀態棧:"+analyzeQueue.toString()); status=act; actionIndex=-1; index--; continue; }else{//進行規約操作 //此時act值小於0,取絕對值之后即為規約所用的文法產生式序號Math.abs(act); for(P p:ParserType.pset){//尋找產生式 if(p.getNum()== Math.abs(act)){ int noZeroNum=0; aindex=analyzeQueue.size()-1; sindex=singleQueue.size()-1; ArrayList<Node> reduceNodeList=new ArrayList<Node>();//規約中間結果存儲列表 // ArrayList<Node> saveNodeList=new ArrayList<Node>();//規約中間變量存儲列表 StringBuilder result=new StringBuilder(); for(int i=0;i<p.getRigthExp().length;i++){ if(!p.getRigthExp()[i].toString().equals("0")){ noZeroNum++; } } while(noZeroNum>0){ //存儲需要規約的單詞 reduceNodeList.add(singleQueue.get(sindex)); System.out.println(singleQueue.get(sindex)+"被規約"); //狀態棧和符號棧要移除的結點 singleQueue.remove(singleQueue.get(sindex)); if(sindex>0) sindex--; analyzeQueue.remove(analyzeQueue.get(aindex));//符號棧和狀態的操作需同步 if (aindex>0) aindex--; noZeroNum--; } V ch=p.getLeftV();//獲取規約后的單詞, int leftVindex=0; //找到在goto表對應的turnIndex值 for(V v:ParserType.vn){ if(!v.equals(ch)){ leftVindex++; }else break; } for(String str:p.getRigthExp()){ result.append(str); } String rigthExp=result.toString(); System.out.println("rigthExp:"+rigthExp); if(rigthExp.contains("+")||rigthExp.contains("-")||rigthExp.contains("*")||rigthExp.contains("/")){ //規約后的單詞四元式 Node saveNode=new Node(p.getRigthExp()[1].toString(),reduceNodeList.get(2).getValue().toString(), reduceNodeList.get(0).getValue().toString(),"t"+(ti++)); // saveNodeList.add(saveNode); //輸出中間四元式 System.out.println(saveNode.toString()); //將單詞串轉換成真實的字符運算並用reduceNode存儲中間結果 switch(p.getRigthExp()[1].toString()){ case "+": reduceNode=ReduceTools.reduceByAdd(reduceNodeList, p);break; case "-": reduceNode=ReduceTools.reduceByJian(reduceNodeList, p); break; case "*": reduceNode=ReduceTools.reduceByCheng(reduceNodeList, p);break; case "/": reduceNode=ReduceTools.reduceByChu(reduceNodeList, p); break; default: break; } }else if(rigthExp.contains("i")){ reduceNode=ReduceTools.reduceFromi(reduceNodeList, p); }else if(rigthExp.contains("(")&&rigthExp.contains(")")){ reduceNode=ReduceTools.reduceByKuoHao(reduceNodeList, p); }/*else if(rigthExp.contains("-F")){//F->-F reduceNode=ReduceTools.reduceByFu(reduceNodeList, p); }*/else{//T->F//E->T//S->E reduceNode=ReduceTools.reduceFromOther(reduceNodeList, p); } singleQueue.add(reduceNode);//規約之后將中間結果壓入符號棧 sindex++; status=ParserType.go[analyzeQueue.get(aindex)][leftVindex]; analyzeQueue.add(status);//向狀態棧添加規約后的狀態 aindex++; System.out.println(singleQueue.get(sindex)+"加入符號棧"); System.out.println(analyzeQueue.get(aindex)+"加入狀態棧"); System.out.println("符號棧:"+singleQueue.toString()); System.out.println("狀態棧:"+analyzeQueue.toString()); actionIndex=-1; break; } } //規約階段涉及goto操作 } }else{ break; } } } }else{ WorldError(); } return 0; } private void ProcError() { // TODO Auto-generated method stub System.out.println("語法錯誤"); } private void WorldError() { // TODO Auto-generated method stub System.out.println("存在詞法錯誤,無法進行語法分析"); } //棧數據倒灌 public void exchange(ArrayList<Node> list1,ArrayList<Node> list2){ for(int i=list1.size()-1;i>=0;i--){ list2.add(list1.get(i)); } } }
具體源碼見我的GitHub https://github.com/kingxiusam/PLTest
(注意:由於能力有限,源碼有一些bug,希望大家可以幫忙修改完善,如果覺得不錯可以給個星)