怎么实现Linux下的逆波兰计算器dc?

 #返回上一级

@Author: 张海拔

@Update: 2014-01-12

@Link: http://www.cnblogs.com/zhanghaiba/p/3516660.html

 

  1 /*

  2  *Author: ZhangHaiba

  3  *Date: 2014-1-12

  4  *File: dc_linux.c

  5  *

  6  *a demo shows how to use a stack to implement dc which as a built-in tool in Linux

  7  *but, this demo only support int number and int operation + - * /

  8  */

  9 

 10 #include <stdio.h>

 11 #include <stdlib.h>

 12 #include <ctype.h>

 13 #define ST_LEN 1024 //the depth of stack

 14 #define BUF_SIZE 32

 15 #define NUM '0'

 16 

 17 //public from stack.h

 18 void push(int);

 19 int pop();

 20 int top();

 21 int is_empty();

 22 int is_full();

 23 void clear();

 24 //private form stack.c

 25 int stack[ST_LEN];

 26 int sp = 0; //point to next empty space

 27 

 28 //public form main.h

 29 int token();

 30 //public form main.c

 31 char buf[BUF_SIZE];

 32 int cnt = 0;

 33 

 34 int main(void)

 35 {

 36     int c;

 37     int op2, op1;

 38     

 39     while ((c = token()) != EOF) {

 40         switch(c) {

 41         case NUM:

 42             push(atoi(buf));

 43             break;

 44         case '+':

 45             if (size() >= 2) {

 46                 op2 = pop(), op1 = pop();

 47                 push(op1 + op2);

 48             } else

 49                 printf("dc: stack empty\n");

 50             break;

 51         case '-':

 52             if (size() >= 2) {

 53                 op2 = pop(), op1 = pop();

 54                 push(op1 - op2);

 55             } else

 56                 printf("dc: stack empty\n");

 57             break;

 58         case '*':

 59             if (size() >= 2) {

 60                 op2 = pop(), op1 = pop();

 61                 push(op1 * op2);

 62             } else

 63                 printf("dc: stack empty\n");

 64             break;

 65         case '/':

 66             if (size() >= 2) {

 67                 op2 = pop(), op1 = pop();

 68                 push(op1 / op2);

 69             } else

 70                 printf("dc: stack empty\n");

 71             break;

 72         case 'p':

 73             printf(is_empty() ? "dc: stack empty\n" : "%d\n", top());

 74         default:

 75             break;

 76         }

 77     }

 78     return 0;

 79 }

 80 

 81 int token()

 82 {

 83     int c = getchar();

 84     if (isdigit(c)) {

 85         buf[cnt++] = c;

 86         while ((c = getchar()) != EOF) {

 87             if (isdigit(c))

 88                 buf[cnt++] = c;

 89             else {

 90                 buf[cnt] = '\0';

 91                 cnt = 0;

 92                 ungetc(c, stdin);

 93                 return NUM;

 94             }

 95         }

 96     } else

 97         return c;

 98 }

 99 

100 void push(int item)

101 {

102     if (!is_full())

103         stack[sp++] = item;

104 }

105 

106 int pop()

107 {

108     if (!is_empty())

109         return stack[--sp];

110 }

111 

112 int top()

113 {

114     if (!is_empty())

115         return stack[sp-1];

116 }

117 

118 int is_full()

119 {

120     return sp >= ST_LEN;

121 }

122 

123 int is_empty()

124 {

125     return sp <= 0;

126 }

127 

128 int size()

129 {

130     return sp;

131 }

132 

133 void clear()

134 {

135     sp = 0;

136 }

 

Linux下有一个很强大计算器bc,而逆波兰计算器dc就是bc的后台。

逆波兰表达式(后缀表达式)不需要括号也不需要定义优先级就可以运算,dc就是用来处理这种“干净”的输入。

学习了栈这个数据结构,对于逆波兰表达式的计算是很容易的。

规则是:遇到操作数则压栈,遇到操作符则弹栈,先后弹出两个操作数,第一个是op2,第二是op1,然后根据操作符把计算结果再次压栈。所以栈顶值就是当前计算的结果。

 

这里的实现的简易dc,仅仅支持int整型,和int操作符+ - * /。

dc的用例如下(上述实现的简易版 dc,其测试用例同下):

432 13 * p
5616
3 p
3
* p
16848
* p
dc: stack empty
16848
42 / 4 p
4
p
4

 

上面的实现中,需要注意的是:

(1)数据封装方面,最好把stack做成一个单独模块,这样可以提供接口,隐藏stack数据本身。

(2)对于栈中元素<2时遇到操作符,不要执行单独一次的弹栈(即把两次弹栈看做一个原子操作,测试发现dc就是这样处理的)。

(3)由于输入数字不一定是一位数,所以需要一个buffer数组来存储多位数的字符表示并封装成字符串用标准库函数atoi转换,这个过程需要用ungetc(int, FILE*)来放回一个字符到缓冲区。

 

 #返回上一级

你可能感兴趣的:(linux)