k&r中的逆波兰表示法计算器

    波兰表示法(Polish notation,或波兰记法),是一种逻辑、算术和代数表示方法,其特点是操作符置于操作数的前面,因此也称做前缀表示法。如果操作符的元数(arity)是固定的,则语法上不需要括号仍然能被无歧义地解析。波兰记法是波兰数学家扬·武卡谢维奇1920年代引入的,用于简化命题逻辑。
举个例子
      (3 + 4)*8 用逆波兰表示法表示为:3 4 + 8 *

先引用下:

从左至右扫描表达式,遇到数字时,将数字压入堆栈(stack.c),遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 op 栈顶元素),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果。
例如后缀表达式“3 4 + 5 × 6 -”:
(1) 从左至右扫描,将3和4压入堆栈;
(2) 遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素,注意与前缀表达式做比较),计算出3+4的值,得7,再将7入栈;
(3) 将5入栈;
(4) 接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈;
(5) 将6入栈;
(6) 最后是-运算符,计算出35-6的值,即29,由此得出最终结果。

地址:https://blog.csdn.net/antineutrino/article/details/6763722

思路就是这样子的:

关于堆栈

就是定义一个外部数组(   double val[MAXVAL]  ),这个就是上面说的堆栈了,用来存操作数,再定义一个变量( int sp;)来记录栈顶的位置,void push(double f)就是用来存操作数的,double pop(void) 用来返回栈顶的操作数,

#define MAXVAL 100   /* maxinum depth of val stack */

double pop(void);

int sp=0;        /* next free stack position */
double val[MAXVAL];    /* value stack */
 
/*push: push f onto value stack */
void push(double f)
{
     if (sp < MAXVAL)
        val[sp++] = f;
    else
        printf("eorror: stack full,can not push %g\
n",f); 
}
 
 /* pop: pop and return top value form stack */
double pop(void)
{
     if( sp > 0)
         return val[--sp];
     else
     {
         printf("error : stack empty\n");
         return 0.0;
    } 
}

然后怎么输入呢?

先看一下main函数

int main(void)

    
    int type;
    double op2;
    char s[MAXOP];

    
    clearStacks(var);
    while((type = getop(s)) != EOF)
    {
        switch(type)
        {
            case NUMBER:               //NUMBER    '0'   表示是s[]中存的是数字字符串
                push(atof(s));                   //atof(s)将数字字符串转换成对应的double型数值(10进制)
                break;
            case '+':
                push(pop() + pop());
                break;
            case '*':
                push(pop() * pop());
                break;
            case '-':
                op2 = pop();
                push(pop()- op2);
                break;
            case '/':
                op2 = pop();
                if(op2 != 0.0)
                    push(pop() / op2);
                else
                    printf("error: zero divisor\n");
                break;               
            case '\n':
                printf("\t%.8g\n",pop());
                break;
            default :
                printf("error: unknown command %s\n");
                break;
        }
    }
    return EXIT_SUCCESS;
}

int getch(void);        /* in getch.c */
void ungetch(int c);    /* in getch.c */

/*getop: get next character or numeric operand */
int getop(char s[])
{
    int i = 0;
    int c;
    int next;
    
    /* skip whitespace */
    while((s[0] = c = getch()) == ' '|| c == '\t')
        ;
    s[1] = '\0';
       
    /* Not a number but may contain a unary minus. */
    if (!isdigit(c) && c != '.' && c != '-')
        return c;           /* not a number */
    if(c == '-')
    {
        next = getch();
        if(!isdigit(next) && next != '.' )
        {
            return c;
        }
        c = next;
    }
    else
    {
        c = getch();
    }
    
    while(isdigit(s[++i] = c))
            c = getch();
    if(c == '.')
        while(isdigit(s[++i] = c = getch())) 
            ;
    s[i] = '\0';
    if( c != EOF)
        ungetch(c);
    return NUMBER;    
}

char buf[BUFSIZE];     /* buffer for ungetch    缓存区 */
int bufp = 0;

