如何在 RPN 计算器中处理负数

问题描述

这是 K&R 教科书中 rpn 计算器的代码,我想让计算器处理负数,我该怎么做?我尝试修改 case'-' 和 ggetop,因为我试图获取一个字符来检查它是否是数字,结果是 ggetop 和 ggetch 自动跳过了空格。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>

#define MAXVAL 100
#define MAXOP 100
#define NUMBER '0'
#define BUFSIZE 100

int sp = 0;
double val[MAXVAL];
char buf[BUFSIZE];
int bufp = 0;

double aatof(char []);
void push(double);
double pop(void);
int ggetop(char []);
int ggetch(void);
void unggetch(int);

int main()
{
    int type;
    double op2;
    int op3;
    char s[MAXOP];
    while ((type = ggetop(s)) != EOF)
    {
        switch (type)
        {
            case NUMBER:
                push(aatof(s));
                break;
            case '+':
                push(pop() + pop());
                break;
            case '*':
                push(pop() * pop());
                break;
            case '-':
                op3= ggetch();
                if (isdigit(ggetch())) {
                    printf("%s",s);
                    push(0 - aatof(s));
                    break;
                }
                else {
                    printf("%s",6);
                    op2 = pop();
                    push(pop() - op2);
                    break;
                }
            case '/':
                op2 = pop();
                if (op2 != 0.0)
                    push( pop() / op2);
                else
                    printf("error: zero divisor\n");
                break;
            case '%':
                op3 = (int)pop();
                if (op3 != 0)
                    push((int)pop() % op3);
                else
                    printf("error: zero divisor\n");
                break;
            case '\n':
                printf("\t%.8g\n",pop());
                break;
            default:
                printf("error: unkNown command %s\n",s);
                break;
        }
    }
    return 0;
}

int ggetop(char s[])
{
    int i,c;
    while ((s[0] = c = ggetch()) == ' ' || c == '\t')
        ;

    s[1] = '\0';
    if (!isdigit(c) && c != '.')
        return c;
    i = 0;
    if (isdigit(c))
        while (isdigit(s[++i] = c = ggetch()))
            ;
    if (c == '.')
        while (isdigit(s[++i] = c = ggetch()))
            ;
        s[i] = '\0';
    if (c != EOF)
        unggetch(c);
    return NUMBER;
}

int ggetch(void)
{
    return (bufp > 0) ? buf[--bufp] : getchar();
}

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

double aatof(char s[])
{
    double val,power;
    int i,sign;
    for (i = 0; isspace(s[i]); i++)
        ;
    sign = (s[i] == '-') ? -1 : 1;
    if (s[i] == '+' || s[i] == '-')
        i++;
    for (val = 0.0; isdigit(s[i]); i++)
        val = 10.0 * val + (s[i] - '0');
    if (s[i] == '.')
        i++;
    for (power = 1.0; isdigit(s[i]); i++)
    {
        val = 10.0 * val + (s[i] - '0');
        power *= 10.0;
    }
    return sign * val / power;
}

void push(double f)
{
    if (sp < MAXVAL)
        val[sp++] = f;
    else
        printf("error: stack full,can't push %g\n",f);
}

double pop(void)
{
    if (sp > 0)
        return val[--sp];
    else
    {
        printf("error: stack empty\n");
        return 0.0;
    }
}

解决方法

ggetop() 可以进行一些返工

int ggetop(char s[]) {
    ...
    // while ((s[0] = c = ggetch()) == ' ' || c == '\t');
    while (isspace( (c = ggetch()) )) ;

    // add
    int sign = c;
    if (sign == '-' || sign == '+') {
      c = ggetch();
    }
    
    ...
    return sign == '-' ? -NUMBER : NUMBER;
}