Lecture 5 thoughts
Stack transformation: Recursive code to iterative code
The centerpiece of the first part of lecture was a demonstration that we can write our own stacks, and thus implement a transformation the compiler normally handles for us. My goal was to demystify the stack concept and, as with every class demonstration, emphasize how easy it can be to peek “under the hood” of the C abstract machine and see what’s really going on. The demonstration went by too quickly and the code, since I wanted to show the transformation live, was messy. My sincere apologies! Here are cleaned-up versions of the input code and the post-transformation code, for your perusal.
Pre-transformation
#include <stdio.h>
#include <stdlib.h>
int factorial(int n) {
int x;
if (n == 0)
x = 1;
else
x = factorial(n - 1) * n;
return x;
}
int main(int argc, char **argv) {
int n = 2;
if (argc >= 2)
n = strtol(argv[1], 0, 0);
printf("%d! == %d\n", n, factorial(n));
}
Post-transformation
#include <stdio.h>
#include <stdlib.h>
/* factorial-handstack: Like factorial.c, but we build a stack to handle the
recursive calls. This replicates work the compiler normally does for us.
And it's not actually that hard! Compare with factorial.c for potential
insight. */
struct factorial_args_and_locals {
int n;
int x;
};
int factorial(int n) {
unsigned char stack[1000000];
// initialize 'stacktop' to point to the very top of the stack
// (stacks grow down by convention)
unsigned char *stacktop = &stack[sizeof(stack)];
// local variables (which represent registers)
struct factorial_args_and_locals *frame; // current stack frame
int argument; // holds the current function's argument
int return_value; // holds the current function's return value
// first time through, the argument is "n"
argument = n;
start:
// push and initialize stack frame
stacktop -= sizeof(struct factorial_args_and_locals);
frame = (struct factorial_args_and_locals *) stacktop;
frame->n = argument;
// function body
if (frame->n == 0)
frame->x = 1;
else {
// recursive call to 'factorial(n - 1)'
argument = frame->n - 1; // set up argument
goto start; // ...and restart function!
resume_caller: // multiply after callee returns
frame->x = return_value * frame->n;
}
return_value = frame->x;
// otherwise, pop stack frame and return to caller
stacktop += sizeof(struct factorial_args_and_locals);
if (stacktop == &stack[sizeof(stack)]) // done: whole function returns
return return_value;
frame = (struct factorial_args_and_locals *) stacktop;
goto resume_caller;
}
int main(int argc, char **argv) {
int n = 2;
if (argc >= 2)
n = strtol(argv[1], 0, 0);
fprintf(stderr, "%d! = %d\n", n, factorial(n));
}