【应用】浮点数四则运算器 Part3:运算模块的编写

已知:后缀表达式已经按规则排在一个栈中。

计算后缀表达式的过程主要按下面的思路进行:

1.保存数据的栈为fx1,创建一个新的栈ans;

2.每次读取时,若fx1不空:

1)若为数据,直接入栈。

2)若为操作符:

    (1)若不为'/':读取ans栈顶两次,取出数据运算后放回栈中。

    (2)若为'/':读取ans栈顶一次,若为0,输出error code 10:'0' under '/',否则取出数据运算后放回栈中。

3.输出ans的栈顶元素。

注意!若ans的元素个数不为1,则出现了问题,输出extra code 11:BUG SHOWED!DAMN!!!

还可以以1000倍为精度判断输出的数是否为浮点数后再输出。

 1 stack<double> ans;
 2 
 3 void Out(double i){
 4     double a;
 5     int a0,a1;
 6     a=i;
 7     a0=1000*a;
 8     if (a0%1000==0){
 9         a1=a;
10         printf("out>>%d\n",a1);
11     }
12     else{
13         printf("out>>%.2lf\n",a);
14     }
15 }

下面是代码实现。

 1 void cal(){
 2     Error=0;
 3     if (ans.empty()==0){
 4         ans.pop();
 5     }
 6     double a=0.0,b=0.0;
 7     char tmp[300];
 8     while (fx1.empty()==0){
 9         if (fx1.top()=="+"||
10             fx1.top()=="-"||
11             fx1.top()=="*"){
12             a=ans.top();
13             ans.pop();
14             b=ans.top();
15             ans.pop();
16             if (fx1.top()=="+"){ans.push(b+a);}
17             if (fx1.top()=="-"){ans.push(b-a);}
18             if (fx1.top()=="*"){ans.push(b*a);}
19             fx1.pop();
20             continue;
21         }
22         if (fx1.top()=="/"){
23             if (ans.top()==0){
24                 Error=1;
25                 printf("out>>error code 10: '0' under '/'\n");
26                 return ;
27             }
28             a=ans.top();
29             ans.pop();
30             b=ans.top();
31             ans.pop();
32             ans.push(b/a);
33             fx1.pop();
34             continue;
35         }
36         for (int i=0;i<300;i++){
37             tmp[i]=0;
38         }
39         strcpy(tmp,fx1.top().c_str());
40         ans.push(atof(tmp));
41         fx1.pop();
42     }
43     if (ans.size()!=1){
44         printf("out>>error code 11: BUG SHOWED!DAMN!!!\n");
45     }
46     else{
47         Out(ans.top());
48         ans.pop();
49     }
50 }

将之前三篇文章中的模块拼合在一起就可以得到完整的程序了。

但是还需要对程序的使用者提供一定的帮助,因此有了下面的指导模块:

 1 void guide(){
 2     printf("浮点数四则运算器:\n");
 3     printf("每输入一个数据或操作符,你需要使用一个空格来表示输入完成。\n");
 4     printf("输入完成一行表达式后,输入回车来表示输入结束。\n");
 5     printf("若输入了错误的表达式,请参照程序的报错类型修正表达式。\n");
 6     printf("你可以为多个变量或单个变量赋值,下面是一个事例:\n");
 7     printf("in>>x y = 3.1\n");
 8     printf("out>>3.1\n");
 9     printf("in>>( x + y ) * -3\n");
10     printf("out>>-18.60\n");
11     printf("保留两位小数。");
12     printf("输入exit可以退出程序。\n");
13     printf("===============================================\n");
14 }

