Cómo se implementa un lenguaje interpretado "sin pila"?

Estoy haciendo mi propio lenguaje interpretado similar a Lisp, y quiero hacer una optimización de llamadas de cola. Quiero liberar a mi intérprete de la pila C para poder administrar mis propios saltos de una función a otra y mi propia magia de pila para lograr el TCO. (Realmente no quiero decir sin pila en sí, solo el hecho de que las llamadas no agregan marcos a la pila C. Me gustaría usar una pila propia que no crezca con las llamadas de cola). Como Python apilable, y a diferencia de Ruby o ... Python estándar, supongo.

Pero, como mi lenguaje es un derivado de Lisp, toda la evaluación de las expresiones s se realiza actualmente de forma recursiva (porque es la forma más obvia en la que pensé hacer este proceso no lineal y altamente jerárquico). Tengo una función eval, que llama a una función Lambda :: apply cada vez que encuentra una llamada a la función. La función de aplicación llama a eval para ejecutar el cuerpo de la función, y así sucesivamente. Mutua hambruna recidiva C sin cola. La única parte iterativa que uso actualmente es evaluar un cuerpo de expresiones s secuenciales.

(defun f (x y)
    (a x y)) ; tail call! goto instead of call. 
             ; (do not grow the stack, keep return addr)

(defun a (x y)
    (+ x y))

; ...

(print (f 1 2)) ; how does the return work here? how does it know it's supposed to
                ; return the value here to be used by print, and how does it know
                ; how to continue execution here??

Entonces, ¿cómo evito usar la recursión C? ¿O puedo usar algún tipo de goto que salte a través de las funciones c? Longjmp, tal vez? Realmente no lo se. Por favor, tengan paciencia conmigo, soy mayormente autodidacta (Internet) en programación.