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