Sidney Cadot said:
Hi Micah,
Only a C implementation for a genuine Turing machine could handle
infinite recursion.
The above statement isn't actually *quite* true. According to
the
as-if rule, an implementation could rewrite recursive code to be
iterative; and since all recursive algorithms are equivalent to
at least one iterative algorithm, this could be done for all
recursive calls. [...]
Memory serving, this is true only for so-called 'primitive
recursive' functions; a counterexample is the Ackermann function:
int ackermann(int x, int y)
{
return (x==0) ? y+1 : (y==0) ? ackermann(x-1,1) :
ackermann(x-1,ackermann(x,y-1));
}
Nope. I never said it could be done without a stack. Read the
rest of my previous message. I never said all such conversions
would be useful for our purposes, I merely said that such a
conversion was always possible.
----------
#include <stdlib.h>
#include <stdio.h>
struct stack {
int x;
struct stack *next;
};
struct stack * stack_push(struct stack **, int);
void stack_pop (struct stack **, int *);
void stack_destroy(struct stack **);
/* In this function, *result is the equivalent of your return
value; a 1 is returned for error; zero for
successful completion. */
int ackermann(int x, int y, int *result)
{
int intermed_result;
int error = 0;
struct stack *stk = NULL;
for (;
{
while (x != 0) {
if (y==0) {
/* Your return ackermann(x-1,1) */
x--;
y = 1;
}
else {
/* Your return ackermann(x-1,ackermann(x,y-1)) */
struct stack *tmpstk;
tmpstk = stack_push(&stk, x-1);
if (!tmpstk) {
stack_destroy(&stk);
error = 1;
}
y--;
}
}
/* Your return y+1 */
intermed_result = y+1;
/* Loop test: */ if (stk == NULL) break;
/* Continue... pop stack and reprocess. */
y = intermed_result;
stack_pop(&stk,&x);
}
*result = intermed_result;
return error;
}
struct stack *stack_push(struct stack **stk, int x)
{
struct stack *new_node = malloc(sizeof *new_node);
if (new_node) {
new_node->x = x;
new_node->next = *stk;
*stk = new_node;
}
return new_node;
}
void stack_pop(struct stack **stk, int *x)
{
struct stack *next_node = (*stk)->next;
*x = (*stk)->x;
free (*stk);
*stk = next_node;
}
void stack_destroy(struct stack **stk)
{
struct stack *next_node;
while (*stk != NULL) {
next_node = (*stk)->next;
free (*stk);
*stk = next_node;
}
}
----------
The above is (obviously) completely without recursion. It can
fail, but so can yours: it's just a question of how long it takes
to hit the limit of your system (for both versions).
HAND,
Micah