int getch(void)        /*get a (possibly pushed-back) charater */
{
        return (bufp > 0) ? buf[--bufp] : getchar();
}

void ungetch(int c)
{
    if(bufp >= BUFSIZE)
        printf(" ungetch : too many characters \n");
    else
        buf[bufp++] = c;
}

这就是基本的框架了。


下面是扩展一些功能的代码
/***********************
***  calcu.h         ***
************************/
#define TURE 1
#define FLASE 0 
#define IDENTIFIER 1
#define NUMBER '0'        /*signal that a number was found */
#define MAX_ID_LEN 32
#define MAXVARS    30

struct varType{
    char name[MAX_ID_LEN];
    double val;
};

extern int pos;
extern struct varType last;

                                            
/***********************
***  main.c          ***
************************/
#include<stdio.h>
#include<math.h>
#include<stdlib.h>   /*for atof(), EXIT_SUCCESS*/
#include"calcu.h"

#define MAXOP 100         /*max size of operand or operator */
#define ENDSTRING     2
#define MAXVARS    30 
#define MAX_ID_LEN 32

int getop(char []);
void push(double);
double pop(void);
void showtop(void);
void duplicate(void);
void swapitems(void);
void clearStacks(struct varType var[]);
void DealWithName(char s[],struct varType var[]);

struct varType last;

/* reverse Polish calculator */
int main(void)

    
    int type;
    double op2;
    char s[MAXOP];
    struct varType var[MAXVARS];
    
    clearStacks(var);
    while((type = getop(s)) != EOF)
    {
        switch(type)
        {
            case NUMBER:
                push(atof(s));
                break;
            case IDENTIFIER:
                DealWithName(s, var);
                break; 
            case '+':
                push(pop() + pop());
                break;
            case '*':
                push(pop() * pop());
                break;
            case '-':
                op2 = pop();
                push(pop()- op2);
                break;
            case '/':
                op2 = pop();
                if(op2 != 0.0)
                    push(pop() / op2);
                else
                    printf("error: zero divisor\n");
                break;
            case '%':
                op2 = pop();
                if(op2 != 0.0)
                    push(fmod(pop(),op2));
                else
                    printf("error : zero divisor\n");
                break;
            case '#':
                duplicate();
                break;
            case '!':
                clearStacks(var);
                break;
            case '~':
                swapitems();
                break;                 
            case '\n':
                showtop();
                break;
            case ENDSTRING:
                break;
            case '=':
                var[pos].val = pop();
                last.val = var[pos].val;
                push(last.val);
                break;
            default :
                printf("error: unknown command %s\n");
                break;
        }
    }
    return EXIT_SUCCESS;
}

/**************************
*** stack.c                ***
***************************/
#include<stdio.h>
#include"calcu.h"

#define MAXVAL 100   /* maxinum depth of val stack */

double pop(void);

int sp=0;        /* next free stack position */
double val[MAXVAL];    /* value stack */
 
/*push: push f onto value stack */
void push(double f)
{
     if (sp < MAXVAL)
        val[sp++] = f;
    else
        printf("eorror: stack full,can not push %g\n",f); 
}
 
 /* pop: pop and return top value form stack */
