LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 2033|回复: 11

中缀式四则运算计算器 -- C语言习作

[复制链接]
发表于 2006-4-28 11:49:23 | 显示全部楼层 |阅读模式
又是一个小程序,学过编程的大概都写过类似程序了,反正写了就放上来,这里还是有一些编程初学者的,和我一样的菜鸟请多交流,高手有空就指点一两句吧,谢谢!


用到了两个栈,一个栈的元素类型是 double,另一个栈的元素类型是 char,用 union 把它们结合在一起

  1. union Era
  2. {
  3.   double nd;    // op.era.nd
  4.   char tor;     // op.era.tor
  5. };
复制代码

这样就可以用同一套pop()和push()函数来处理两个栈了,否则就要写两套大同小异的pop()和push()。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
发表于 2006-4-28 12:00:04 | 显示全部楼层
如果很小的话, 就别用附件了, 直接嵌在里面有好一些.
回复 支持 反对

使用道具 举报

发表于 2006-4-28 12:42:17 | 显示全部楼层
你的我下载不了?

也发一个抄自书上的:


  1. #include<ctype.h>
  2. #include<stdio.h>
  3. #include<stdlib.h>

  4. #define NUM 257
  5. #define NONE 258


  6. int lookahead;
  7. int lineno = 1;
  8. int tokenval=NONE;

  9. double expr();


  10. // exp -> term rest
  11. // rest -> empty
  12. //      -> + term rest
  13. //      -> - term rest
  14. // term -> factor termrest
  15. // termrest -> * factor termrest
  16. //          -> / factor termrest
  17. // factor -> num
  18. //        -> (expr)

  19. void error(char *s){
  20.   printf("syntax error:%s\n",s);
  21.   exit(1);
  22. }

  23. int lexan()
  24. {
  25.   int t;
  26.   while(1){
  27.     t=getchar();
  28.     if(t==' ' || t=='\t' ) ;
  29.     else if(t=='\n')
  30.       lineno++;
  31.     else if(isdigit(t)){
  32.       tokenval=t-'0';
  33.       t=getchar();
  34.       while(isdigit(t)){
  35.         tokenval=tokenval*10+t-'0';
  36.         t=getchar();
  37.       }
  38.       ungetc(t, stdin);
  39.       return NUM;
  40.     }
  41.     else {
  42.       tokenval=NONE;
  43.       return t;
  44.     }
  45.   }
  46. }

  47. void match(int t){
  48.   if(lookahead==t){
  49.     lookahead=lexan();
  50.   }
  51.   else error("in match");
  52. }

  53. double factor(){
  54.   double r=0;
  55.   if(lookahead=='('){
  56.     match('(');
  57.     r=expr();
  58.     match(')');
  59.   }
  60.   else if( lookahead==NUM){
  61.     r=tokenval;
  62.     match(NUM);
  63.   }
  64.   else error("in factor");
  65.   return r;
  66. }

  67. double term(){
  68.   double num=factor();
  69.   while(1){
  70.     if(lookahead=='*'){
  71.       match('*');
  72.       num*=factor();
  73.     }
  74.     else if( lookahead=='/'){
  75.       match('/');
  76.       num/=factor();
  77.     }
  78.     else break;      
  79.   }
  80.   return num;
  81. }

  82. double expr(){
  83.   double left=term();
  84.   while(1){
  85.     if(lookahead=='+'){
  86.       match('+');
  87.       left+=term();
  88.       
  89.     } else if(lookahead=='-'){
  90.       match('-');
  91.       left-=term();
  92.     }
  93.     else break;
  94.   }
  95.   return left;
  96. }


  97. int main(int argc, char **argv)
  98. {
  99.   lookahead=lexan();
  100.   while(!feof(stdin)){
  101.     printf("\n%f\n",expr());
  102.   }
  103.   return 0;
  104. }
复制代码
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-4-28 13:28:25 | 显示全部楼层
  1. /* infix calculator version 0.1.3 #20060428
  2. * by 419Labs
  3. * kikistar.com@gmail.com
  4. * http://my.opera.com/419/
  5. *
  6. * References:
  7. * 1.[K&R] The C Programming Language (second edition)
  8. *                                            影印版 ISBN 7-302-02412-X/TP.1214
  9. * 2.[Mark Allen Weiss] Data Structures and Algorithm Analysis in C
  10.                              (second edition) 中文版 ISBN 7-111-12748-X
  11. * 3.[严蔚敏 吴伟民] 数据结构(C语言版)             ISBN 7-900643-22-2
  12. */
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <ctype.h>
  16. #define MAXOP        100
  17. #define NUMBER        '0'        // signal that a number was found
  18. #define EMPTY        0
  19. enum Optype { ND, TOR };        // ND for operand, TOR for operator
  20. union Era
  21. {
  22.   double nd;        // op.era.nd
  23.   char tor;        // op.era.tor
  24. };
  25. struct Op
  26. {
  27.   int max;
  28.   int top;
  29.   enum Optype type;
  30.   union Era *era;
  31. };
  32. struct Op *create_stack(int max, enum Optype);
  33. void push(union Era, struct Op *);
  34. union Era pop(struct Op *);
  35. void nullerr(void);
  36. int getop(char []);
  37. double operate(struct Op *opnd, struct Op *optor);
  38. void print_stack(struct Op *op);
  39. char top_tor(struct Op *);
  40. int
  41. main()
  42. {
  43.   int c;
  44.   char s[MAXOP];
  45.   union Era era;
  46.   struct Op *opnd;
  47.   struct Op *optor;
  48.   opnd = create_stack(MAXOP, ND);
  49.   optor = create_stack(MAXOP, TOR);
  50.   printf(" 本程序可进行“加减乘除(+ - * /)”四则混合运算。\n");
  51.   printf(" 输入 q 或按 Ctrl+D 退出程序。\n");
  52.   printf(" 输入算式后按回车即可算出答案:\n\n");
  53.   while ((c = getop(s)) != EOF) {
  54.     switch (c) {
  55.     case NUMBER:
  56.       if (opnd->top > optor->top + 1) {        // 如果是逆波兰算式
  57.         printf("\tparse error\n");
  58.         while (getchar() != '\n')
  59.           /*void*/;
  60.         opnd->top = EMPTY;
  61.         era.nd = 0.0;
  62.       }
  63.       else
  64.         era.nd = atof(s);
  65.       push(era, opnd);
  66.       break;
  67.     case '+':            // + 和 - 优先级最低,把除了 '(' 以外的全部操作符弹出后入栈
  68.     case '-':
  69.       if (optor->top == EMPTY) {
  70.         era.tor = c;
  71.         push(era, optor);
  72.       }
  73.       else {
  74.         while (optor->top > EMPTY)
  75.           if (top_tor(optor) == '(')
  76.             break;
  77.           else {
  78.             era.nd = operate(opnd, optor);
  79.             push(era, opnd);
  80.           }
  81.         era.tor = c;
  82.         push(era, optor);
  83.       }
  84.       break;
  85.     case '*':                      // 乘除优先级最高,把相同优先级的乘和除弹出后入栈
  86.     case '/':
  87.       if (optor->top == EMPTY) {
  88.         era.tor = c;
  89.         push(era, optor);
  90.       }
  91.       else {
  92.         while (optor->top > EMPTY)
  93.           if (((era.tor = top_tor(optor)) == '+')
  94.               || (era.tor == '-')
  95.               || (era.tor == '('))
  96.             break;
  97.           else {
  98.             era.nd = operate(opnd, optor);
  99.             push(era, opnd);
  100.           }
  101.         era.tor = c;
  102.         push(era, optor);
  103.       }
  104.       break;
  105.     case '(':                // '(' 不作运算,直接放入optor栈。
  106.       era.tor = c;
  107.       push(era, optor);
  108.       break;
  109.     case ')':                // 把 '(' 之前的全部操作符弹出,计算后把 '(' 也弹出
  110.         while (optor->top > EMPTY)
  111.           if (top_tor(optor) == '(')
  112.             break;
  113.           else {
  114.             era.nd = operate(opnd, optor);
  115.             push(era, opnd);
  116.           }
  117.         pop(optor);
  118.       break;
  119.     case '\n':                // 把余下的操作符全部弹出,计算后输出结果
  120.       if (opnd->top == EMPTY)
  121.         /*do nothing*/;
  122.       else
  123.         while (optor->top > EMPTY)
  124.           if (top_tor(optor) == '(')
  125.             pop(optor);
  126.           else {
  127.             era.nd = operate(opnd, optor);
  128.             push(era, opnd);
  129.           }
  130.       era = pop(opnd);
  131.       printf("\t%.8g\n", era.nd);
  132.       break;
  133.     case 'p':
  134.       print_stack(opnd);
  135.       getchar();
  136.       break;
  137.     case 'q':
  138.       exit(0);
  139.       break;
  140.     default:
  141.       printf("error: unknown command %s\n", s);
  142.       break;
  143.     }
  144.   }
  145.   return 0;
  146. }
  147. struct Op *create_stack(int max, enum Optype type)
  148. {
  149.   struct Op *op;
  150.   op = malloc(sizeof(*op));
  151.   if (op == NULL)
  152.     nullerr();
  153.   op->era = calloc(sizeof(union Era), max);
  154.   if (op->era == NULL)
  155.     nullerr();
  156.   op->max = max;
  157.   op->top = EMPTY;
  158.   op->type = type;
  159.   return op;
  160. }
  161. void
  162. push(union Era era, struct Op *op)
  163. {
  164.   if (op->top >= op->max) {
  165.     if (op->type == ND)
  166.       printf("error: stack full, can't push %g\n", era.nd);
  167.     else
  168.       printf("error: stack full, can't push %c\n", era.tor);
  169.   }
  170.   else
  171.     op->era[op->top++] = era;
  172. }
  173. union Era
  174. pop(struct Op *op)
  175. {
  176.   if (op->top > EMPTY)
  177.     return op->era[--op->top];
  178.   else {
  179.     printf("error: stack empty\n");
  180.     if (op->type == ND)
  181.       op->era[EMPTY].nd = 0.0;
  182.     else
  183.       op->era[EMPTY].tor = 0;
  184.     return op->era[EMPTY];
  185.   }
  186. }
  187. void nullerr(void)
  188. {
  189.   printf("not enough memory\n");
  190.   exit(1);
  191. }
  192. int getop(char s[])        // [K&R] section 4.3
  193. {
  194.   int i, c;
  195.   while ((s[0] = c = getchar()) == ' ' || c == '\t')
  196.     /*do nothing*/;
  197.   s[1] = '\0';
  198.   if (!isdigit(c) && c != '.')
  199.     return c;                // not a number
  200.   i = 0;
  201.   if (isdigit(c))        // collect integer part
  202.     while (isdigit(s[++i] = c = getchar()))
  203.       ;
  204.   if (c == '.')                // collect fraction part
  205.     while (isdigit(s[++i] = c = getchar()))
  206.       /*do nothing*/;
  207.   s[i] = '\0';
  208.   if (c != EOF)
  209.     ungetc(c, stdin);
  210.   return NUMBER;
  211. }
  212. double operate(struct Op *opnd, struct Op *optor)
  213. {
  214.   union Era nd1, nd2, tor;
  215.   nd2 = pop(opnd);
  216.   nd1 = pop(opnd);
  217.   tor = pop(optor);
  218.   switch (tor.tor) {
  219.   case '+':
  220.     return nd1.nd + nd2.nd;
  221.     break;
  222.   case '-':
  223.     return nd1.nd - nd2.nd;
  224.     break;
  225.   case '*':
  226.     return nd1.nd * nd2.nd;
  227.     break;
  228.   case '/':
  229.     return nd1.nd / nd2.nd;
  230.     break;
  231.   default:
  232.     return 0.0;
  233.     break;
  234.   }
  235. }
  236. void print_stack(struct Op *op)
  237. {
  238.   int i;
  239.   for (i = op->top; i > 0; i--)
  240.     printf("%g\n", op->era[i].nd);
  241. }
  242. char top_tor(struct Op *op)
  243. {
  244.   return op->era[op->top-1].tor;        // after push, top plus one
  245. }
