计算后缀表达式的过程主要按下面的思路进行:
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倍为精度判断输出的数是否为浮点数后再输出。
stack<double> ans;
void Out(double i){
double a;
int a0,a1;
a=i;
a0=1000*a;
if (a0%1000==0){
a1=a;
printf("out>>%d\n",a1);
}
else{
printf("out>>%.2lf\n",a);
}
}
代码:
void cal(){
Error=0;
if (ans.empty()==0){
ans.pop();
}
double a=0.0,b=0.0;
char tmp[300];
while (fx1.empty()==0){
if (fx1.top()=="+"||
fx1.top()=="-"||
fx1.top()=="*"){
a=ans.top();
ans.pop();
b=ans.top();
ans.pop();
if (fx1.top()=="+"){ans.push(b+a);}
if (fx1.top()=="-"){ans.push(b-a);}
if (fx1.top()=="*"){ans.push(b*a);}
fx1.pop();
continue;
}
if (fx1.top()=="/"){
if (ans.top()==0){
Error=1;
printf("out>>error code 10: '0' under '/'\n");
return ;
}
a=ans.top();
ans.pop();
b=ans.top();
ans.pop();
ans.push(b/a);
fx1.pop();
continue;
}
for (int i=0;i<300;i++){
tmp[i]=0;
}
strcpy(tmp,fx1.top().c_str());
ans.push(atof(tmp));
fx1.pop();
}
if (ans.size()!=1){
printf("out>>error code 11: BUG SHOWED!DAMN!!!\n");
}
else{
Out(ans.top());
ans.pop();
}
}
将之前三篇文章中的模块拼合在一起就可以得到完整的程序了。
但是还需要对程序的使用者提供一定的帮助,因此有了下面的指导模块:
void guide(){
printf("浮点数四则运算器:\n");
printf("每输入一个数据或操作符,你需要使用一个空格来表示输入完成。\n");
printf("输入完成一行表达式后,输入回车来表示输入结束。\n");
printf("若输入了错误的表达式,请参照程序的报错类型修正表达式。\n");
printf("你可以为多个变量或单个变量赋值,下面是一个事例:\n");
printf("in>>x y = 3.1\n");
printf("out>>3.1\n");
printf("in>>( x + y ) * -3\n");
printf("out>>-18.60\n");
printf("保留两位小数。");
printf("输入exit可以退出程序。\n");
printf("===============================================\n");
}
作业结束后助教君给出的参考用标准程序也折叠在下方。
#include
#include
#include
#include
#include
#include
using namespace std;
// debug flag
#define $ if(0)
const int MAX_VAR_LENGTH=107;
const char POSITIVE=1,NEGATIVE=2,END=3; // special operators
int precedence[256]; // char -> precedence
struct Number { // to deal with auto float/int recognition
double val;
bool is_integer;
};
// variable stuffs
string var_name;
inline bool valid_var_char(char c) {
return (c>='a'&&c<='z') || (c>='A'&&c<='Z') || (c>='0'&&c<='9') || c=='_';
}
inline int read_var_name(char *s) {
char var_name_tmp[MAX_VAR_LENGTH];
if(!valid_var_char(s[0]) || (s[0]>='0'&&s[0]<='9'))
return 0;
var_name_tmp[0]=s[0];
int i=1;
for(;valid_var_char(s[i]);i++)
var_name_tmp[i]=s[i];
var_name_tmp[i]='\0';
var_name=var_name_tmp;
return i;
}
map<string,Number> var_store;
// apply `op` to `val`s
inline void apply(stack<Number> &val,char op) {
if(op=='(' || op==')' || op==END) return;
if(val.empty()) throw "no sufficient operand";
Number v2=val.top(); val.pop();
// unary operators
if(op==POSITIVE) {
val.push(v2);
return;
} else if(op==NEGATIVE) {
val.push(Number{-v2.val,v2.is_integer});
return;
}
if(val.empty()) throw "no sufficient operand";
Number v1=val.top(); val.pop();
// binary operators
Number res;
res.is_integer=v1.is_integer&&v2.is_integer;
if(op=='+') res.val=v1.val+v2.val;
else if(op=='-') res.val=v1.val-v2.val;
else if(op=='*') res.val=v1.val*v2.val;
else if(op=='/') {
if(fabs(v2.val)<1e-6) throw "division by zero";
res.val=v1.val/v2.val;
}
else throw "invalid operator";
// round the result if is integer
if(res.is_integer) res.val=double(int(res.val));
$ printf("[APPLY] %lf %c %lf = %lf\n",v1.val,op,v2.val,res.val);
val.push(res);
}
// calc a pure expression
inline Number calc(char *s) {
int len=(int)strlen(s);
s[len++]=END;
stack<char> op;
op.push(END);
stack<Number> val;
bool last_is_operand=false;
for(int i=0;i<len;) {
if(s[i]==' ') {
$ printf("[SPACE] at %d\n",i);
i++;
} else if(int var_len=read_var_name(s+i)) { // variable
if(last_is_operand) throw "continuous operand";
if(var_store.find(var_name)==var_store.end()) throw "uninitialized variable";
$ printf("[VAR] at %d: %s\n",i,var_name.c_str());
val.push(var_store[var_name]);
last_is_operand=true;
i+=var_len;
} else if((s[i]>='0'&&s[i]<='9')||s[i]=='.') { // number literal
if(last_is_operand) throw "continuous operand";;
double curval;
int curlen;
sscanf(s+i,"%lf%n",&curval,&curlen);
$ printf("[VAL] at %d+%d: %lf\n",i,curlen,curval);
bool is_integer=true;
for(int j=i;j<i+curlen;j++)
if(s[j]=='.')
is_integer=false;
if(curlen==0 || (!is_integer && curlen==1)) // '.'
throw "invalid number";
val.push(Number{curval,is_integer});
last_is_operand=true;
i+=curlen;
} else { // operator
char o=s[i];
// detect unary POSITIVE & NEGATIVE
int prev=i-1;
while(prev>=0 && s[prev]==' ') prev--;
if((o=='+' || o=='-') && ( // we use s[prev] instead of s[i-1] here because of possible whitespaces
prev==-1 || (s[prev]=='(' || s[prev]=='+' || s[prev]=='-' || s[prev]=='*' || s[prev]=='/')
)) {
o=(o=='+')?POSITIVE:NEGATIVE;
}
$ printf("[OP] at %d: %c\n",i,o);
if(!precedence[(int)o]) {
throw "unknown operator";
}
if(o=='(') {
if(last_is_operand) throw "invalid usage of bracket";
op.push(o);
} else if(o==')') {
if(!last_is_operand) throw "invalid usage of bracket";
while(!op.empty() && op.top()!='(') {
char top=op.top();
$ printf("[APPLY] %c : %c\n",o,top);
apply(val,top); op.pop();
}
if(op.empty()) throw "invalid usage of bracket";
$ printf("[APPLY] %c : (\n",o);
op.pop(); //'('
} else { // normal arithmetic operator
if(o!=POSITIVE && o!=NEGATIVE) // unary operator should not apply right now, or -+2 will cause an error
while(!op.empty() && precedence[(int)o]<=precedence[(int)op.top()]) {
char top=op.top();
$ printf("[APPLY] %c : %c\n",o,top);
apply(val,top); op.pop();
}
op.push(o);
last_is_operand=false;
}
i++;
}
}
// finished
if(op.size()!=1 || val.size()!=1)
throw "bad expression";
return val.top();
}
int main() {
char s[10007];
precedence[(int)'(']=1, precedence[(int)')']=1,
precedence[(int)END]=2, // precedence of END is higher than ( and ) so we can check bracket errors correctly
precedence[(int)'+']=3, precedence[(int)'-']=3,
precedence[(int)'*']=4, precedence[(int)'/']=4,
precedence[(int)POSITIVE]=5, precedence[(int)NEGATIVE]=5;
while(true) {
Number res;
scanf("%*[ ]"); // ignore leading spaces
gets(s);
if(strcmp(s,"exit")==0)
return 0;
int len=(int)strlen(s),eqpos=-1;
for(int i=len-1;i>0;i--) // eqpos: position of the last `=`
if(s[i]=='=') {
eqpos=i;
break;
}
try {
if(eqpos==-1) // pure EXPRESSION
res=calc(s);
else { // VAR = EXPRESSION
res=calc(s+eqpos+1); // the EXPRESSION part
int name_len=read_var_name(s);
for(int i=name_len;i<eqpos;i++) // tackle with trailing spaces after variable name
if(s[i]!=' ')
throw "bad variable name";
// finally store it
$ printf("STORE TO %s\n",var_name.c_str());
var_store[var_name]=res;
}
} catch(const char *e) {
printf("error: %s\n",e);
//printf("error\n");
continue;
}
// no error
printf(res.is_integer ? "%.0lf\n" : "%.2lf\n", res.val);
}
}
//浮点数四则运算器(参考答案)