表达式计算器的设计与实现

一、             字符集定义

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,希望大家可以帮忙修改完善,如果觉得不错可以给个星)

时间: 2024-08-09 06:32:42

表达式计算器的设计与实现的相关文章

表达式计算器类的设计5(面向对象的表达式计算器8)

计算器的github下载地址:https://github.com/ljian1992/calculator 概述 表达式计算器的类基本已经设计完成了,由于在程序运行的时候总会有这样那样的异常,例如:a +2, a没有初始化,对于异常的管理一般而言是需要自定义异常类.这个自定义异常类也是在继承了系统已经定义好的exception类,然后再重新定义内容. 异常的种类 语法异常---->SyntaxError类 赋值时左操作数不是变量:1 = 2; 缺少括号:1 + (2*2 不认识的函数: 函数缺

表达式计算器类的设计4(面向对象的表达式计算器7)

概述 把符号表和变量表中的内容保存到一个文件中,通过IO文件流,来把符号表和变量表存储到文件中.在这之前需要弄明白什么是序列化和反序列化 对象的序列化 序列化:把对象转换为字节序列的过程 反序列化:把字节序列恢复为对象的过程 我们要把SymbolTable类的对象(符号表)和Storage类的对象(变量表)转换成字节序列保存到文件中,这时就可以设置Serializer类来完成这样的功能,同样的设置一个DeSerializer类来完成把保存到文件当中的字节序列恢复为对象的功能.这里要注意的是,所有

表达式计算器类的设计3(面向对象的表达式计算器6)

概述 有了构建语法的类,存储符号的类,现在就可以对表达式进行扫描,解析了.扫描可以抽象出一个Scanner类来完成这一个功能,而解析可以抽象出一个Parser类来完成这一个功能.这两个类存在一定的关系,扫描与解析的互动是这样子的:扫描到一个标识符,然后解析它是什么标识符.由于该表达式计算器是要支持一些命令的,命令的解析和表达式的解析过程完全不一样,所有呢,又要设置一个CommandParser类,来解析命令. Scanner类,Parser类,CommandParser类的设计 Scanner类

表达式计算器类的设计2(表达式计算器5)

计算器的github下载地址:https://github.com/ljian1992/calculator 符号表,函数表,变量存储表 表达式计算器,需要支持变量和函数,而变量和函数都是些符号,因此设置一个SymbolTable类来存储这些符号.符号有两种,一种是变量,一种是函数,故在设置一个Storage类存储变量中的值,设置一个FunctionTable类来存储函数.由于这三中类存在着联系,现在在设置一个Calc类来管理它们. SymbolTable类,FunctionTable类,Sto

表达式计算器类的设计1(表达式计算器4)

计算器的github下载地址:https://github.com/ljian1992/calculator 我们的最终目的是计算出表达式中的值,因此就需要定义一个抽象类用于计算表达式的值,该抽象类定义为:Node 下面所有的类图不使用UML建模语言画的,是通过visual studio自动生成的类关系图(自己用UML建模画的不小心被我删掉了) Node的类图 它继承了个Noncpyable类,由于我们是要做面向对象的表达式计算器,所以呢,通过一个小小的手段,把拷贝给禁止掉.这个小小的手段就是让

基于对象编程与面向对象编程(表达式计算器3)

基于对象编程与面向对象编程 我们的最终目的是用C++设计一个面向对象的表达式计算器,所以非常有必要弄清楚,什么是基于对象编程和面向对象的编程.而要弄清楚这一点,又要先弄明白什么是值语言,什么是对象语义 值语义:对象的拷贝与原对象无关,拷贝后与原对象脱离关系,互不影响.这种拷贝叫深拷贝.拷贝之后脱离关系,只要在拷贝的时候都为对象分配内存空间就行了.某种些情况下算是一种对资源的浪费 值语义例子 class Test { private: int * pNum_; public: Test(int n

【APP】表达式计算器 更新说明

下载链接(包括源代码):http://pan.baidu.com/s/1kTwrhcV 更新日志: 版本号:1.0.0.3 更新时间:2014/07/02 12:52 --修复了mv命令和rm命令的一些Bug 该Bug通常会导致出现不寻常的错误 --修复了赋值表达式中直接输入:=的错误 该Bug会导致程序崩溃 版本号:1.0.0.2 更新时间:2014/07/02 01:08 --修复了自定义变量名称的一些Bug 该Bug通常会导致不能正常处理变量名而出错 --修复了判断传入参数的消息映射系统的

Flex版本的基于栈的表达式计算器

/** * 表达式计算器,输入数学表达式的字符串,输出计算结果的数值 * 1.扫描表达式,将运算符与运算数分别入栈, * 2.运算符入栈前先与上一个运算符进行优先级比较,如果当前运算符优先级低于或等于前一个运算符, * 则将前一个运算符和对应的运算数出栈运算,否则运算符直接入栈 * @author lijy */ public class ExpressionCaculator { /** * 运算数栈 * */ private var numberStack:Array; /** * 运算符栈

VS2013 调试时出现“表达式计算器中发生内部错误”的问题解决办法

今天写代码的时候跟踪程序,发现打断点的地方根本看不到断点变量的结果,而且在快速监视中显示“ 表达式计算器中发生内部错误 ”,更看不到监视的变量了,上网找了半天也没找到答案,后来重新分析了一下自己的代码,发现是因为代码内部有死循环造成的,倒不是自己写的死循环,是有几个checkbox(我是在winform程序中)控件我添加了CheckedChanged事件方法,比如说这个事件方法我们暂且叫它FunctionA(“这个方法内部有设置类的枚举变量B的代码”),而我在Form_Load方法中又通过这个类