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

【应用】浮点数四则运算器 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倍为精度判断输出的数是否为浮点数后再输出。

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);
    }
}

//浮点数四则运算器(参考答案)

你可能感兴趣的:(C++)