/***
* @author banxi1988
* @mail banxi1988 at gmail.com
* @qq 787928000
* 一个简单的四则运算器。C语言实现。暂时无法实现处理括号。
* @bug-report : if have any suggestion and find any bug please send mail to my mail or send massage to my qq! thanks
*/
#include
#include
#include
#include
//#define BANXI_DEBUG 1
#define MAX_LEN 1024
#define D_BIT_LEN 32
/***
* 一些有用的宏,关于字符操作
*/
#define is_operator(ch) (strchr("+-*/",(ch)) != NULL) // 判断是否是运算符
#define is_muldiv(ch) (strchr("*/",(ch)) != NULL) // 判断是否是乘法或除法
#define is_end_input(ch) (ch == EOF || ch == '/n') //判断是否是输入的结尾。一次只允许输入一行。所以..
typedef enum OP_TYPE_TAG{OPERAND,OPERATOR}OP_TYPE;
typedef enum READ_STATE{R_OPERAND,R_OPERATOR}READ_TYPE;
typedef struct OP_ITEM_TAG{
double operand;
char operator;
OP_TYPE op_type;
}OP_ITEM;
OP_ITEM op_items[MAX_LEN] = {{0,0,0}};
int items_count = 0;
READ_TYPE read_type = R_OPERAND;
int remove_space(){
char ch;
while(isspace(ch=getchar()));
ungetc(ch,stdin);
}//end remove_space
int bits_length_tips(int index){
if(index > 37){
printf("WARNING:YOU HAVE INPUT A TOO LARGER NUMBER,IF HAVE NO POINT!/n");
}else if(index > D_BIT_LEN){
printf("WARNING:YOU HAVA INPUT A LARGER NUMBER!/n");
}//
}//end bits_length_tips
int input_data(){
char buffer[D_BIT_LEN] = {'/0'};
char operator = 'a';
double operand = 0.0;
char ch = 'a';
int index = 0; //for digit bit count
int flag = 0; //for float . token count
read_type = R_OPERAND; // 先读操作数
while(1){
if(read_type == R_OPERAND){
remove_space(); //清除空格
/// 接受到非数字组成字符跳出,或者空格也跳出
index = 0;
while((ch = getchar())&&(!isspace(ch))){
if(isdigit(ch)){
buffer[index++] = ch;
}else if(ch == '.'){
flag++;
if(flag > 1){
printf("ERROR:too many /'./' char,need a number/n");
exit(EXIT_FAILURE);
}else{
buffer[index++] = ch;
}
}else{
if(flag < 1 && index < 1){
printf("ERROR:need a /'./' or a digit,but %c recive/n",ch);
exit(EXIT_FAILURE);
}else{
break; // stop revice for operand
}//end other char
}//
}//end while
ungetc(ch,stdin);// 将空格或者其它字符放回,以便下面处理
bits_length_tips(index); // 超多位数可能越界提示
index = (index > 36)?36:index;
buffer[index] = '/0';
operand = atof(buffer);
op_items[items_count].operand = operand;
op_items[items_count].op_type = OPERAND;
read_type = R_OPERATOR;
items_count++;
}// end deal with digit
else{
while(isspace(ch = getchar()) && (ch != '/n')); // 消除空格
if(is_end_input(ch))break; // 结束则跳出总循环。
if(!is_operator(ch)){
printf("ERROR:need a OPERATOR ,but %c recive/n",ch);
exit(EXIT_FAILURE);
}
op_items[items_count].operator = ch;
op_items[items_count].op_type = OPERATOR;
read_type = R_OPERAND;
items_count++;
}//end deal with operator
}//end while 1 read exp
///
if(items_count % 2 == 0){
printf("ERROR:non valid expression/n");
exit(EXIT_FAILURE);
}//
return 0;
}//end input_data
void
print_data(){
int i = 0;
for(i = 0; i < items_count; i++){
if(op_items[i].op_type == OPERAND){
printf("%d/t%lf/t",i,op_items[i].operand);
}//
else{
printf("%d/t%c/t",i,op_items[i].operator);
}
printf("/n");
}//end for
}//end print_data
/***
* @function :根据传入的两个数及运算符即操作符,返回运算结果
* @param :left double
* @param :right double
* @param : op char
* @return : double
* 说明:均为从左到右运算
*
*/
double cal(double left,char op,double right){
switch(op){
case '+':return left+right;break;
case '-':return left - right ;break;
case '*':return left*right;break;
case '/':
if(right == 0){
printf("divide not be 0/n");exit(EXIT_FAILURE);
}//
else{
return left/right;
}
break;
default:
#ifdef BANXI_DEBUG
printf("%f %c %f/n",left,op,right);
#endif
printf("non valid operator %c /n",op);
exit(EXIT_FAILURE);
break;
}//end op switch
}//end cal
/**
* @function:计算表达式。如2*4+2 则先计算2+4部分。然后将计算所得值放回左操作符所在位置。
* 即成为了2*6。此计算没有考虑优先级。从右向左计算。
* 前提依赖为表达式完全按照规范来。即expression -----> operand operator operand ,组成。计算对应如下。
* op_items[i-2] op_items[i-1] op_items[i]
*
*/
double cal_exp(){
double result = 0;
int i = 0;
for(i = items_count -1; i > 1; i -= 2){
result = cal(op_items[i - 2].operand,op_items[i-1].operator,op_items[i].operand);
op_items[i-2].operand = result;
}//
return op_items[0].operand;
}//
/**
* @function :交换a,b为下标的op_items中的内容。
*/
void swap_items(int a,int b){
double operand;
char operator;
OP_TYPE op_type;
operand = op_items[a].operand;
operator = op_items[a].operator;
op_type = op_items[a].op_type;
op_items[a].operand = op_items[b].operand;
op_items[a].operator = op_items[b].operator;
op_items[a].op_type = op_items[b].op_type;
op_items[b].operand = operand;
op_items[b].operator = operator;
op_items[b].op_type = op_type;
}//
/**
* @function :将下标from处的op_items内容复制到dest下标处。dest处的内容将被覆盖。
*/
void copy_items(int dest,int from){
op_items[dest].operand = op_items[from].operand;
op_items[dest].operator = op_items[from].operator;
op_items[dest].op_type = op_items[from].op_type;
}//end copy_items
/**
* @function: 从start下标处开始。将steps后的op_items中的内容往前移steps个单位。
* 即start后面的steps个数组内容没有了将后面的向前移动以便对齐。
*
*/
int move_items(int start,int steps){
int index = 0;
for(index = start ; (index+steps) < items_count; index++){
copy_items(index,index+steps);
}//
return 0;
}//end move_items
/**
* @function : 扫描op_items数组,查找乘法或者除法。如果返回找到第一个的下标。
*如果没有找到返回-1
*说明:依赖于规范的表达式。所以查找op_items下标为1,3,5,……
*/
int find_muldiv(){
int i = 0;
for(i = 1; i < items_count; i+=2){
#ifdef BANXI_DEBUG
if(op_items[i].op_type != OPERATOR){
printf("need a operator but is a : op_items[%d].operand :%lf/n",i,op_items[i].operand);
}//
#endif //BANXI_DEBUG
if(is_muldiv(op_items[i].operator)){
return i;
}//end
}//
return -1;
}//
/***
* @function : 带优先级的表达式计算。
* 一种思路就是,先扫描整个op_items 数组。找到优先级最高的计算。然后为将op_items后面的项前移两位。
*
*
*/
double cal_exp_with_pri(){
int index = 0;
int i = 0;
double result = 0;
for(i = items_count -2; i > 0; i -= 2){
index = find_muldiv();
if(index > 0){
#ifdef BANXI_DEBUG
printf("find a priority in %d cal.../n",index);
#endif
result = cal(op_items[index - 1].operand,op_items[index].operator,op_items[index+1].operand);
op_items[index-1].operand = result;
move_items(index,2);
}//
else{
index = i;
result = cal(op_items[index - 1].operand,op_items[index].operator,op_items[index+1].operand);
op_items[index-1].operand = result;
}
items_count -= 2;
#ifdef BANXI_DEBUG
print_data();
#endif // debug
}//
return op_items[0].operand;
}//end
int main(void){
double result = 0.0;
input_data();
#ifdef BANXI_DEBUG
print_data();
#endif // BANXI_DEBUG
result = cal_exp_with_pri();
printf("/t %.2lf/n",result);
printf("calculate takes time %ld seconds /n",clock()/CLOCKS_PER_SEC);
return EXIT_SUCCESS;
}//end
/*****
运行及测试结果:
调试模式输出如下:
banxi1988@banxi:~/cpp/c/exp_cal$ gcc -g -o simple simple.c
banxi1988@banxi:~/cpp/c/exp_cal$ echo 2+4*8/8+1 | ./simple
02.000000
1+
24.000000
3*
48.000000
5/
68.000000
7+
81.000000
find a priority in 3 cal...
02.000000
1+
232.000000
3/
48.000000
5+
61.000000
find a priority in 3 cal...
02.000000
1+
24.000000
3+
41.000000
02.000000
1+
25.000000
07.000000
7.00
calculate takes time 0 seconds
非调试模式输入结果如下:
banxi1988@banxi:~/cpp/c/exp_cal$ echo 2+4*8/8+1 | ./simple
7.00
calculate takes time 0 seconds
banxi1988@banxi:~/cpp/c/exp_cal$ echo 2+4*8/8+1*2/2 | ./simple
7.00
calculate takes time 0 seconds
banxi1988@banxi:~/cpp/c/exp_cal$ echo 2+4*8/8+1*2/4 | ./simple
6.50
calculate takes time 0 seconds
banxi1988@banxi:~/cpp/c/exp_cal$
*
*
*/