Преобразование Lisp в C++
Я работаю над языком игрушек, который компилируется на C++ на основе lisp (очень маленькое подмножество схемы), я пытаюсь выяснить, как представить выражение let,
(let ((var 10)
(test 12))
(+ 1 1)
var)
сначала я думал, что выполнить все exprs, а затем вернуть последний, но возвращение убьет мою способность вложить выражения let, каков будет способ представления let?
кроме того, любые ресурсы на source to source transformation апприцируются, у меня есть googled, но все, что я мог бы Компилятор схемы 90 мин.
3 ответов
один из способов расширить let
рассматривать его как lambda
:
((lambda (var test) (+ 1 1) var) 10 12)
затем преобразуйте это в функцию и соответствующий вызов на C++:
int lambda_1(int var, int test) {
1 + 1;
return var;
}
lambda_1(10, 12);
Итак, в более широком контексте:
(display (let ((var 10)
(test 12))
(+ 1 1)
var))
становится
display(lambda_1(10, 12));
есть гораздо больше деталей, таких как необходимость доступа к лексическим переменным за пределами let
внутри let
. Поскольку C++ не имеет лексически вложенных функций (в отличие от Pascal, например), это потребует дополнительная реализация.
я попытаюсь объяснить наивный подход к компиляции вложенных
lambda
s. С объяснения Грега о расширении let
на lambda
очень хорошо, я не буду let
вообще, я предполагаю, что let
is
производная форма или макрос и расширяется в lambda
форма это
позвонил немедленно.
компиляция функций Lisp или Scheme непосредственно в функции C или c++ будет сложно из-за вопросов, поднятых другими плакатами. В зависимости от подход, полученный C или c++ не известные (или даже очень читабельно).
я написал компилятор Lisp-to-C после завершения структуры и интерпретации компьютерных программ (это одно из заключительных упражнений, и на самом деле я обманул и просто написал переводчик с байтового кода SICP на C). Подмножество C, которое оно излучало, не использовало функции C для обработки функций Lisp вообще. Это потому что Регистрация машинного языка в главе 5 SICP действительно ниже уровня чем С.
при условии, что вы имея некоторую форму сред, которые связывают имена со значениями, вы можете определить суть вызова функции следующим образом: расширить среду, в которой функция была определена, с формальными параметрами, связанными с аргументами, а затем оценить тело функции в этой новой среде.
в компиляторе SICP среда хранится в глобальной переменной, и есть другие глобальные переменные, содержащие список аргументов для вызова функции, как а также объект процедуры, который вызывается (объект процедуры включает указатель на среду, в которой он был определен) и метку для перехода, когда функция возвращается.
имейте в виду, что при компиляции lambda
выражение, есть
два синтаксических компонентов, вы знаете, во время компиляции: официальное
параметры и тело lambda
.
когда функция компилируется, испускаемый код выглядит примерно так этот псевдокод:
some-label
*env* = definition env of *proc*
*env* = extend [formals] *argl* *env*
result of compiling [body]
...
jump *continue*
... где *env*
и *argl*
глобальные переменные держит
окружение и список аргументов, и extend
- некоторая функция (это может
быть правильной функцией C++), которая расширяет среду *env*
by
сопряжение имен в *argl*
С [formals]
.
затем, когда скомпилированный код запускается, и есть вызов этого
lambda
где-то еще в вашем коде соглашение о вызове должно поставить
результат оценки списка аргументов в *argl*
переменная, поместите метку возврата в the *continue*
переменной, а затем перейти к some-label
.
в случае вложенных lambda
s, испущенный код будет выглядеть что-то
вот так:
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 и шепелявить маленькими кусочками.
SICP охватывает метациркулярную интерпретацию для начинающих, а также ряд вариантов интерпретатора и компилятор байтового кода, который мне удалось запутать и исказить выше. Вот только последние две главы, первые 3 Главы так же хорошо. Это замечательная книга. Обязательно прочтите, если еще нет.
Л. Я.С. П включает в себя количество интерпретаторов, написанных в схеме, компилятор для байтового кода и компилятор для C. я нахожусь в середине этого и могу с уверенностью сказать, что это глубокая, богатая книга, которая стоит времени всех, кто заинтересован в реализации Lisp. Он может быть немного устарел к этому моменту, но для новичка, как я, он все еще ценен. Он более продвинутый, чем SICP, поэтому будьте осторожны. Он включает главу в середине о денотационной семантике, которая прошла в основном прямо над моей головой.
некоторые другие Примечания:
Дариус бекон Селф-хостинг Лисп для компилятора C
лямда-подъемно -, который является более продвинутым методом, который, я думаю, Марк Фили использует
если вы ищете инструменты, чтобы помочь с переводом из источника в источник, я бы рекомендовал ANTLR. Это превосходно.
однако вам нужно подумать о том, как перевести с свободно типизированного языка (lisp) на менее свободно типизированный язык (c). Например, в вашем вопросе, что то типа 10
? А short
? Ан int
? А double
?