表達式計算器的設計與實現


一、             字符集定義

1.  <字符> → <數字>│<單界符>│.

2.  <數字> → 0│<非零數字>

3.  <非零數字>→ 1│2│…│9

4.  <單界符> →<運算符>│(│)

5.  <運算符> → +│-│*│/

二、             單詞集定義

6.<單詞> → <單界符>│<常數>

7.<常數> → <無符號整數>│<無符號浮點數>

8.<無符號整數> →0│<非零整數>

9.<非零整數> → <非零數字> <數字串>

10.<數字串> → <數字> <數字串>│NULL

11.<無符號浮點數> →<無符號整數>. <數字> <數字串>

三、             數據類型定義

12.<類型> → intdouble

四、             表達式定

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,希望大家可以幫忙修改完善,如果覺得不錯可以給個星)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM