Exercise 4.10 - Calculator using getline

Question

An alternate organization uses getline to read an entire input line; this makes getch and ungetch unnecessary. Revise the calculator to use this approach.

/**
 * Revise the Calculator program to use the getline instead of getch and ungetch
 **/

#include<stdio.h>
#include<stdlib.h> /* for atof() */

#define MAXOP 100
#define NUMBER '0'

int getop(char []);

void push(double);

double pop(void);

/* reverse polish notation calculator */

int main(void) {
    int type;
    double op2;
    char s[MAXOP];

    while ((type = getop(s)) != EOF) {
        switch (type) {
            case 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);
                break;
            case '\n':
                printf("\t%.9g\n", pop());
                break;
            default:
                printf("error: unknown command %s\n", s);
                break;
        }
    }
    return 0;
}

#define MAXVAL 100 /* maximum depth of the val stack */

int sp = 0;
double val[MAXVAL];

/* push : push f onto value stack */

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

/* pop: pop and return top values from stack */

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


/* using getline instead of getch and ungetch */

#include<ctype.h>

#define MAXLINE 100

int mgetline(char line[], int limit);

int li = 0;  /* input line index */
char line[MAXLINE];  /* one input line */

/* getop: get next operator or numeric operand */

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

    if (line[li] == '\0')
        if (mgetline(line, MAXLINE) == 0)
            return EOF;
        else
            li = 0;

    while ((s[0] = c = line[li++]) == ' ' || c == '\t');

    s[1] = '\0';

    if (!isdigit(c) && c != '.')
        return c;

    i = 0;

    if (isdigit(c))
        while (isdigit(s[++i] = c = line[li++]));
    if (c == '.')
        while (isdigit(s[++i] = c = line[li++]));

    s[i] = '\0';

    li--;

    return NUMBER;
}

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

    for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
        s[i] = c;

    if (c == '\n')
        s[i++] = c;

    s[i] = '\0';

    return i;
}


		

Explanation

This program uses _getline to get the characters and operands from the input and and proceeds with the RPN calculator logic.

This is the main part of the program.

/* getop: get next operator or numeric operand */

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

        if(line[li] == '\0')
                if(_getline(line,MAXLINE) == 0)
                        return EOF;
                else
                        li =0;

        while((s[0] = c = line[li++]) == ' ' || c == '\t')
                ;

        s[1] = '\0';

        if(!isdigit(c) && c!= '.')
                return c;

        i = 0;

        if(isdigit(c))
                while(isdigit(s[++i] = c = line[li++]))
                        ;
        if( c == '.')
                while(isdigit(s[++i] = c = line[li++]))
                        ;

        s[i] = '\0';

        li--;

        return NUMBER;
}

From the _getline function, it takes the input in the line character array, and if if the line is 0 only, then we define that as EOF and return EOF. Then we assign to c the value present at line and look for various conditions like, if line is a space or tab character, we simply skip it. If we encouter c which is not a digit or not a . character, we return c immediately. At the end if it is valid number, we return a NUMBER, which is then pushed onto the stack of the RPN calculator.

An example execution will look like this.

10 10 +
        20
10.1 20.2 +
        30.3

Visualize It

Try It