完整的程序折叠在下方。

  1 #include<iostream>
  2 #include<stdio.h>
  3 #include<stdlib.h>
  4 #include<algorithm>
  5 #include<map>
  6 #include<stack>
  7 #include<queue>
  8 
  9 using namespace std;
 10 
 11 string dat;
 12 string all[100];
 13 map<string,string> cnt;
 14 map<string,string>::iterator iter;
 15 int flag=0;
 16 int x=0;
 17 
 18 void Getdata(){
 19     x=0;
 20     flag=0;
 21     dat="";
 22     for (int i=0;i<100;i++){
 23         all[i]="";
 24     }
 25     int code=0;
 26     char a=0;
 27     cout<<"in>>";
 28     while (1){
 29         a=getchar();
 30         if (a=='('){
 31             code++;
 32         }
 33         if (a==')'){
 34             code--;
 35         }
 36         if (code<0){
 37             flag=1;
 38         }
 39         if (a==' '){
 40             all[x]=dat;
 41             x++;
 42             dat="";
 43             continue;
 44         }
 45         if (a=='\n'){
 46             all[x]=dat;
 47             dat="";
 48             if (flag==3){
 49                 for (int i=0;i<x;i++){
 50                     cnt[all[i]]=all[x];
 51                 }
 52             }
 53             if (all[x]=="exit"&&x==0){
 54                 flag=4;
 55             }
 56             if (code>0){
 57                 flag=2;
 58             }
 59             return ;
 60         }
 61         if (a=='='){
 62             flag=3;
 63             all[x]=dat;
 64             x++;
 65             dat="";
 66             continue;
 67         }
 68         dat+=a;
 69     }
 70 }
 71 
 72 int Error=0;
 73 
 74 void givenum(){
 75     Error=0;
 76     for (int i=0;i<=x;i++){
 77         if ((all[i][0]>='0'&&all[i][0]<='9')||
 78             all[i]=="("||
 79             all[i]==")"||
 80             all[i][0]=='+'||
 81             all[i][0]=='-'||
 82             all[i]=="*"||
 83             all[i]=="/"){
 84             continue;
 85         }
 86         if (cnt.find(all[i])!=cnt.end()){
 87             all[i]=cnt[all[i]];
 88         }
 89         else{
 90             printf("out>>error code 3: undefined '%s'\n",all[i].c_str());
 91             Error=1;
 92             break;
 93         }
 94     }
 95 }
 96 
 97 void check(){
 98     Error=0;
 99     int code[x+10];
100     for (int i=0;i<=x;i++){
101         if (all[i]=="+"||
102             all[i]=="-"||
103             all[i]=="*"||
104             all[i]=="/"){
105             code[i]=4;
106             continue;
107         }
108         if (all[i][0]=='('){
109             code[i]=2;
110             continue;
111         }
112         if (all[i][0]==')'){
113             code[i]=3;
114             continue;
115         }
116         code[i]=1;
117     }
118     if (code[0]==4){
119         printf("out>>error code 9: extra start operation '%s'\n",all[0].c_str());
120         Error=1;
121     }
122     for (int i=0;i<=x;i++){
123         if (i>0&&
124             code[i]==1&&
125             code[i-1]==3){
126             printf("out>>error code 4: operation after ')' needed\n");
127             Error=1;
128         }
129         if (i<x&&
130             code[i]==1&&
131             code[i+1]==2){
132             printf("out>>error code 5: operation before '(' needed\n");
133             Error=1;
134         }
135         if (i<x&&
136             code[i]==1&&
137             code[i+1]==1){
138             printf("out>>error code 6: operation after '%s' needed\n",all[i].c_str());
139             Error=1;
140         }
141         if (i<x&&
142             code[i]==4&&
143             code[i+1]==4){
144             printf("out>>error code 7: double operation '%s' '%s'\n",all[i].c_str(),all[i+1].c_str());
145             Error=1;
146         }
147     }
148     if (code[x]==4){
149         printf("out>>error code 8: extra end operation '%s'\n",all[x].c_str());
150         Error=1;
151     }
152 }
153 
154 stack<string> fx1;
155 stack<string> fx2;
156 
157 int level(string buffer){
158     switch (buffer[0]){
159         case '+': return 1;
160         case '-': return 1;
161         case '*': return 2;
162         case '/': return 2;
163         default:  return 0;
164     }
165 }
166 
167 void change(){
168     while (fx1.empty()!=1){
169         fx1.pop();
170     }
171     while (fx2.empty()!=1){
172         fx2.pop();
173     }
174     int m=0;
175     while (m<=x){
176         if (all[m]=="+"||
177             all[m]=="-"||
178             all[m]=="*"||
179             all[m]=="/"){
180             if (fx1.empty()==1||
181                 fx1.top()=="("){
182                 fx1.push(all[m]);
183                 m++;
184                 continue;
185             }
186             else{
187                 if (level(fx1.top())<=level(all[m])){
188                     fx1.push(all[m]);
189                     m++;
190                     continue;
191                 }
192                 else{
193                     while (fx1.empty()!=1&&
194                            fx1.top()!="("&&
195                            level(fx1.top())>level(all[m])){
196                         fx2.push(fx1.top());
197                         fx1.pop();
198                     }
199                     fx1.push(all[m]);
200                     m++;
201                     continue;
202                 }
203             }
204         }
205         if (all[m][0]=='('||
206             all[m][0]==')'){
207             if (all[m][0]=='('){
208                 fx1.push(all[m]);
209                 m++;
210                 continue;
211             }
212             if (all[m][0]==')'){
213                 while (fx1.empty()!=1&&
214                        fx1.top()!="("){
215                     fx2.push(fx1.top());
216                     fx1.pop();
217                 }
218                 fx1.pop();
219                 m++;
220                 continue;
221             }
222         }
223         fx2.push(all[m]);
224         m++;
225     }
226     while (fx1.empty()!=1){
227         fx2.push(fx1.top());
228         fx1.pop();
229     }
230     while (fx2.empty()!=1){
231          fx1.push(fx2.top());
232          fx2.pop();
233     }
234 }
235 
236 stack<double> ans;
237 
238 void Out(double i){
239     double a;
240     int a0,a1;
241     a=i;
242     a0=1000*a;
243     if (a0%1000==0){
244         a1=a;
245         printf("out>>%d\n",a1);
246     }
247     else{
248         printf("out>>%.2lf\n",a);
249     }
250 }
251 
252 void cal(){
253     Error=0;
254     if (ans.empty()==0){
255         ans.pop();
256     }
257     double a=0.0,b=0.0;
258     char tmp[300];
259     while (fx1.empty()==0){
260         if (fx1.top()=="+"||
261             fx1.top()=="-"||
262             fx1.top()=="*"){
263             a=ans.top();
264             ans.pop();
265             b=ans.top();
266             ans.pop();
267             if (fx1.top()=="+"){ans.push(b+a);}
268             if (fx1.top()=="-"){ans.push(b-a);}
269             if (fx1.top()=="*"){ans.push(b*a);}
270             fx1.pop();
271             continue;
272         }
273         if (fx1.top()=="/"){
274             if (ans.top()==0){
275                 Error=1;
276                 printf("out>>error code 10: '0' under '/'\n");
277                 return ;
278             }
279             a=ans.top();
280             ans.pop();
281             b=ans.top();
282             ans.pop();
283             ans.push(b/a);
284             fx1.pop();
285             continue;
286         }
287         for (int i=0;i<300;i++){
288             tmp[i]=0;
289         }
290         strcpy(tmp,fx1.top().c_str());
291         ans.push(atof(tmp));
292         fx1.pop();
293     }
294     if (ans.size()!=1){
295         printf("out>>error code 11: BUG SHOWED!DAMN!!!\n");
296     }
297     else{
298         Out(ans.top());
299         ans.pop();
300     }
301 }
302 
303 void guide(){
304     printf("浮点数四则运算器:\n");
305     printf("每输入一个数据或操作符,你需要使用一个空格来表示输入完成。\n");
306     printf("输入完成一行表达式后,输入回车来表示输入结束。\n");
307     printf("若输入了错误的表达式,请参照程序的报错类型修正表达式。\n");
308     printf("你可以为多个变量或单个变量赋值,下面是一个事例:\n");
309     printf("in>>x y = 3.1\n");
310     printf("out>>3.1\n");
311     printf("in>>( x + y ) * -3\n");
312     printf("out>>-18.60\n");
313     printf("保留两位小数。");
314     printf("输入exit可以退出程序。\n");
315     printf("===============================================\n");
316 }
317 
318 int main(){
319     guide();
320     while (1){
321         Getdata();
322         if (flag==1){
323             printf("out>>error code 1: extra ')'\n");
324             continue;
325         }
326         if (flag==2){
327             printf("out>>error code 2: extra '('\n");
328             continue;
329         }
330         if (flag==3){
331             printf("out>>%s\n",cnt[all[x-1]].c_str());
332             continue;
333         }
334         if (flag==4){
335             break;
336         }
337         if (flag==0){
338             givenum();
339             if (Error==1){
340                 continue;
341             }
342             check();
343             if (Error==1){
344                 continue;
345             }
346             change();
347             cal();
348             continue;
349         }
350     }
351     return 0;
352 }
浮点数四则运算器

 