double pop(void)
{
     if( sp > 0)
         return val[--sp];
     else
     {
         printf("error : stack empty\n");
         return 0.0;
    } 
}
void showtop(void)
{
    double item = pop();
    printf("Top of stack contains: %.8g\n",item);
    push(item);

void duplicate(void)
{
    double temp = pop();
    
    push(temp);
    push(temp);
}
void swapitems(void)
{
    double temp1 = pop();
    double temp2 = pop();

    push(temp1);
    push(temp2);
}

/* pop only returns a value if sp is greater than zero. So setting the
stack pointer to zero will cause pop to return its error */
/* Altered to clear both the main stack and that of the variable
structure */
void clearStacks(struct varType var[])
{
    int i;

/* Clear the main stack by setting the pointer to the bottom. */    
    sp = 0;

/* Clear the variables by setting the initial element of each name
   to the terminating character. */
   for( i = 0;i < MAXVARS; ++i)
   {
           var[i].name[0] = '\0';
        var[i].val = 0.0; 
   }
    
}

/**********************************
****getch.c                        ***
***********************************/
#include<string.h>
#include<stdio.h>

#define BUFSIZE 100 

    char buf[BUFSIZE];     /* buffer for ungetch */
    int bufp = 0;

    int getch(void)        /*get a (possibly pushed-back) charater */
    {
        return (bufp > 0) ? buf[--bufp] : getchar();
}

void ungetch(int c)
{
    if(bufp >= BUFSIZE)
        printf(" ungetch : too many characters \n");
    else
        buf[bufp++] = c;
}

void ungets(const char *s)
{
    int i = strlen(s);
    
    while(i > 0)
    {
        ungetch(s[--i]);
     } 
 }  


/************************************
****  getop.c                           ***
*************************************/
#include<stdio.h>
#include<ctype.h>
#include"calcu.h"    

int getch(void);        /* in getch.c */
void ungetch(int c);    /* in getch.c */

/*getop: get next character or numeric operand */
int getop(char s[])
{
    int i = 0;
    int c;
    int next;
    
    /* skip whitespace */
    while((s[0] = c = getch()) == ' '|| c == '\t')
        ;
    s[1] = '\0';
    
    if(isalpha(c))
    {
        i=0;
        while(isalpha(s[i++] = c))
            c = getch();
        s[i-1] = '\0';
        if(c != EOF)
            ungetch(c);
        return IDENTIFIER;
    }
    
    /* Not a number but may contain a unary minus. */
    if (!isdigit(c) && c != '.' && c != '-')
        return c;           /* not a number */
    if(c == '-')
    {
        next = getch();
        if(!isdigit(next) && next != '.' )
        {
            return c;
        }
        c = next;
    }
    else
    {
        c = getch();
    }
    
    while(isdigit(s[++i] = c))
            c = getch();
    if(c == '.')
        while(isdigit(s[++i] = c = getch())) 
            ;
    s[i] = '\0';
    if( c != EOF)
        ungetch(c);
    return NUMBER;    
}

/***********************************
*** dealwith.c                     ***
************************************/
#include"calcu.h"
#include<string.h>
#include<math.h>

#define MAXVARS    30

int pos = 0;
extern struct varType last;

void DealWithVar(char s[],struct varType var[]);
int pop(void);
void push(double f);

/* deal with a string/name this may be either a maths function or for
future exercises: a variable */
/* a string/name may be either a maths function or a variable */
void DealWithName(char s[],struct varType var[]) 
{
    double op2;
    
    if(0 == strcmp(s ,"sin"))
        push(sin(pop()));
    else if(0 == strcmp(s ,"cos"))
        push(cos(pop()));
    else if(0 == strcmp(s ,"exp"))
        push(exp(pop()));
    else if(0 == strcmp(s ,"pow"))
    {
        op2 = pop();
        push(pow(pop() ,op2));
    }
    /* Finally if it isn't one of the supported maths functions we have a 
      variable to deal with. */
    else
    {
        DealWithVar(s,var); 
    }
}

/* Our identifier is not one of the supported maths function so we have 
   to regard it as an identifier. */
void DealWithVar(char s[],struct varType var[])
{
    int i = 0;
    
    while(var[i].name[0] != '\0' && i < MAXVARS-1)
    {
        if(!strcmp(s, var[i].name))
        {
            strcpy(last.name, s);
            last.val = var[i].val;
            push(var[i].val);
            pos = i;
            return;
        }
        i++;
    }
    
    /* variable name not found so add it */
    strcpy(var[i].name, s);
    /* and save it to last variable*/
    strcpy(last.name, s);
    push(var[i].val);
    pos = i;


 

猜你喜欢

转载自blog.csdn.net/qq_40691051/article/details/81611788