#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>


void push(uint32_t a, uint32_t **stackpp)
{
    **stackpp = a;
    (*stackpp)++;
}

uint32_t pop(uint32_t **stackpp)
{
    (*stackpp)--;
    return **stackpp;
}

uint32_t fib(uint32_t a)
{
    uint32_t stack[10000] = {0};
    uint32_t *stackp = stack;
    uint32_t where_to_go;
    
    // локальные дефайны
    #define PUSH(x) push(x, &stackp)
    #define POP() pop(&stackp)
    #define AFTER_P1 0
    #define AFTER_P2 1
    #define RESULT 2
    #define GOTO_VAL(x) do{where_to_go = (x); goto wtg_l;}while(0)

    PUSH(RESULT);
    PUSH(a);
    while(stackp != stack)
    {
        uint32_t tmp = POP();
        if (tmp == 0)
        {
            uint32_t ret = POP();
            PUSH(0);
            GOTO_VAL(ret);
        }
        else if (tmp == 1)
        {
            uint32_t ret = POP();
            PUSH(1);
            GOTO_VAL(ret);
        }
        else
        {
            PUSH(tmp-2); // предварительно сохраняем
            PUSH( AFTER_P1 );
            PUSH(tmp-1);
            continue;
            
            after_p1:;
            uint32_t tmp1 = POP(); // возвращенное значение
            uint32_t tmp2 = POP(); // предварительно сохраненное
            PUSH(tmp1);
            PUSH(AFTER_P2);
            PUSH(tmp2);
            continue;
            
            after_p2:;
            uint32_t val = POP()+POP();
            int ret = POP();
            PUSH(val);
            GOTO_VAL(ret);
        }
    }
    // ERROR - стек размотался. Такого быть не должно
    exit(-1);

    wtg_l:
    switch(where_to_go)
    {
      case AFTER_P1: goto after_p1;
      case AFTER_P2: goto after_p2;
      case RESULT:   goto result;
      default: exit(-1); // хуйня какая-то, хуй знает куда прыгать
    }
  
    result:
    return POP();
    // убираем локальные дефайны
    #undef PUSH 
    #undef POP
    #undef AFTER_P1
    #undef AFTER_P2
    #undef RESULT
    #undef GOTO_VAL
}

int main(void)
{
    for(uint32_t i = 0; i < 30; i++)
    {
        printf("%" PRIu32 ", ", fib(i));
    }
    return EXIT_SUCCESS;
}