1. 程式人生 > >k&r中的逆波蘭表示法計算器

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;