Exercise 4-4

Add commands to print the top element of the stack without popping, to duplicate it, and to swap the top two elements. Add a command to clear the stack.

First, let us lay the framework for implementing our commands. We can create functions for each command, and add cases for them by using letters. In addition, to make it easier to work with our stack operations, we will make it so that a newline only pops the top element if there is only one element in the stack. So for example, the input 1 1 1 would not cause any elements to be popped. This will not interfere with our existing operations since they pop out elements regardless of whether a newline is entered.

    ...
    int getop(char []);
    void push(double);
    double pop(void);
    void print_val(void);
    void duplicate(void);
    void swap(void);
    void clear(void);
    int getch(void);
    void ungetch(int);
    ...
    /* reverse Polish calculator */
    main()
    {
        int type;
        double op1, op2;
        char s[MAXOP];
    
        while ((type = getop(s)) != EOF) {
            switch (type) {
            ...
            case 'p':
                print_val();
                break;
            case 'd':
                duplicate();
                break;
            case 's':
                swap();
                break;
            case 'c':
                clear();
                break;
            case '\n':
                if (sp == 1)
                    printf("\t%.8g\n", pop());
                break;
            default:
                printf("error: unknown command %s\n", s);
                break;
            }
        }
        return 0;
    }
    ...

Let us first tackle print_val, which will print the top element of the stack. We make sure that the stack is not empty (by checking if sp is greater than zero), before printing val[sp - 1], which corresponds to the top element since sp is the next free position in the stack. In case the stack is empty, we print an error message.

    /* print_val:  print top element of value stack */
    void print_val(void)
    {
        if (sp > 0)
            printf("\t%.8g\n", val[sp - 1]);
        else
            printf("error: stack empty\n");
    }

In order to duplicate the top element, we first make sure that the stack is neither empty nor full. Afterward, we pop the top element of the stack and push it twice.

    /* duplicate:  duplicate top element of value stack */
    void duplicate(void)
    {
        if (sp > MAXVAL - 1) {
            printf("error: stack full, can't duplicate\n");
            return;
        } else if (sp <= 0) {
            printf("error: stack empty\n");
            return;
        }
        double temp = pop();
    
        push(temp);
        push(temp);
    }

Next, let us look at implementing the swap command. We first need to ensure that there are at least two elements in the stack. If the condition is satisfied, we pop the top two elements of the stack, and push them in reverse order.

    /* swap:  swap top two elements of value stack */
    void swap(void)
    {
        if (sp <= 1) {
            printf("swap: stack doesn't contain 2 elements\n");
            return;
        }
        double num_1 = pop();
        double num_2 = pop();
    
        push(num_1);
        push(num_2);
    }

Note: remember, stacks work by the last in, first out rule. A good way to visualize this is a stack of sheets. In order to swap the top two sheets, we take out sheet one and sheet two, before putting back sheet one first and then sheet two.

Finally, the clear function is by far the easiest. We do not need to actually clear the elements; instead, we set sp to zero, which means new elements that are pushed will simply override the existing values.

    /* clear:  clear value stack */
    void clear(void)
    {
        sp = 0;
    }