Ancient CS 61 Content Warning!!!!!1!!!
This is not the current version of the class.
This site was automatically translated from a wiki. The translation may have introduced mistakes (and the content might have been wrong to begin with).

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));
}