Exercise 4-6. Add commands for handling variables. (It’s easy to provide for twenty-six variables with single-letter names.) Add a variable for the most recently printed value.
Twenty-six variables map naturally to an array var[26] indexed by c - 'a'. The protocol: a lowercase letter pushes its variable’s value; = assigns the top of the stack to the variable named by the next token (without popping). A special $ variable holds the most recently printed value — updated automatically every time \n prints the result. The tricky design decision is that = keeps the value on the stack, so 3 x = 4 y = assigns both without breaking the calculation flow.
Key Additions
/* K&R Exercise 4-6 — RPN calculator: variables and last-value
* Add to the calculator from Exercise 4-5.
* Compile: gcc -ansi -Wall ex4-6.c -o ex4-6 -lm */
static double var[26]; /* a..z */
static double last = 0.0; /* $ = most recently printed value */
/* In getop: uppercase letters return the char directly (operator dispatch).
* Lower-case letters are handled below. */
/* In the main switch, add: */
/* push variable value */
/* (In getop, a single lowercase letter should return VARIABLE='v'
* with s[0] = the letter. For simplicity here we handle it in main.) */
/* Assignment: = varname stores top-of-stack into var without popping */
case '=':
/* peek at next non-space token to get variable name */
{
int c;
while ((c = gc()) == ' ' || c == '\t')
;
if (c >= 'a' && c <= 'z')
var[c - 'a'] = val[sp > 0 ? sp-1 : 0];
else
printf("error: = must be followed by a variable name\n");
}
break;
/* $ pushes the last-printed value */
case '$':
push(last);
break;
/* Update last when printing (in the '\n' case): */
case '\n':
last = pop();
printf("\t%.8g\n", last);
break;
Complete Working Demo
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#define MAXVAL 100
#define NUMBER '0'
static double val[MAXVAL];
static int sp = 0;
static double var[26];
static double last = 0.0;
void push(double f) { if (sp < MAXVAL) val[sp++] = f; }
double pop(void) { return sp > 0 ? val[--sp] : 0.0; }
static int _buf = EOF;
int gc(void) { int c = _buf; _buf = EOF; return (c != EOF) ? c : getchar(); }
void ugc(int c) { _buf = c; }
int getop(char s[])
{
int i, c;
while ((s[0] = c = gc()) == ' ' || c == '\t')
;
s[1] = '\0';
if (c >= 'a' && c <= 'z') return 'v'; /* variable name in s[0] */
if (!isdigit(c) && c != '.') return c;
i = 0;
while (isdigit(s[++i] = c = gc()))
;
if (c == '.')
while (isdigit(s[++i] = c = gc()))
;
s[i] = '\0';
if (c != EOF) ugc(c);
return NUMBER;
}
int main(void)
{
int type;
double op2;
char s[100];
while ((type = getop(s)) != EOF) {
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) push(pop()/op2); break;
case 'v': push(var[s[0]-'a']); break; /* push variable */
case '=': /* assign TOS to next variable */
{ int c; while((c=gc())==' '||c=='\t'); if(c>='a'&&c<='z') var[c-'a']=val[sp>0?sp-1:0]; } break;
case '$': push(last); break;
case '\n': last = pop(); printf("\t%.8g\n", last); break;
}
}
return 0;
}
Test It
printf "3.14159\n= p\np\n2 p * *\n" | ./ex4-6
# Store pi in p, compute 2*pi*pi
What This Exercise Teaches
- State outside the stack — variables and
lastare module-level state; the stack itself is stateless between operations - Assignment without pop —
=peeks rather than pops, so the value stays available for the next operation - Special variable
$— automatically updated on every print; allows using the previous result without re-typing - Design choice — uppercase vs lowercase for store/recall is one convention; push-on-read plus explicit
=is another; neither is canonically correct
Set Up Your C Environment
← Exercise 4-5 |
Chapter 4 Solutions |
Exercise 4-7 →
Book: The C Programming Language, 2nd Ed — Kernighan & Ritchie
1 comment on “K&R C Programs Exercise 4-6”