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 mgetline 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(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;
}

From the mgetline 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