ckernighan-and-ritchierpn

RPN in "The C Programming Language" book 2nd edition section 4.3, numbers not being pushed to stack


I have been reading through the C programming Langauge book and in section 4.3 I am trying to compile and run the code thats provided in pages 76-79. I think I have done exactly what is in the textbook, but its not working as it should.

From some printf's i have found that the numbers that are inputted are not actually being pushed to the stack in val[sp]. instead, when printing out the number, it shows a 0.

Also, the spaces aren't being skipped in

while((s[0] = c = getch()) == ' ' || c == '\t'{
    ;
}

and so the getop() treats them as a non digit and just returns the space. Because of this the output just prints error unknown command when the spaces are being read.

Also, the '+' is not being read as a command! So it just returns error unknown command when the program encounters it. I am at a loss as how this is happening given I have copied word for word in the textbook and ran it. I am not sure if this code is out of date and doesn't run on newer machines as well. I am also using CodeBlocks to run this if that helps.

Any help is greatly appreciated!

Here's my code

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


#define MAXOP 100
#define NUMBER '0'


int getop(char[]);
void push(double);
double pop(void);




int main()
{
    //extern double val[MAXVAL];
    int type;
    double op2;
    char s[MAXOP];

    while((type = getop(s)) != EOF){
        switch(type){
        case NUMBER:
            puts("a number");
            push(atof(s));
            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 division");
            }
            break;

        case '\n':
            printf("\t%.8g\n", pop());
            break;
        default:
            printf("error unknown command %s\n", s);
            break;

        }
    }
    printf("Hello world!\n");
    return 0;
}

#define MAXVAL 100
int sp = 0;
double val[MAXVAL];

void push(double f)
{
    //extern int sp;
    //extern double val[MAXVAL];

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

double pop(void)
{
    //extern int sp;
    //extern double val[MAXVAL];

    if(sp > 0){
        return val[--sp];
    }
    else{
        printf("stack is empty\n");
        return 0.0;
    }
}

int getch(void);
void ungetch(int c);

int getop(char s[])
{
    int i, c;

    while((s[0] = c = getch()) == ' ' || c == '\t'){
        ;
    }

    s[1] = '\0';
    if(!isdigit(c) && c != '.'){
        printf("%c", c);
        return c;
    }
    i = 0;
    if(isdigit(c)){
        while(isdigit(s[i++] = c = getch())){
            ;
        }
    }
    if(c == '.'){
        while(isdigit(s[i++] = c = getch())){
            ;
        }
    }
    s[i] = '\0';
    if(c != EOF){
        ungetch(c);
    }
    return NUMBER;
}

#define BUFSIZE 100
char buf[BUFSIZE];
int bufp = 0;

int getch(void)
{
    //extern int bufp;
    //extern char buf[BUFSIZE];

    return (bufp > 0) ? buf[--bufp] : getchar();
}

void ungetch(int c)
{
    //extern int bufp;
    //extern char buf[BUFSIZE];

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

and the output for 3 4 + 1

I have tried to print out each part (the number when it is being pushed) and also print out the '+' to see if it is actually being returned as '+'. It is, and I am at a loss as how this is happening.


Solution

  • One problem is that your code has:

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

    The book (p79) has:

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

    The difference between ++bufp and bufp++ is critical.

    It isn't the only problem, but things are closer to working when that's fixed.

    It is crucial that:

    1. You copy code accurately.
    2. You understand the difference between ++x and x++.

    With those extra fixes — meaning changing your code to match what's in the book — the code seems to work, at least on the input 3 4 +.