Преобразование 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, например), это потребует дополнительная реализация.


я попытаюсь объяснить наивный подход к компиляции вложенных lambdas. С объяснения Грега о расширении 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.

в случае вложенных lambdas, испущенный код будет выглядеть что-то вот так:

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?