Exercise 4-3. Given the basic framework, it's straightforward to extend the calculator. Add the modulus (%) operator and provisions for negative numbers.
1 2 +
1 2 * 3 + 5 -
-1 2 +
-1 -2 -
4 3 %
2 0 %
1 3 /
1 0 /
#include <stdio.h> // for printf(), getchar(), EOF
#include <stdlib.h> // for atof()
#define MAXOP 100 // max size of operand or operator
#define NUMBER '0' // signal that a number has been found
int getop(char []); // get the next operand or operator
void push(double); // push operand on stack
double pop(void); // pop operand from stack
int main()
{
int type, i1, i2;
double op2; // second operand for -, /, %
char s[MAXOP]; // operand or operator
while((type = getop(s)) != EOF && type != '\0')
{ // nonempty line ending with EOF will not be executed
switch(type)
{
case NUMBER :
push(atof(s));
break;
case '+' :
push(pop() + pop());
break;
case '-' :
op2 = pop();
push(pop() - op2);
break;
case '*' :
push(pop() * pop());
break;
case '/' :
op2 = pop();
if (op2 != 0.0)
{push(pop() / op2);}
else {printf("Error: zero divisor\n");}
break;
case '%' :
i2 = pop(); // automatic conversions
i1 = pop(); // from double to int
if (i2 != 0.0)
{push(i1 % i2);} // auto conversion from int to double, arg of push()
else {printf("Error: zero divisor\n");}
break;
case '\n' :
printf("\t%.8g\n", pop()); // top of stack
break;
default :
printf("Unknown command: %s\n", s);
break;
}
}
return 0;
}
#define MAXVAL 100 // stack size
// stack pointer (0 is top of stack):
int sp = 0; // next free stack position
double val[MAXVAL]; // value stack
void push(double f) // push f on (top of) stack
{
if (sp < MAXVAL) {val[sp++] = f;}
else {printf("Error: stack full, can't push %g\n", f);}
}
double pop(void) // pop and return top value from stack
{
if (sp > 0) {return val[--sp];}
else
{
printf("Error: stack empty\n");
return 0.0;
}
}
#include <ctype.h> // for isdigit()
int getch(void);
void ungetch(int);
int getop(char s[]) // get next operator or numeric operand
{
int c, i;
while ((s[0] = c = getch()) == ' ' || c == '\t') // skip beginning ' ', '\t'
{} // last value read in s[0] is not ' ' or '\t', but could be '\n' or EOF
s[1] = '\0'; // end string
if (!isdigit(c) && c != '.' && c != '+' && c != '-')
{return c;} // not a number, probably an operator (or '\n' or '\0' or EOF)
// here c is digit or '.' or '+' or '-'
i = 0;
if (c == '+' || c == '-') // unary or binary sign
{
c = getch();
if (!isdigit(c) && c != '.')
{
ungetch(c);
return s[0]; // binary '+' or '-'
}
else // c is digit or '.'
{
if (s[i] == '-') {i++;} // s[0]
// if (s[i] == '+') {} // skip adding '+' to s[]
s[i] = c; // digit or '.'
}
}
if (isdigit(c)) // collect integer part
{ // s[i] contains c (digit)
while (isdigit(s[++i] = c = getch()))
{}
} // here s[i] is not a digit
if (c == '.') // collect fraction part
{ // s[i] contains c (s[i] == '.')
while (isdigit(s[++i] = c = getch()))
{}
} // here s[i] is not a digit
s[i] = '\0'; // end string containing number (operand)
if (c != EOF) {ungetch(c);} // cannot ungetch(EOF) as EOF is not a char
else {ungetch('\0');} // EOF or '\0' returned by getop() will end the program
return NUMBER;
}
#define BUFSIZE 100
char buf[BUFSIZE]; // buffer for ungetch()
// buf[] pointer (0 is top of buf):
int bufp = 0; // next free position in buf[]
int getch(void) // get a (possibly pushed-back) character
{
return (bufp > 0) ? buf[--bufp] : getchar();
}
// push character back on input (make it available for the next getch()):
void ungetch(int c)
{
if (bufp >= BUFSIZE)
{printf("ungetch(): too many characters\n");}
else {buf[bufp++] = c;}
}
/*
gcc calc.c -o calc
./calc
1 2 +
3
1 2 + 3 * 4 /
2.25
-1 2 +
1
-1 -2 +
-3
-1 2 + 3 *
3
2 0 /
Error: zero divisor
2 // pop() called by '\n' returns first operand, still on stack
1 2 /
0.5
2 3 %
2
4 2 %
0
4 1 %
0
4 3 %
1
4 0 %
Error: zero divisor
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
a b +
Unknown command: a
Unknown command: b
Error: stack empty // nothing pushed, pop() called by +
Error: stack empty // pop() called by '\n'
0 // value returned by pop() for an empty stack
1 2 9
9 // pop() called by '\n'
+
3 // 1 + 2
1 2 c
Unknown command: c
2 // pop() called by '\n'
3 +
4 // 1 + 3
CTRL^D (EOF) or CTRL^C in Linux, CTRL^Z + Enter in Windows
./calc < compute.txt
3 // 1 2 +
0 // 1 2 * 3 + 5 -
1 // -1 2 +
1 // -1 -2 -
1 // 4 3 %
Error: zero divisor // 2 0 %
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
0.33333333 // 1 3 /
Error: zero divisor // 1 0 /
1 // pop() called by '\n' returns first operand, still on stack
*/
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
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.
#include <stdio.h> // for printf(), getchar(), EOF
#include <stdlib.h> // for atof()
#define MAXOP 100 // max size of operand or operator
#define NUMBER '0' // signal that a number has been found
int getop(char []); // get the next operand or operator
void push(double); // push operand on stack
double pop(void); // pop operand from stack
int main()
{
int type, i1, i2;
double op1, op2; // operands
char s[MAXOP]; // operand or operator
extern int sp; // global var (stack pointer)
extern double val[]; // global var (stack)
while((type = getop(s)) != EOF && type != '\0')
{ // nonempty line ending with EOF will not be executed
switch(type)
{
case NUMBER :
push(atof(s));
break;
case '+' :
push(pop() + pop());
break;
case '-' :
op2 = pop();
push(pop() - op2);
break;
case '*' :
push(pop() * pop());
break;
case '/' :
op2 = pop();
if (op2 != 0.0)
{push(pop() / op2);}
else {printf("Error: zero divisor\n");}
break;
case '%' :
i2 = pop(); // automatic conversions
i1 = pop(); // from double to int
if (i2 != 0.0)
{push(i1 % i2);} // auto conversion from int to double, arg of push()
else {printf("Error: zero divisor\n");}
break;
case 'p' : // print top of stack without popping
if (sp > 0)
{
printf("top of stack: %g\n", val[sp-1]);
}
else
{
printf("Error: stack empty\n");
}
break;
case 'd' : // duplicate top of stack (push top of stack)
op1 = pop();
push(op1);
push(op1);
break;
case 's' : // swap the top elements on stack
op1 = pop();
op2 = pop();
push(op1);
push(op2);
break;
case 'c' : // clear the stack
sp = 0; // reset stack pointer
break;
case '\n' :
printf("\t%.8g\n", pop()); // top of stack
break;
default :
printf("Unknown command: %s\n", s);
break;
}
}
return 0;
}
#define MAXVAL 100 // stack size
// stack pointer (0 is top of stack):
int sp = 0; // next free stack position
double val[MAXVAL]; // value stack
void push(double f) // push f on (top of) stack
{
if (sp < MAXVAL) {val[sp++] = f;}
else {printf("Error: stack full, can't push %g\n", f);}
}
double pop(void) // pop and return top value from stack
{
if (sp > 0) {return val[--sp];}
else
{
printf("Error: stack empty\n");
return 0.0;
}
}
#include <ctype.h> // for isdigit()
int getch(void);
void ungetch(int);
int getop(char s[]) // get next operator or numeric operand
{
int c, i;
while ((s[0] = c = getch()) == ' ' || c == '\t') // skip beginning whitespace (' ', '\t')
{} // last value read in s[0] is not ' ' or '\t', but could be '\n' or EOF
s[1] = '\0'; // end string
if (!isdigit(c) && c != '.' && c != '+' && c != '-')
{return c;} // not a number, probably an operator (or '\n' or '\0' or EOF)
// here c is digit or '.' or '+' or '-'
i = 0;
if (c == '+' || c == '-') // unary or binary sign
{
c = getch();
if (!isdigit(c) && c != '.')
{
ungetch(c);
return s[0]; // binary '+' or '-'
}
else // c is digit or '.'
{
if (s[i] == '-') {i++;} // s[0]
// if (s[i] == '+') {} // skip adding '+' to s[]
s[i] = c; // digit or '.'
}
}
if (isdigit(c)) // collect integer part
{ // s[i] contains c (digit)
while (isdigit(s[++i] = c = getch()))
{}
} // here s[i] is not a digit
if (c == '.') // collect fraction part
{ // s[i] contains c (s[i] == '.')
while (isdigit(s[++i] = c = getch()))
{}
} // here s[i] is not a digit
s[i] = '\0'; // end string containing number (operand)
if (c != EOF) {ungetch(c);} // cannot ungetch(EOF) as EOF is not a char
else {ungetch('\0');} // EOF or '\0' returned by getop() will end the program
return NUMBER;
}
#define BUFSIZE 100
char buf[BUFSIZE]; // buffer for ungetch()
// buf[] pointer (0 is top of buf):
int bufp = 0; // next free position in buf[]
int getch(void) // get a (possibly pushed-back) character
{
return (bufp > 0) ? buf[--bufp] : getchar();
}
// push character back on input (make it available for the next getch()):
void ungetch(int c)
{
if (bufp >= BUFSIZE)
{printf("ungetch(): too many characters\n");}
else {buf[bufp++] = c;}
}
/*
gcc stackops.c -o stackops
./stackops
1 2 +
3
1 2 + d + // 1+2 == 3, duplicate
6 // 3+3
1 2 + 3 * 4 /
2.25
-1 2 +
1
1 2 -
-1 // 1-2
1 2 s -
1 // 2-1
-1 -2 +
-3
-1 2 + 3 *
3
2 0 /
Error: zero divisor
2 // pop() called by '\n' returns first operand, still on stack
1 2 /
0.5
2 3 %
2
4 2 %
0
4 1 %
0
4 3 %
1
4 0 %
Error: zero divisor
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
a b +
Unknown command: a
Unknown command: b
Error: stack empty // nothing pushed, pop() called by +
Error: stack empty // pop() called by '\n'
0 // value returned by pop() for an empty stack
1 2 9
9 // pop() called by '\n'
+
3 // 1 + 2
1 2 3 s d p // swap(2,3), duplicate 2, print 2
top of stack: 2
2
p
top of stack: 2
2
p
top of stack: 3
3
p
top of stack: 1
1
p
Error: stack empty
Error: stack empty
0
1 2 3 c // clear stack
Error: stack empty // pop() called by '\n'
0 // value returned by pop() for empty stack
CTRL^D (EOF) or CTRL^C in Linux, CTRL^Z + Enter in Windows
./stackops < compute.txt
3 // 1 2 +
0 // 1 2 * 3 + 5 -
1 // -1 2 +
1 // -1 -2 -
1 // 4 3 %
Error: zero divisor // 2 0 %
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
0.33333333 // 1 3 /
Error: zero divisor // 1 0 /
1 // pop() called by '\n' returns first operand, still on stack
*/
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
Exercise 4-5. Add access to library functions like sin(), exp(), and pow(). See <math.h> in Appendix B, Section 4.
#include <stdio.h> // for printf(), getchar(), EOF
#include <stdlib.h> // for atof()
#include <math.h> // for sin(), exp(), pow()
#define MAXOP 100 // max size of operand or operator
#define NUMBER '0' // signal that a number has been found
int getop(char []); // get the next operand or operator
void push(double); // push operand on stack
double pop(void); // pop operand from stack
int main()
{
int type, i1, i2;
double op2; // operand
char s[MAXOP]; // operand or operator
while((type = getop(s)) != EOF && type != '\0')
{ // nonempty line ending with EOF will not be executed
switch(type)
{
case NUMBER :
push(atof(s));
break;
case '+' :
push(pop() + pop());
break;
case '-' :
op2 = pop();
push(pop() - op2);
break;
case '*' :
push(pop() * pop());
break;
case '/' :
op2 = pop();
if (op2 != 0.0)
{push(pop() / op2);}
else {printf("Error: zero divisor\n");}
break;
case '%' :
i2 = pop(); // automatic conversions
i1 = pop(); // from double to int
if (i2 != 0.0)
{push(i1 % i2);} // auto conversion from int to double, arg of push()
else {printf("Error: zero divisor\n");}
break;
case 's' : // sin()
push(sin(pop()));
break;
case 'e' : // exp(x), exponential function e^x
push(exp(pop()));
break;
case 'p' : // pow(x,y)
op2 = pop();
push(pow(pop(), op2));
break;
case '\n' :
printf("\t%.8g\n", pop()); // top of stack
break;
default :
printf("Unknown command: %s\n", s);
break;
}
}
return 0;
}
#define MAXVAL 100 // stack size
// stack pointer (0 is top of stack):
int sp = 0; // next free stack position
double val[MAXVAL]; // value stack
void push(double f) // push f on (top of) stack
{
if (sp < MAXVAL) {val[sp++] = f;}
else {printf("Error: stack full, can't push %g\n", f);}
}
double pop(void) // pop and return top value from stack
{
if (sp > 0) {return val[--sp];}
else
{
printf("Error: stack empty\n");
return 0.0;
}
}
#include <ctype.h> // for isdigit()
int getch(void);
void ungetch(int);
int getop(char s[]) // get next operator or numeric operand
{
int c, i;
while ((s[0] = c = getch()) == ' ' || c == '\t') // skip beginning ' ', '\t'
{} // last value read in s[0] is not ' ' or '\t', but could be '\n' or EOF
s[1] = '\0'; // end string
if (!isdigit(c) && c != '.' && c != '+' && c != '-')
{return c;} // not a number, probably an operator (or '\n' or '\0' or EOF)
// here c is digit or '.' or '+' or '-'
i = 0;
if (c == '+' || c == '-') // unary or binary sign
{
c = getch();
if (!isdigit(c) && c != '.')
{
ungetch(c);
return s[0]; // binary '+' or '-'
}
else // c is digit or '.'
{
if (s[i] == '-') {i++;} // s[0]
// if (s[i] == '+') {} // skip adding '+' to s[]
s[i] = c; // digit or '.'
}
}
if (isdigit(c)) // collect integer part
{ // s[i] contains c (digit)
while (isdigit(s[++i] = c = getch()))
{}
} // here s[i] is not a digit
if (c == '.') // collect fraction part
{ // s[i] contains c (s[i] == '.')
while (isdigit(s[++i] = c = getch()))
{}
} // here s[i] is not a digit
s[i] = '\0'; // end string containing number (operand)
if (c != EOF) {ungetch(c);} // cannot ungetch(EOF) as EOF is not a char
else {ungetch('\0');} // EOF or '\0' returned by getop() will end the program
return NUMBER;
}
#define BUFSIZE 100
char buf[BUFSIZE]; // buffer for ungetch()
// buf[] pointer (0 is top of buf):
int bufp = 0; // next free position in buf[]
int getch(void) // get a (possibly pushed-back) character
{
return (bufp > 0) ? buf[--bufp] : getchar();
}
// push character back on input (make it available for the next getch()):
void ungetch(int c)
{
if (bufp >= BUFSIZE)
{printf("ungetch(): too many characters\n");}
else {buf[bufp++] = c;}
}
/*
gcc mathops.c -o mathops -lm // link math library
./mathops
0 s // sin(0)
0
3.14 s // sin(pi)
0.0015926529
1.57 s // sin(pi/2)
0.99999968
1 e // e^1
2.7182818
2 e // e^2
7.3890561
3 2 p // 3^2
9
2 3 p // 2^3
8
1 2 +
3
1 2 + 3 * 4 /
2.25
-1 2 +
1
1 2 -
-1 // 1-2
-1 -2 +
-3
-1 2 + 3 *
3
2 0 /
Error: zero divisor
2 // pop() called by '\n' returns first operand, still on stack
1 2 /
0.5
2 3 %
2
4 2 %
0
4 1 %
0
4 3 %
1
4 0 %
Error: zero divisor
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
a b +
Unknown command: a
Unknown command: b
Error: stack empty // nothing pushed, pop() called by +
Error: stack empty // pop() called by '\n'
0 // value returned by pop() for an empty stack
1 2 9
9 // pop() called by '\n'
+
3 // 1 + 2
1 2 c
Unknown command: c
2 // pop() called by '\n'
3 +
4 // 1 + 3
CTRL^D (EOF) or CTRL^C in Linux, CTRL^Z + Enter in Windows
./mathops < compute.txt
3 // 1 2 +
0 // 1 2 * 3 + 5 -
1 // -1 2 +
1 // -1 -2 -
1 // 4 3 %
Error: zero divisor // 2 0 %
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
0.33333333 // 1 3 /
Error: zero divisor // 1 0 /
1 // pop() called by '\n' returns first operand, still on stack
*/
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
Exercise 4-6. Add commands for handling variables. (It's easy to provide twenty-six variables with single-letter names.) Add a variable for the most recently printed value.
#include <stdio.h> // for getchar(), putchar(), printf(), EOF
#include <stdlib.h> // for atof()
#include <string.h> // for strcpy()
#define MAXOP 100 // max size of operand or operator
#define NUMBER '0' // signal that a number has been found
#define VARS 26 // single-letter variable names
#define DESCRIPTION 100 // max description length for variables
int getop(char []); // get the next operand or operator
void push(double); // push operand on stack
double pop(void); // pop operand from stack
int main()
{
int type, i1, i2;
double op2; // operand
double last = 0.0; // last printed value
char s[MAXOP]; // operand or operator
extern int sp; // stack pointer
extern double val[]; // stack
char variables[VARS] = {'\0'}; // single-letter variable names
char descriptions[VARS][DESCRIPTION]; // 2D array
variables['l'-'a'] = 'l';
strcpy(descriptions['l'-'a'], "last printed value");
variables['p'-'a'] = 'p';
strcpy(descriptions['p'-'a'], "print stack");
variables['s'-'a'] = 's';
strcpy(descriptions['s'-'a'], "stack size");
while((type = getop(s)) != EOF && type != '\0')
{ // nonempty line ending with EOF will not be executed
switch(type)
{
case NUMBER :
push(atof(s));
break;
case '+' :
push(pop() + pop());
break;
case '-' :
op2 = pop();
push(pop() - op2);
break;
case '*' :
push(pop() * pop());
break;
case '/' :
op2 = pop();
if (op2 != 0.0)
{push(pop() / op2);}
else {printf("Error: zero divisor\n");}
break;
case '%' :
i2 = pop(); // automatic conversions
i1 = pop(); // from double to int
if (i2 != 0.0) // automatic conversions from int to double,
{push(i1 % i2);} // here argument of push()
else {printf("Error: zero divisor\n");}
break;
case 'l' : // last printed value
printf("Last printed value: %.8g\n", last);
break;
case 's' : // stack size
printf("Stack size: %d\n", sp);
break;
case 'p' : // print stack
for (i1 = 0; i1 < sp; i1++)
{
printf("%g ", val[i1]);
}
putchar('\n');
break;
case 'L' : // list variables
for (i1 = 0; i1 < VARS; i1++)
{
if (variables[i1] != '\0') // non-null
{printf("%c, ", variables[i1]);}
}
putchar('\n');
break;
case 'P' : // print variables and descriptions
for (i1 = 0; i1 < VARS; i1++)
{
if (variables[i1] != '\0') // non-null
{ // print non-null variables and their descriptions:
printf("%c - %s\n", variables[i1], descriptions[i1]);
}
}
break;
case '\n' :
last = pop(); // top of stack
printf("\t%.8g\n", last); // last printed value
break;
default :
printf("Unknown command: %s\n", s);
break;
}
}
return 0;
}
#define MAXVAL 100 // stack size
// stack pointer (0 is top of stack):
int sp = 0; // next free stack position
double val[MAXVAL]; // value stack
void push(double f) // push f on (top of) stack
{
if (sp < MAXVAL) {val[sp++] = f;}
else {printf("Error: stack full, can't push %g\n", f);}
}
double pop(void) // pop and return top value from stack
{
if (sp > 0) {return val[--sp];}
else
{
printf("Error: stack empty\n");
return 0.0;
}
}
#include <ctype.h> // for isdigit()
int getch(void);
void ungetch(int);
int getop(char s[]) // get next operator or numeric operand
{
int c, i;
while ((s[0] = c = getch()) == ' ' || c == '\t') // skip beginning ' ', '\t'
{} // last value read in s[0] is not ' ' or '\t', but could be '\n' or EOF
s[1] = '\0'; // end string
if (!isdigit(c) && c != '.' && c != '+' && c != '-')
{return c;} // not a number, probably an operator (or '\n' or '\0' or EOF)
// here c is digit or '.' or '+' or '-'
i = 0;
if (c == '+' || c == '-') // unary or binary sign
{
c = getch();
if (!isdigit(c) && c != '.')
{
ungetch(c);
return s[0]; // binary '+' or '-'
}
else // c is digit or '.'
{
if (s[i] == '-') {i++;} // s[0]
// if (s[i] == '+') {} // skip adding '+' to s[]
s[i] = c; // digit or '.'
}
}
if (isdigit(c)) // collect integer part
{ // s[i] contains c (digit)
while (isdigit(s[++i] = c = getch()))
{}
} // here s[i] is not a digit
if (c == '.') // collect fraction part
{ // s[i] contains c (s[i] == '.')
while (isdigit(s[++i] = c = getch()))
{}
} // here s[i] is not a digit
s[i] = '\0'; // end string containing number (operand)
if (c != EOF) {ungetch(c);} // cannot ungetch(EOF) as EOF is not a char
else {ungetch('\0');} // EOF or '\0' returned by getop() will end the program
return NUMBER;
}
#define BUFSIZE 100
char buf[BUFSIZE]; // buffer for ungetch()
// buf[] pointer (0 is top of buf):
int bufp = 0; // next free position in buf[]
int getch(void) // get a (possibly pushed-back) character
{
return (bufp > 0) ? buf[--bufp] : getchar();
}
// push character back on input (make it available for the next getch()):
void ungetch(int c)
{
if (bufp >= BUFSIZE)
{printf("ungetch(): too many characters\n");}
else {buf[bufp++] = c;}
}
/*
gcc varscalc.c -o varscalc
./varscalc
L
l, p, s,
Error: stack empty
0 // pop() called by '\n'
P
l - last printed value
p - print stack
s - stack size
Error: stack empty
0 // pop() called by '\n'
s
Stack size: 0
Error: stack empty
0
1 2 3 s
Stack size: 3
3 // pop() called by '\n'
+
3
p
Error: stack empty
0
1 2 3 p // print stack
1 2 3
3 // pop() called by '\n'
p
1 2
2 // pop() called by '\n'
p
1
1 // pop() called by '\n'
p
Error: stack empty // pop() called by '\n'
0 // value returned by pop() for empty stack
1 2 3 l
Last printed value: 0
3
l
Last printed value: 3
2
l
Last printed value: 2
1
l
Last printed value: 1
Error: stack empty
0
l
Last printed value: 0
Error: stack empty
0
1 2 +
3
1 2 + 3 * 4 /
2.25
-1 2 +
1
1 2 -
-1 // 1-2
-1 -2 +
-3
-1 2 + 3 *
3
2 0 /
Error: zero divisor
2 // pop() called by '\n' returns first operand, still on stack
1 2 /
0.5
2 3 %
2
4 2 %
0
4 1 %
0
4 3 %
1
4 0 %
Error: zero divisor
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
a b +
Unknown command: a
Unknown command: b
Error: stack empty // nothing pushed, pop() called by +
Error: stack empty // pop() called by '\n'
0 // value returned by pop() for an empty stack
1 2 9
9 // pop() called by '\n'
+
3 // 1 + 2
1 2 c
Unknown command: c
2 // pop() called by '\n'
3 +
4 // 1 + 3
CTRL^D (EOF) or CTRL^C in Linux, CTRL^Z + Enter in Windows
./varscalc < compute.txt
3 // 1 2 +
0 // 1 2 * 3 + 5 -
1 // -1 2 +
1 // -1 -2 -
1 // 4 3 %
Error: zero divisor // 2 0 %
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
0.33333333 // 1 3 /
Error: zero divisor // 1 0 /
1 // pop() called by '\n' returns first operand, still on stack
*/
You should follow the same convention we used here: commands for handling variables are uppercase letters, while variables are lowercase letters.
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
Exercise 4-7. Write a routine ungets(s) that will push back an entire string onto the input. Should ungets() know about buf[] and bufp, or should it just use ungetch()?
#include <stdio.h> // for printf(), getchar(), EOF
#include <stdlib.h> // for atof()
#define MAXOP 100 // max size of operand or operator
#define NUMBER '0' // signal that a number has been found
int getop(char []); // get the next operand or operator
void push(double); // push operand on stack
double pop(void); // pop operand from stack
int main()
{
int type, i1, i2;
double op2; // second operand for -, /, %
char s[MAXOP]; // operand or operator
while((type = getop(s)) != EOF && type != '\0')
{ // nonempty line ending with EOF will not be executed
switch(type)
{
case NUMBER :
push(atof(s));
break;
case '+' :
push(pop() + pop());
break;
case '-' :
op2 = pop();
push(pop() - op2);
break;
case '*' :
push(pop() * pop());
break;
case '/' :
op2 = pop();
if (op2 != 0.0)
{push(pop() / op2);}
else {printf("Error: zero divisor\n");}
break;
case '%' :
i2 = pop(); // automatic conversions
i1 = pop(); // from double to int
if (i2 != 0.0)
{push(i1 % i2);} // auto conversion from int to double, arg of push()
else {printf("Error: zero divisor\n");}
break;
case '\n' :
printf("\t%.8g\n", pop()); // top of stack
break;
default :
printf("Unknown command: %s\n", s);
break;
}
}
return 0;
}
#define MAXVAL 100 // stack size
// stack pointer (0 is top of stack):
int sp = 0; // next free stack position
double val[MAXVAL]; // value stack
void push(double f) // push f on (top of) stack
{
if (sp < MAXVAL) {val[sp++] = f;}
else {printf("Error: stack full, can't push %g\n", f);}
}
double pop(void) // pop and return top value from stack
{
if (sp > 0) {return val[--sp];}
else
{
printf("Error: stack empty\n");
return 0.0;
}
}
#include <ctype.h> // for isdigit()
int getch(void);
void ungetch(int);
int getop(char s[]) // get next operator or numeric operand
{
int c, i;
while ((s[0] = c = getch()) == ' ' || c == '\t') // skip beginning ' ', '\t'
{} // last value read in s[0] is not ' ' or '\t', but could be '\n' or EOF
s[1] = '\0'; // end string
if (!isdigit(c) && c != '.' && c != '+' && c != '-')
{return c;} // not a number, probably an operator (or '\n' or '\0' or EOF)
// here c is digit or '.' or '+' or '-'
i = 0;
if (c == '+' || c == '-') // unary or binary sign
{
c = getch();
if (!isdigit(c) && c != '.')
{
ungetch(c);
return s[0]; // binary '+' or '-'
}
else // c is digit or '.'
{
if (s[i] == '-') {i++;} // s[0]
// if (s[i] == '+') {} // skip adding '+' to s[]
s[i] = c; // digit or '.'
}
}
if (isdigit(c)) // collect integer part
{ // s[i] contains c (digit)
while (isdigit(s[++i] = c = getch()))
{}
} // here s[i] is not a digit
if (c == '.') // collect fraction part
{ // s[i] contains c (s[i] == '.')
while (isdigit(s[++i] = c = getch()))
{}
} // here s[i] is not a digit
s[i] = '\0'; // end string containing number (operand)
if (c != EOF) {ungetch(c);} // cannot ungetch(EOF) as EOF is not a char
else {ungetch('\0');} // EOF or '\0' returned by getop() will end the program
return NUMBER;
}
#define BUFSIZE 100
char buf[BUFSIZE]; // buffer for ungetch()
// buf[] pointer (0 is top of buf):
int bufp = 0; // next free position in buf[]
int getch(void) // get a (possibly pushed-back) character
{
return (bufp > 0) ? buf[--bufp] : getchar();
}
// push character back on input (make it available for the next getch()):
void ungetch(int c)
{
if (bufp >= BUFSIZE)
{printf("ungetch(): too many characters\n");}
else {buf[bufp++] = c;}
}
#include <string.h> // for strlen()
void ungets1(char s[]) // less efficient
{
int len = strlen(s);
int i;
for (i = 0; i < len; i++)
{
ungetch(s[i]); // many function calls (inefficient)
}
}
void ungets2(char s[]) // more efficient
{
int len = strlen(s);
if (bufp + len >= BUFSIZE)
{
printf("ungetch(): too many characters\n");
return;
}
int i;
for (i = 0; i < len; i++)
{
buf[bufp++] = s[i]; // no function calls here (more efficient)
}
}
/*
gcc ungets.c -o ungets
./ungets
1 2 +
3
1 2 + 3 * 4 /
2.25
-1 2 +
1
-1 -2 +
-3
-1 2 + 3 *
3
2 0 /
Error: zero divisor
2 // pop() called by '\n' returns first operand, still on stack
1 2 /
0.5
2 3 %
2
4 2 %
0
4 1 %
0
4 3 %
1
4 0 %
Error: zero divisor
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
a b +
Unknown command: a
Unknown command: b
Error: stack empty // nothing pushed, pop() called by +
Error: stack empty // pop() called by '\n'
0 // value returned by pop() for an empty stack
1 2 9
9 // pop() called by '\n'
+
3 // 1 + 2
1 2 c
Unknown command: c
2 // pop() called by '\n'
3 +
4 // 1 + 3
CTRL^D (EOF) or CTRL^C in Linux, CTRL^Z + Enter in Windows
./ungets < compute.txt
3 // 1 2 +
0 // 1 2 * 3 + 5 -
1 // -1 2 +
1 // -1 -2 -
1 // 4 3 %
Error: zero divisor // 2 0 %
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
0.33333333 // 1 3 /
Error: zero divisor // 1 0 /
1 // pop() called by '\n' returns first operand, still on stack
*/
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
Exercise 4-8. Suppose that there will never be more than one character of pushback. Modify getch() and ungetch() accordingly.
Exercise 4-9. Our getch() and ungetch() do not handle a pushed-back EOF correctly. Decide what their properties ought to be if an EOF is pushed back, then implement your design.
#include <stdio.h> // for printf(), getchar(), EOF
#include <stdlib.h> // for atof()
#define MAXOP 100 // max size of operand or operator
#define NUMBER '0' // signal that a number has been found
int getop(char []); // get the next operand or operator
void push(double); // push operand on stack
double pop(void); // pop operand from stack
int main()
{
int type, i1, i2;
double op2; // second operand for -, /, %
char s[MAXOP]; // operand or operator
while((type = getop(s)) != EOF)
{ // nonempty line ending with EOF will not be executed
switch(type)
{
case NUMBER :
push(atof(s));
break;
case '+' :
push(pop() + pop());
break;
case '-' :
op2 = pop();
push(pop() - op2);
break;
case '*' :
push(pop() * pop());
break;
case '/' :
op2 = pop();
if (op2 != 0.0)
{push(pop() / op2);}
else {printf("Error: zero divisor\n");}
break;
case '%' :
i2 = pop(); // automatic conversions
i1 = pop(); // from double to int
if (i2 != 0.0)
{push(i1 % i2);} // auto conversion from int to double, arg of push()
else {printf("Error: zero divisor\n");}
break;
case '\n' :
printf("\t%.8g\n", pop()); // top of stack
break;
default :
printf("Unknown command: %s\n", s);
break;
}
}
return 0;
}
#define MAXVAL 100 // stack size
// stack pointer (0 is top of stack):
int sp = 0; // next free stack position
double val[MAXVAL]; // value stack
void push(double f) // push f on (top of) stack
{
if (sp < MAXVAL) {val[sp++] = f;}
else {printf("Error: stack full, can't push %g\n", f);}
}
double pop(void) // pop and return top value from stack
{
if (sp > 0) {return val[--sp];}
else
{
printf("Error: stack empty\n");
return 0.0;
}
}
#include <ctype.h> // for isdigit()
int getch(void);
void ungetch(int);
int getop(char s[]) // get next operator or numeric operand
{
int c, i;
while ((s[0] = c = getch()) == ' ' || c == '\t') // skip beginning ' ', '\t'
{} // last value read in s[0] is not ' ' or '\t', but could be '\n' or EOF
s[1] = '\0'; // end string
if (!isdigit(c) && c != '.' && c != '+' && c != '-')
{return c;} // not a number, probably an operator (or '\n' or EOF)
// here c is digit or '.' or '+' or '-'
i = 0;
if (c == '+' || c == '-') // unary or binary sign
{
c = getch();
if (!isdigit(c) && c != '.')
{
ungetch(c);
return s[0]; // binary '+' or '-'
}
else // c is digit or '.'
{
if (s[i] == '-') {i++;} // s[0]
// if (s[i] == '+') {} // skip adding '+' to s[]
s[i] = c; // digit or '.'
}
}
if (isdigit(c)) // collect integer part
{ // s[i] contains c (digit)
while (isdigit(s[++i] = c = getch()))
{}
} // here s[i] is not a digit
if (c == '.') // collect fraction part
{ // s[i] contains c (s[i] == '.')
while (isdigit(s[++i] = c = getch()))
{}
} // here s[i] is not a digit
s[i] = '\0'; // end string containing number (operand)
ungetch(c); // if (c == EOF), the next getop() will return EOF, ending the program
return NUMBER;
}
// buffer for ungetch():
int buf = EOF-1; // not a real character, not even EOF
int getch(void) // get a (possibly pushed-back) character
{
if (buf < EOF)
{
return getchar();
}
int temp = buf; // buf >= EOF
buf = EOF-1; // reset buf
return temp;
}
// push character back on input (make it available for the next getch()):
void ungetch(int c)
{
buf = c;
}
/*
gcc calc1.c -o calc1
./calc1
1 2 +
3
1 2 + 3 * 4 /
2.25
-1 2 +
1
-1 -2 +
-3
-1 2 + 3 *
3
2 0 /
Error: zero divisor
2 // pop() called by '\n' returns first operand, still on stack
1 2 /
0.5
2 3 %
2
4 2 %
0
4 1 %
0
4 3 %
1
4 0 %
Error: zero divisor
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
a b +
Unknown command: a
Unknown command: b
Error: stack empty // nothing pushed, pop() called by +
Error: stack empty // pop() called by '\n'
0 // value returned by pop() for an empty stack
1 2 9
9 // pop() called by '\n'
+
3 // 1 + 2
1 2 c
Unknown command: c
2 // pop() called by '\n'
3 +
4 // 1 + 3
CTRL^D (EOF) or CTRL^C in Linux, CTRL^Z + Enter in Windows
./calc1 < compute.txt
3 // 1 2 +
0 // 1 2 * 3 + 5 -
1 // -1 2 +
1 // -1 -2 -
1 // 4 3 %
Error: zero divisor // 2 0 %
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
0.33333333 // 1 3 /
Error: zero divisor // 1 0 /
1 // pop() called by '\n' returns first operand, still on stack
*/
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
Exercise 4-10. An alternate organization uses getline() to read an entire input line; this makes getch() and ungetch() unnecessary. Revise the calculator to use this approach.
#include <stdio.h> // for printf(), getchar(), EOF
#include <stdlib.h> // for atof()
#define MAXLINE 1000 // max line length
#define MAXOP 100 // max size of operand or operator
#define NUMBER '0' // signal that a number has been found
int getLine(char [], int); // getline() is declared in stdio.h
char line[MAXLINE];
int lp; // line pointer
int getop(char []); // get the next operand or operator
void push(double); // push operand on stack
double pop(void); // pop operand from stack
int main()
{
int type, i1, i2, len;
double op2; // second operand for -, /, %
char s[MAXOP]; // operand or operator
while((len = getLine(line, MAXLINE)) > 0)
{ // nonempty line ending with EOF will not be executed
lp = 0; // reset
while(lp < len)
{
type = getop(s);
switch(type)
{
case NUMBER :
push(atof(s));
break;
case '+' :
push(pop() + pop());
break;
case '-' :
op2 = pop();
push(pop() - op2);
break;
case '*' :
push(pop() * pop());
break;
case '/' :
op2 = pop();
if (op2 != 0.0)
{push(pop() / op2);}
else {printf("Error: zero divisor\n");}
break;
case '%' :
i2 = pop(); // automatic conversions
i1 = pop(); // from double to int
if (i2 != 0.0)
{push(i1 % i2);} // auto conversion from int to double, arg of push()
else {printf("Error: zero divisor\n");}
break;
case '\n' :
printf("\t%.8g\n", pop()); // top of stack
break;
default :
printf("Unknown command: %s\n", s);
break;
} // end of switch()
// if (type == '\n') {break;} // out of inner while()
} // end of inner while()
} // end of outer while()
return 0;
} // end of main()
// getLine(): read a line into s[], return length
int getLine(char s[], int lim)
{
int c = EOF; // initialize
int i;
// getchar() is only executed if (i < (lim-1)):
for (i = 0; i < (lim-1) && (c = getchar()) != EOF && c != '\n'; i++)
{ // from 0 to lim-2; s[lim-2]='\n' or not, s[lim-1]='\0'
s[i] = c;
}
if (c == '\n') // i < (lim-1), getchar() executed
{
s[i] = c; // '\n'
i++;
}
s[i] = '\0'; // the null character ends a string
return i; // max(i) == (lim-1), assuming (lim-1) > 0
}
#define MAXVAL 100 // stack size
// stack pointer (0 is top of stack):
int sp = 0; // next free stack position
double val[MAXVAL]; // value stack
void push(double f) // push f on (top of) stack
{
if (sp < MAXVAL) {val[sp++] = f;}
else {printf("Error: stack full, can't push %g\n", f);}
}
double pop(void) // pop and return top value from stack
{
if (sp > 0) {return val[--sp];}
else
{
printf("Error: stack empty\n");
return 0.0;
}
}
#include <ctype.h> // for isdigit()
int getop(char s[]) // get next operator or numeric operand
{
int c, i;
while ((s[0] = c = line[lp++]) == ' ' || c == '\t') // skip beginning ' ', '\t'
{} // last value read in s[0] is not ' ' or '\t', but could be '\n' or EOF
s[1] = '\0'; // end string
if (!isdigit(c) && c != '.' && c != '+' && c != '-')
{return c;} // not a number, probably an operator (or '\n')
// here c is digit or '.' or '+' or '-'
i = 0;
if (c == '+' || c == '-') // unary or binary sign
{
c = line[lp++];
if (!isdigit(c) && c != '.')
{
lp--;
return s[0]; // binary '+' or '-'
}
else // c is digit or '.'
{
if (s[i] == '-') {i++;} // s[0]
// if (s[i] == '+') {} // skip adding '+' to s[]
s[i] = c; // digit or '.'
}
}
if (isdigit(c)) // collect integer part
{ // s[i] contains c (digit)
while (isdigit(s[++i] = c = line[lp++]))
{}
} // here s[i] is not a digit
if (c == '.') // collect fraction part
{ // s[i] contains c (s[i] == '.')
while (isdigit(s[++i] = c = line[lp++]))
{}
} // here s[i] is not a digit
s[i] = '\0'; // end string containing number (operand)
lp--; // line[] does not contain EOF
return NUMBER;
}
/*
gcc getcalc.c -o getcalc
./getcalc
1 2 +
3
1 2 + 3 * 4 /
2.25
-1 2 +
1
-1 -2 +
-3
-1 2 + 3 *
3
2 0 /
Error: zero divisor
2 // pop() called by '\n' returns first operand, still on stack
1 2 /
0.5
2 3 %
2
4 2 %
0
4 1 %
0
4 3 %
1
4 0 %
Error: zero divisor
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
a b +
Unknown command: a
Unknown command: b
Error: stack empty // nothing pushed, pop() called by +
Error: stack empty // pop() called by '\n'
0 // value returned by pop() for an empty stack
1 2 9
9 // pop() called by '\n'
+
3 // 1 + 2
1 2 c
Unknown command: c
2 // pop() called by '\n'
3 +
4 // 1 + 3
CTRL^D (EOF) or CTRL^C in Linux, CTRL^Z + Enter in Windows
./getcalc < compute.txt
3 // 1 2 +
0 // 1 2 * 3 + 5 -
1 // -1 2 +
1 // -1 -2 -
1 // 4 3 %
Error: zero divisor // 2 0 %
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
0.33333333 // 1 3 /
Error: zero divisor // 1 0 /
1 // pop() called by '\n' returns first operand, still on stack
*/
In getop(), we always write line[lp++]; one should be consistent.
while (isdigit(s[++i] = c = line[lp])) {lp++;} followed by lp--; at the end of getop() is not correct. Thus, when line[lp] is not a digit, the test inside while() fails and lp++; is not executed. However, lp--; is executed and then lp points to the last digit of the last read number. The next getop() reads this digit as a separate number, then executes lp--; then the next getop() reads the same digit, etc., entering an infinite loop.
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
Compile (and assemble) source files (without linking):
gcc -c getch.c
gcc -c stack.c
gcc -c getop.c
gcc -c calc.c
Link all object files (*.o) and output executable `calc':
gcc *.o -o calc
You can also use the makefile:
make
gcc -c getch.c
gcc -c stack.c
gcc -c getop.c
gcc -c calc.c
gcc *.o -o calc
Delete object files:
rm *.o
Or:
make clean
Run program with input from the keyboard:
./calc
Run program with input from a file:
./calc < compute.txt
all: calc
calc: getch.o stack.o getop.o calc.o
gcc *.o -o calc
getch.o: getch.c
gcc -c getch.c
stack.o: stack.c
gcc -c stack.c
getop.o: number.h getop.h getop.c
gcc -c getop.c
calc.o: number.h calc.h calc.c
gcc -c calc.c
clean:
rm *.o
1 2 +
1 2 * 3 + 5 -
-1 2 +
-1 -2 -
4 3 %
2 0 %
1 3 /
1 0 /
#define NUMBER '0' // signal that a number has been found
int getch(void); // get the next input character
void ungetch(int); // push the last read character back on input
int getop(char []); // get the next operand or operator
void push(double); // push operand on stack
double pop(void); // pop operand from stack
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
#include <stdio.h> // for getchar(), EOF
// buffer for ungetch():
int buf = EOF-1; // not a real character, not even EOF
int getch(void) // get a (possibly pushed-back) character
{
if (buf < EOF)
{
return getchar();
}
int temp = buf; // buf >= EOF
buf = EOF-1; // reset buf
return temp;
}
// push character back on input (make it available for the next getch()):
void ungetch(int c)
{
buf = c;
}
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
#include <stdio.h> // for printf()
#define MAXVAL 100 // stack size
// stack pointer (0 is top of stack):
int sp = 0; // next free stack position
double val[MAXVAL]; // value stack
void push(double f) // push f on (top of) stack
{
if (sp < MAXVAL) {val[sp++] = f;}
else {printf("Error: stack full, can't push %g\n", f);}
}
double pop(void) // pop and return top value from stack
{
if (sp > 0) {return val[--sp];}
else
{
printf("Error: stack empty\n");
return 0.0;
}
}
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
#include <ctype.h> // for isdigit()
#include "number.h" // for NUMBER
#include "getop.h" // for getch(), ungetch()
int getop(char s[]) // get next operator or numeric operand
{
int c, i;
while ((s[0] = c = getch()) == ' ' || c == '\t') // skip beginning whitespace (' ', '\t')
{} // last value read in s[0] is not ' ' or '\t', but could be '\n' or EOF
s[1] = '\0'; // end string
if (!isdigit(c) && c != '.' && c != '+' && c != '-')
{return c;} // not a number, probably an operator (or '\n' or EOF)
// here c is digit or '.' or '+' or '-'
i = 0;
if (c == '+' || c == '-') // unary or binary sign
{
c = getch();
if (!isdigit(c) && c != '.')
{
ungetch(c);
return s[0]; // binary '+' or '-'
}
else // c is digit or '.'
{
if (s[i] == '-') {i++;} // s[0]
// if (s[i] == '+') {} // skip adding '+' to s[]
s[i] = c; // digit or '.'
}
}
if (isdigit(c)) // collect integer part
{ // s[i] contains c (digit)
while (isdigit(s[++i] = c = getch()))
{}
} // here s[i] is not a digit
if (c == '.') // collect fraction part
{ // s[i] contains c (s[i] == '.')
while (isdigit(s[++i] = c = getch()))
{}
} // here s[i] is not a digit
s[i] = '\0'; // end string containing number (operand)
ungetch(c); // if (c == EOF), the next getop() will return EOF, ending the program
return NUMBER;
}
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
#include <stdio.h> // for printf(), EOF
#include <stdlib.h> // for atof()
#include "number.h" // for NUMBER
#include "calc.h" // for getop(), push(), pop()
#define MAXOP 100 // max size of operand or operator
int main()
{
int type, i1, i2;
double op2; // second operand for -, /, %
char s[MAXOP]; // operand or operator
while((type = getop(s)) != EOF)
{ // nonempty line ending with EOF will not be executed
switch(type)
{
case NUMBER :
push(atof(s));
break;
case '+' :
push(pop() + pop());
break;
case '-' :
op2 = pop();
push(pop() - op2);
break;
case '*' :
push(pop() * pop());
break;
case '/' :
op2 = pop();
if (op2 != 0.0)
{push(pop() / op2);}
else {printf("Error: zero divisor\n");}
break;
case '%' :
i2 = pop(); // automatic conversions
i1 = pop(); // from double to int
if (i2 != 0.0)
{push(i1 % i2);} // automatic conversion from int to double, argument of push()
else {printf("Error: zero divisor\n");}
break;
case '\n' :
printf("\t%.8g\n", pop()); // top of stack
break;
default :
printf("Unknown command: %s\n", s);
break;
}
}
return 0;
}
/*
gcc -c getch.c // compile (and assemble) without linking
gcc -c stack.c // compile (and assemble) without linking
gcc -c getop.c // compile (and assemble) without linking
gcc -c calc.c // compile (and assemble) without linking
gcc *.o -o calc // link all object files (*.o) and output executable `calc'
./calc // run program with input from the keyboard
1 2 +
3
1 2 + 3 * 4 /
2.25
-1 2 +
1
-1 -2 +
-3
-1 2 + 3 *
3
2 0 /
Error: zero divisor
2 // pop() called by '\n' returns first operand, still on stack
1 2 /
0.5
2 3 %
2
4 2 %
0
4 1 %
0
4 3 %
1
4 0 %
Error: zero divisor
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
a b +
Unknown command: a
Unknown command: b
Error: stack empty // nothing pushed, pop() called by +
Error: stack empty // pop() called by '\n'
0 // value returned by pop() for an empty stack
1 2 9
9 // pop() called by '\n'
+
3 // 1 + 2
1 2 c
Unknown command: c
2 // pop() called by '\n'
3 +
4 // 1 + 3
CTRL^D (EOF) or CTRL^C in Linux, CTRL^Z + Enter in Windows
// Run program with input from a file:
./calc < compute.txt
3 // 1 2 +
0 // 1 2 * 3 + 5 -
1 // -1 2 +
1 // -1 -2 -
1 // 4 3 %
Error: zero divisor // 2 0 %
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
0.33333333 // 1 3 /
Error: zero divisor // 1 0 /
1 // pop() called by '\n' returns first operand, still on stack
*/
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
Exercise 4-11. Modify getop() so that it doesn't need to use ungetch(). Hint: use an internal static variable.
#include <stdio.h> // for printf(), getchar(), EOF
#include <stdlib.h> // for atof()
#define MAXOP 100 // max size of operand or operator
#define NUMBER '0' // signal that a number has been found
int getop(char []); // get the next operand or operator
void push(double); // push operand on stack
double pop(void); // pop operand from stack
int main()
{
int type, i1, i2;
double op2; // second operand for -, /, %
char s[MAXOP]; // operand or operator
while((type = getop(s)) != EOF)
{ // nonempty line ending with EOF will not be executed
switch(type)
{
case NUMBER :
push(atof(s));
break;
case '+' :
push(pop() + pop());
break;
case '-' :
op2 = pop();
push(pop() - op2);
break;
case '*' :
push(pop() * pop());
break;
case '/' :
op2 = pop();
if (op2 != 0.0)
{push(pop() / op2);}
else {printf("Error: zero divisor\n");}
break;
case '%' :
i2 = pop(); // automatic conversions
i1 = pop(); // from double to int
if (i2 != 0.0)
{push(i1 % i2);} // auto conversion from int to double, arg of push()
else {printf("Error: zero divisor\n");}
break;
case '\n' :
printf("\t%.8g\n", pop()); // top of stack
break;
default :
printf("Unknown command: %s\n", s);
break;
}
}
return 0;
}
#define MAXVAL 100 // stack size
// stack pointer (0 is top of stack):
int sp = 0; // next free stack position
double val[MAXVAL]; // value stack
void push(double f) // push f on (top of) stack
{
if (sp < MAXVAL) {val[sp++] = f;}
else {printf("Error: stack full, can't push %g\n", f);}
}
double pop(void) // pop and return top value from stack
{
if (sp > 0) {return val[--sp];}
else
{
printf("Error: stack empty\n");
return 0.0;
}
}
#include <ctype.h> // for isdigit()
int getop(char s[]) // get next operator or numeric operand
{
int c, i;
static int buf = EOF-1; // not a real character, not even EOF
if (buf == ' ' || buf == '\t' || buf == EOF-1) // initially buf == EOF-1
{
while ((s[0] = c = getchar()) == ' ' || c == '\t') // skip beginning ' ', '\t'
{} // last value read in s[0] is not ' ' or '\t', but could be '\n' or EOF
}
else // buf >= EOF
{s[0] = c = buf;} // here buf could be EOF, from a previous call to getop()
buf = EOF-1; // reset buf
s[1] = '\0'; // end string
if (!isdigit(c) && c != '.' && c != '+' && c != '-')
{return c;} // not a number, probably an operator (or '\n' or EOF)
// here c is digit or '.' or '+' or '-'
i = 0;
if (c == '+' || c == '-') // unary or binary sign
{
c = getchar();
if (!isdigit(c) && c != '.')
{
buf = c; // push character back on input
return s[0]; // binary '+' or '-'
}
else // c is digit or '.'
{
if (s[i] == '-') {i++;} // s[0]
// if (s[i] == '+') {} // skip adding '+' to s[]
s[i] = c; // digit or '.'
}
}
if (isdigit(c)) // collect integer part
{ // s[i] contains c (digit)
while (isdigit(s[++i] = c = getchar()))
{}
} // here s[i] is not a digit
if (c == '.') // collect fraction part
{ // s[i] contains c (s[i] == '.')
while (isdigit(s[++i] = c = getchar()))
{}
} // here s[i] is not a digit
s[i] = '\0'; // end string containing number (operand)
buf = c; // if (c == EOF), the next getop() will return EOF, ending the program
return NUMBER;
}
/*
gcc static.c -o static
./static
1 2 +
3
1 2 + 3 * 4 /
2.25
-1 2 +
1
-1 -2 +
-3
-1 2 + 3 *
3
2 0 /
Error: zero divisor
2 // pop() called by '\n' returns first operand, still on stack
1 2 /
0.5
2 3 %
2
4 2 %
0
4 1 %
0
4 3 %
1
4 0 %
Error: zero divisor
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
a b +
Unknown command: a
Unknown command: b
Error: stack empty // nothing pushed, pop() called by +
Error: stack empty // pop() called by '\n'
0 // value returned by pop() for an empty stack
1 2 9
9 // pop() called by '\n'
+
3 // 1 + 2
1 2 c
Unknown command: c
2 // pop() called by '\n'
3 +
4 // 1 + 3
CTRL^D (EOF) or CTRL^C in Linux, CTRL^Z + Enter in Windows
./static < compute.txt
3 // 1 2 +
0 // 1 2 * 3 + 5 -
1 // -1 2 +
1 // -1 -2 -
1 // 4 3 %
Error: zero divisor // 2 0 %
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
0.33333333 // 1 3 /
Error: zero divisor // 1 0 /
1 // pop() called by '\n' returns first operand, still on stack
*/