复制代码
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-4-28 13:43:27 | 显示全部楼层
多谢pointer提醒。我贴在上面了。
你那个程序怎么比我的短那么多!什么书里出来的?
我正在研究你这个程序,不知道为什么每次计算完都说syntax error:in factor
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-4-28 14:11:40 | 显示全部楼层
那程序就是用你所说的形式语言编的吧?比我的简短很多呀!

加减运算的函数调用乘除运算的函数,乘除运算的函数调用括号函数,括号函数又反过来调用加减运算的函数--如此形成递归!现在我只能这样大概理解,其中的细节和逻辑一时半刻搞不懂,先收藏,以后多学点递归再回头看。
回复 支持 反对

使用道具 举报

发表于 2006-4-28 16:14:36 | 显示全部楼层
形式语言可不是这玩儿
回复 支持 反对

使用道具 举报

发表于 2006-4-28 19:04:03 | 显示全部楼层
改BS的......
#include<iostream>
#include<map>
#include<string>
#include<cctype>
#include<math.h>
using namespace std;
class expr;
enum Token_value{
SQRT,SIN,COS,
NAME,NUMBER,END,
PLUS='+',MINUS='-',MUL='*',DIV='/',
PRINT=';',ASSIGN='=',LP='(',RP=')',MIN='^'
};
typedef double (*dfdp)(double);
dfdp math[]={sqrt,sin,cos};
int i;
typedef Token_value (expr::*get_token_p_p)();
get_token_p_p get_token_p;
class expr{
public:
expr(const char* str);
expr(void);
void jisuan(void);
double eval();
void print(){}

private:
int line_no;

string string_expr;
double (*dfddp)(double,double);
double number_value;
string string_value;
map<string,double> table;
Token_value curr_tok;
double my_expr(bool get);
double term(bool get);
double prim(bool get);
double min(bool get);
Token_value get_token(void);
Token_value get_token_ios(void);

double error(char *str);
};
expr::expr(void)
{
line_no=0;
i=-1;
number_value=0;
table["pi"]=3.1415;
table["e"]=2.718281;

}
expr::expr(const char* str)
{
string_expr=str;
expr();
}
double expr::error(char *str)
{
cerr<<"line:"<<line_no<<" "<<str<<endl;
return 1;
}
double expr::my_expr(bool get)
{
double left=term(get);
for(;;)
switch(curr_tok){
case PLUS:
left+=term(true);
break;
case MINUS:
left-=term(true);
break;
default:
return left;
}
}
double expr::term(bool get)
{
double left=min(get);
for(;;)
switch(curr_tok){
case MUL:
left*=min(true);
break;
case DIV:
if(double d=min(true)){
left/=d;
break;
}
return error("divide by 0");
default:
return left;
}
}
double expr::min(bool get)
{
double left=prim(get);
dfddp=pow;
for(;;)
{
switch(curr_tok){
case MIN:
left=dfddp(left,prim(true));
break;
case SQRT:
left=math[SQRT](left);
(this->*get_token_p)();
return left;
case SIN:
left=math[SIN](left);
(this->*get_token_p)();
return left;
case COS:
left=math[COS](left);
(this->*get_token_p)();
return left;
default:
return left;
}
}
}
double expr::prim(bool get)
{
if(get) (this->*get_token_p)();
switch(curr_tok){
case NUMBER:
{
double v=number_value;
(this->*get_token_p)();
return v;
}
case NAME:
{
if(strcmp(string_value.c_str(),"sqrt")==0)
{
(this->*get_token_p)();
if(curr_tok!=LP) return error("(expected");
double e=my_expr(true);
if(curr_tok!=RP) return error(")expected");
//get_token(); // delete RP;
curr_tok=SQRT;
return e;
}
else if(strcmp(string_value.c_str(),"sin")==0)
{
(this->*get_token_p)();
if(curr_tok!=LP) return error("( expected");
double e=my_expr(true);
if(curr_tok!=RP) return error(")expected");
curr_tok=SIN;
return e;
}
else if(strcmp(string_value.c_str(),"cos")==0)
{
(this->*get_token_p)();
if(curr_tok!=LP) return error("( expected");
double e=my_expr(true);
if(curr_tok!=RP) return error(")expected");
curr_tok=COS;
return e;
}
else {

double& v=table[string_value];
if((this->*get_token_p)()==ASSIGN)
{ line_no++; v=my_expr(true);}
return v;
}
}
case MINUS:
return -prim(true);
case LP:
{
double e=my_expr(true);
if(curr_tok!=RP) return error(")expected");
(this->*get_token_p)(); // delete RP;
return e;
}
return error("primay expected");
}
}
Token_value expr::get_token(void)
{
char ch=0;
double power=1;
number_value=0.0;
do{
if(!(ch=string_expr[++i])) return curr_tok=END;
}while(ch!='\n' && isspace(ch));
switch(ch){
case 0:
return curr_tok=END;
case ';':
case '*':
case '/':
case '+':
case '-':
case '(':
case ')':
case '=':
case '^':
return curr_tok=Token_value(ch);
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
//string_expr.putback(ch);
while((isdigit((int)ch)))
{
number_value=number_value*10+(ch-'0');
ch=string_expr[++i];
}
if(ch=='.')
ch=string_expr[++i];
while((isdigit((int)ch)))
{
number_value=number_value*10+(ch-'0');
ch=string_expr[++i];
power*=10;
}
i--;
number_value=number_value/power;
// cout<<number_value<<endl;
return curr_tok=NUMBER;
default:
if(isalpha(ch)){
string_value=ch;
while((ch=string_expr[++i]) && isalnum(ch)) string_value.push_back(ch);
i--;
return curr_tok=NAME;
}
//error("bad token");
return curr_tok=PRINT;
}
}
Token_value expr::get_token_ios(void)
{
char ch=0;
do{
if(!cin.get(ch)) return curr_tok=END;
}while(ch!='\n' && isspace(ch));
switch(ch){
case 0:
return curr_tok=END;
case ';':
case '*':
case '/':
case '+':
case '-':
case '(':
case ')':
case '=':
case '^':
return curr_tok=Token_value(ch);
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
cin.putback(ch);
cin>>number_value;
return curr_tok=NUMBER;
default:
if(isalpha(ch)){
string_value=ch;
while(cin.get(ch) && isalnum(ch)) string_value.push_back(ch);
cin.putback(ch);
return curr_tok=NAME;
}
//error("bad token");
return curr_tok=PRINT;
}
}
void expr::jisuan(void)
{
get_token_p=&expr::get_token_ios;
while(cin){
(this->*get_token_p)();
if(curr_tok==END)break;
if(curr_tok==PRINT)continue;
cout<<my_expr(false)<<'\n';
// cout<<number_value<<endl;
}
//return 0;
}
double expr::eval(void)
{
get_token_p=&expr::get_token;
//while(string_expr){
(this->*get_token_p)();
//if(curr_tok==END)break;
//if(curr_tok==PRINT)continue;
return my_expr(false);
// cout<<number_value<<endl;
// }
//return 0;
}
int main(void)
{ /*
expr x("123/3+123*4-3");
cout<<"x="<<x.eval()<<"\n";
x.print();
*/
expr a("1+3+9/3");
cout<<a.eval()<<endl;
a.jisuan();
}
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-4-28 21:24:42 | 显示全部楼层
没想到传说中的Lolita也光临本贴呀。

ywchen2000你那个是C++呀,我还没敢开始学。刚从china-pub买了The C++ Programming Language,天呀,怎么比K&R的TCPL厚那么多!看来不容易学。

贴代码用 [code] [/code]吧,那样就有缩进而且不会有表情也可以有框架以免太长。
回复 支持 反对

使用道具 举报

发表于 2006-4-28 23:36:34 | 显示全部楼层
kikiwarm:
你是怎么运行的呢? 我这儿是测试过可以的.
这个程序从标准输入读取, 写到标准输出.
如:

  1. ./cexp
  2. 1+2*3-4   <-这是输入, 按Enter, Ctrl-D
复制代码


程序摘自编译原理的龙书, 不过原书是转换为后缀表达式的地方换为计算了.
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表