Одним из решений является то, что иногда называют «батутным стилем».Батут представляет собой цикл верхнего уровня, который отправляет небольшим функциям, которые выполняют небольшой шаг вычисления перед возвратом.
Я сидел здесь почти полчаса, пытаясь придумать хороший, короткий пример.К сожалению, я должен сделать бесполезную вещь и отправить вам ссылку:
http://en.wikisource.org/wiki/Scheme:_An_Interpreter_for_Extended_Lambda_Calculus/Section_5
Статья называется «Схема: интерпретатор для расширенного лямбда-исчисления», а раздел 5 реализуетрабочий интерпретатор схем на устаревшем диалекте Лиспа.Секрет в том, как они используют ** CLINK ** вместо стека.Другие глобальные переменные используются для передачи данных между функциями реализации, такими как регистры ЦП.Я бы проигнорировал ** QUEUE **, ** TICK ** и ** PROCESS **, поскольку они имеют дело с многопоточными и фальшивыми прерываниями.** EVLIS ** и ** UNEVLIS **, в частности, используются для оценки аргументов функции.Неоцененные аргументы хранятся в ** UNEVLIS **, пока они не будут оценены и переданы в ** EVLIS **.
Функции, на которые следует обратить внимание, с некоторыми небольшими примечаниями:
MLOOP: MLOOPэто основной цикл интерпретатора, или «батут».Игнорируя ** TICK **, его единственная задача - вызывать любую функцию в ** PC **.Снова и снова и снова.
SAVEUP: SAVEUP объединяет все регистры в ** CLINK **, что в основном совпадает с тем, когда C сохраняет регистры в стек перед вызовом функции.** CLINK ** на самом деле является «продолжением» для переводчика.(Продолжение - это просто состояние вычисления. Технически, сохраненный кадр стека также является продолжением. Следовательно, некоторые Лиспы сохраняют стек в кучу для реализации call / cc.)
RESTORE: RESTORE восстанавливает "регистры ", как они были сохранены в ** CLINK **.Это похоже на восстановление стекового фрейма на основе стекового языка.Таким образом, это в основном «возврат», за исключением того, что некоторая функция явно вставила возвращаемое значение в ** VALUE **.(** VALUE ** явно не перекрывается RESTORE.) Также обратите внимание, что RESTORE не всегда имеет для возврата к вызывающей функции.Некоторые функции фактически СОХРАНЯЮТ совершенно новые вычисления, которые RESTORE с радостью «восстановит».
AEVAL: AEVAL - это функция EVAL.
EVLIS: EVLIS существует для оценки аргументов функции и примененияфункция этих аргументов.Чтобы избежать рекурсии, это ЭКОНОМИЯ ЭВЛИС-1.EVLIS-1 был бы просто обычным старым кодом после применения функции, если код был написан рекурсивно.Однако, чтобы избежать рекурсии и стека, это отдельное «продолжение».
Надеюсь, я вам чем-то помог.Я просто хотел бы, чтобы мой ответ (и ссылка) был короче.