作业结束后助教君给出的参考用标准程序也折叠在下方。

  1 #include <cstdio>
  2 #include <stack>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <string>
  6 #include <map>
  7 using namespace std;
  8 
  9 // debug flag
 10 #define $ if(0)
 11 
 12 const int MAX_VAR_LENGTH=107;
 13 const char POSITIVE=1,NEGATIVE=2,END=3; // special operators
 14 int precedence[256]; // char -> precedence
 15 
 16 struct Number { // to deal with auto float/int recognition
 17     double val;
 18     bool is_integer;
 19 };
 20 
 21 // variable stuffs
 22 string var_name;
 23 inline bool valid_var_char(char c) {
 24     return (c>='a'&&c<='z') || (c>='A'&&c<='Z') || (c>='0'&&c<='9') || c=='_';
 25 }
 26 inline int read_var_name(char *s) {
 27     char var_name_tmp[MAX_VAR_LENGTH];
 28     
 29     if(!valid_var_char(s[0]) || (s[0]>='0'&&s[0]<='9'))
 30         return 0;
 31     var_name_tmp[0]=s[0];
 32     int i=1;
 33     for(;valid_var_char(s[i]);i++)
 34         var_name_tmp[i]=s[i];
 35     var_name_tmp[i]='\0';
 36     var_name=var_name_tmp;
 37     return i;
 38 }
 39 map<string,Number> var_store;
 40 
 41 // apply `op` to `val`s
 42 inline void apply(stack<Number> &val,char op) {
 43     if(op=='(' || op==')' || op==END) return;
 44     
 45     if(val.empty()) throw "no sufficient operand";
 46     Number v2=val.top(); val.pop();
 47     
 48     // unary operators
 49     if(op==POSITIVE) {
 50         val.push(v2);
 51         return;
 52     } else if(op==NEGATIVE) {
 53         val.push(Number{-v2.val,v2.is_integer});
 54         return;
 55     }
 56     
 57     if(val.empty()) throw "no sufficient operand";
 58     Number v1=val.top(); val.pop();
 59     
 60     // binary operators
 61     Number res;
 62     res.is_integer=v1.is_integer&&v2.is_integer;
 63     
 64     if(op=='+') res.val=v1.val+v2.val;
 65     else if(op=='-') res.val=v1.val-v2.val;
 66     else if(op=='*') res.val=v1.val*v2.val;
 67     else if(op=='/') {
 68         if(fabs(v2.val)<1e-6) throw "division by zero";
 69         res.val=v1.val/v2.val;
 70     }
 71     else throw "invalid operator";
 72     
 73     // round the result if is integer
 74     if(res.is_integer) res.val=double(int(res.val));
 75     
 76     $ printf("[APPLY] %lf %c %lf = %lf\n",v1.val,op,v2.val,res.val);
 77     val.push(res);
 78 }
 79 
 80 // calc a pure expression
 81 inline Number calc(char *s) {
 82     int len=(int)strlen(s);
 83     s[len++]=END;
 84     stack<char> op;
 85     op.push(END);
 86     stack<Number> val;
 87     bool last_is_operand=false;
 88     
 89     for(int i=0;i<len;) {
 90         if(s[i]==' ') {
 91             $ printf("[SPACE] at %d\n",i);
 92             i++;
 93         } else if(int var_len=read_var_name(s+i)) { // variable
 94             if(last_is_operand) throw "continuous operand";
 95             
 96             if(var_store.find(var_name)==var_store.end()) throw "uninitialized variable";
 97             $ printf("[VAR] at %d: %s\n",i,var_name.c_str());
 98             val.push(var_store[var_name]);
 99             
100             last_is_operand=true;
101             i+=var_len;
102         } else if((s[i]>='0'&&s[i]<='9')||s[i]=='.') { // number literal
103             if(last_is_operand) throw "continuous operand";;
104             double curval;
105             int curlen;
106             
107             sscanf(s+i,"%lf%n",&curval,&curlen);
108             $ printf("[VAL] at %d+%d: %lf\n",i,curlen,curval);
109             
110             bool is_integer=true;
111             for(int j=i;j<i+curlen;j++)
112                 if(s[j]=='.')
113                     is_integer=false;
114             
115             if(curlen==0 || (!is_integer && curlen==1)) // '.'
116                 throw "invalid number";
117             
118             val.push(Number{curval,is_integer});
119             last_is_operand=true;
120             i+=curlen;
121         } else { // operator
122             char o=s[i];
123             
124             // detect unary POSITIVE & NEGATIVE
125             int prev=i-1;
126             while(prev>=0 && s[prev]==' ') prev--;
127             if((o=='+' || o=='-') && ( // we use s[prev] instead of s[i-1] here because of possible whitespaces
128                                       prev==-1 || (s[prev]=='(' || s[prev]=='+' || s[prev]=='-' || s[prev]=='*' || s[prev]=='/')
129                                       )) {
130                 o=(o=='+')?POSITIVE:NEGATIVE;
131             }
132             
133             $ printf("[OP] at %d: %c\n",i,o);
134             if(!precedence[(int)o]) {
135                 throw "unknown operator";
136             }
137             
138             if(o=='(') {
139                 if(last_is_operand) throw "invalid usage of bracket";
140                 op.push(o);
141             } else if(o==')') {
142                 if(!last_is_operand) throw "invalid usage of bracket";
143                 while(!op.empty() && op.top()!='(') {
144                     char top=op.top();
145                     $ printf("[APPLY] %c : %c\n",o,top);
146                     apply(val,top); op.pop();
147                 }
148                 if(op.empty()) throw "invalid usage of bracket";
149                 $ printf("[APPLY] %c : (\n",o);
150                 op.pop(); //'('
151             } else { // normal arithmetic operator
152                 if(o!=POSITIVE && o!=NEGATIVE) // unary operator should not apply right now, or -+2 will cause an error
153                     while(!op.empty() && precedence[(int)o]<=precedence[(int)op.top()]) {
154                         char top=op.top();
155                         $ printf("[APPLY] %c : %c\n",o,top);
156                         apply(val,top); op.pop();
157                     }
158                 
159                 op.push(o);
160                 last_is_operand=false;
161             }
162             i++;
163         }
164     }
165     // finished
166     
167     if(op.size()!=1 || val.size()!=1)
168         throw "bad expression";
169     return val.top();
170 }
171 
172 int main() {
173     char s[10007];
174     
175     precedence[(int)'(']=1, precedence[(int)')']=1,
176     precedence[(int)END]=2, // precedence of END is higher than ( and ) so we can check bracket errors correctly
177     precedence[(int)'+']=3, precedence[(int)'-']=3,
178     precedence[(int)'*']=4, precedence[(int)'/']=4,
179     precedence[(int)POSITIVE]=5, precedence[(int)NEGATIVE]=5;
180     
181     while(true) {
182         Number res;
183         scanf("%*[ ]"); // ignore leading spaces
184         
185         gets(s);
186         if(strcmp(s,"exit")==0)
187             return 0;
188         
189         int len=(int)strlen(s),eqpos=-1;
190         for(int i=len-1;i>0;i--) // eqpos: position of the last `=`
191             if(s[i]=='=') {
192                 eqpos=i;
193                 break;
194             }
195         
196         try {
197             if(eqpos==-1) // pure EXPRESSION
198                 res=calc(s);
199             else { // VAR = EXPRESSION
200                 res=calc(s+eqpos+1); // the EXPRESSION part
201                 
202                 int name_len=read_var_name(s);
203                 for(int i=name_len;i<eqpos;i++) // tackle with trailing spaces after variable name
204                     if(s[i]!=' ')
205                         throw "bad variable name";
206                 
207                 // finally store it
208                 $ printf("STORE TO %s\n",var_name.c_str());
209                 var_store[var_name]=res;
210             }
211         } catch(const char *e) {
212             printf("error: %s\n",e);
213             //printf("error\n");
214             continue;
215         }
216         // no error
217         printf(res.is_integer ? "%.0lf\n" : "%.2lf\n", res.val);
218     }
219 }
浮点数四则运算器(参考答案)

 

posted @ 2018-12-04 16:31  ParallelParadox  阅读(327)  评论(0)    收藏  举报