您的位置:首页 > 运维架构 > Linux

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

2014-01-12 22:41 639 查看
#返回上一级

@Author: 张海拔

@Update: 2014-01-12

@Link: http://www.cnblogs.com/zhanghaiba/p/3516660.html
/*
*Author: ZhangHaiba
*Date: 2014-1-12
*File: dc_linux.c
*
*a demo shows how to use a stack to implement dc which as a built-in tool in Linux
*but, this demo only support int number and int operation + - * /
*/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define ST_LEN 1024 //the depth of stack
#define BUF_SIZE 32
#define NUM '0'

//public from stack.h
void push(int);
int pop();
int top();
int is_empty();
int is_full();
void clear();
//private form stack.c
int stack[ST_LEN];
int sp = 0; //point to next empty space

//public form main.h
int token();
//public form main.c
char buf[BUF_SIZE];
int cnt = 0;

int main(void)
{
int c;
int op2, op1;

while ((c = token()) != EOF) {
switch(c) {
case NUM:
push(atoi(buf));
break;
case '+':
if (size() >= 2) {
op2 = pop(), op1 = pop();
push(op1 + op2);
} else
printf("dc: stack empty\n");
break;
case '-':
if (size() >= 2) {
op2 = pop(), op1 = pop();
push(op1 - op2);
} else
printf("dc: stack empty\n");
break;
case '*':
if (size() >= 2) {
op2 = pop(), op1 = pop();
push(op1 * op2);
} else
printf("dc: stack empty\n");
break;
case '/':
if (size() >= 2) {
op2 = pop(), op1 = pop();
push(op1 / op2);
} else
printf("dc: stack empty\n");
break;
case 'p':
printf(is_empty() ? "dc: stack empty\n" : "%d\n", top());
default:
break;
}
}
return 0;
}

int token()
{
int c = getchar();
if (isdigit(c)) {
buf[cnt++] = c;
while ((c = getchar()) != EOF) {
if (isdigit(c))
buf[cnt++] = c;
else {
buf[cnt] = '\0';
cnt = 0;
ungetc(c, stdin);
return NUM;
}
}
} else
return c;
}

void push(int item)
{
if (!is_full())
stack[sp++] = item;
}

int pop()
{
if (!is_empty())
return stack[--sp];
}

int top()
{
if (!is_empty())
return stack[sp-1];
}

int is_full()
{
return sp >= ST_LEN;
}

int is_empty()
{
return sp <= 0;
}

int size()
{
return sp;
}

void clear()
{
sp = 0;
}


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*)来放回一个字符到缓冲区。

#返回上一级
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: