Я попытаюсь объяснить наивный подход к компиляции вложенных lambda
с.Поскольку объяснение Грега о расширении let
в lambda
очень хорошее, я вообще не буду обращаться к let
, я предполагаю, что let
является производной формой или макросом и разворачивается в lambda
форма, которая вызывается немедленно.
Компиляция функций Lisp или Scheme непосредственно в функции C или C ++ будет сложной из-за проблем, возникших у других авторов.В зависимости от подхода полученный C или C ++ не будет распознаваемым (или даже очень читабельным).
Я написал компилятор Lisp-to-C после завершения Структуры и Интерпретации компьютерных программ (это один изЗаключительные упражнения, и на самом деле я обманул и просто написал переводчик из SICP байт-кода в C).Подмножество C, которое оно излучало, вообще не использовало функции C для обработки функций Lisp.Это связано с тем, что машинный язык регистров в главе 5 SICP действительно ниже уровня C.
Предполагая, что у вас есть какая-то форма окружения, которая связывает имена со значениями, вы можете определить суть вызова функции следующим образом: расширить среду, в которой была определена функция, с помощью формальных параметров, связанных с аргументами, а затем оценить тело функции в этой новой среде.
В компиляторе SICP среда содержится в глобальной переменной.и есть другие глобальные переменные, содержащие список аргументов для вызова функции, а также вызываемый объект процедуры (объект процедуры содержит указатель на среду, в которой он был определен) и метку, к которой можно перейтифункция возвращает.
Имейте в виду, что при компиляции выражения lambda
есть два синтаксических компонента, которые вы знаете во время компиляции: формальные параметры и тело lambda
.
Когда функция компилируется, EMIКод tted выглядит примерно так: псевдокод:
some-label
*env* = definition env of *proc*
*env* = extend [formals] *argl* *env*
result of compiling [body]
...
jump *continue*
... где *env*
и *argl*
- глобальные переменные, содержащие список окружения и аргументов, а extend
- некоторая функция (это может бытьправильная функция C ++), которая расширяет среду *env*
путем сопряжения имен в *argl*
со значениями в [formals]
.
Затем, когда запускается скомпилированный код, и существует вызов этого lambda
где-то еще в вашем коде, соглашение о вызовах должно помещать результат оценки списка аргументов в переменную *argl*
, помещать метку возврата в переменную *continue*
, а затем переходить к some-label
.
В случае вложенных lambda
с, излучаемый код будет выглядеть примерно так:
some-label
*env* = definition env of *proc*
*env* = extend [formals-outer] *argl* *env*
another-label
*env* = definition env of *proc*
*env* = extend [formals-inner] *argl* *env*
result of compiling [body-inner]
...
jump *continue*
rest of result of compiling [body-outer]
... somewhere in here there might be a jump to another-label
jump *continue*
Это немного сложно объяснить, и я уверен, что я запуталсяработа этого.Я не могу придумать достойного примера, который бы не касался меня в основном небрежно, описывая целую главу 5 SICP.Поскольку я потратил время на написание этого ответа, я собираюсь опубликовать его, но мне очень жаль, если он безнадежно запутывает.
Я настоятельно рекомендую SICP и Lispв Small Pieces .
SICP охватывает метациркулярную интерпретацию для начинающих, а также ряд вариантов интерпретатора и компилятор байтового кода, который мне удалось запутать и покалечить выше.Это только две последние главы, первые 3 главы также хороши.Это прекрасная книга.Абсолютно прочитайте его, если вы еще этого не сделали.
LiSP включает в себя несколько интерпретаторов, написанных на Scheme, компилятор для байтового кода и компилятор для C. Я в середине и могу с уверенностью сказатьЭто глубокая, богатая книга, достойная внимания тех, кто интересуется внедрением Lisp.Это может быть немного устаревшим к этому моменту, но для начинающего, как я, это все еще ценно.Он более продвинутый, чем SICP, поэтому будьте осторожны.Он включает в себя главу посередине о денотационной семантике, которая в основном шла прямо у меня над головой.
Некоторые другие примечания:
Самодостаточный компилятор Lisp to C Дариуса Бэкона
лямбда-лифтинг , это более продвинутая техника, которую, я думаю, использует Марк Фили