На этом шаге мы рассмотрим общие вопросы создания интерпретаторов.
Предположим, что мы хотим получить транслятор с языка L на машину M и при этом написать его на самом языке L. L может быть языком, специально предназначенным для написания трансляторов, или языком высокого уровня. Желание написать транслятор на том же языке вполне естественно, если нет другого подходящего языка, кроме, быть может, автокода. Здесь можно выбрать следующую линию поведения.
Написать транслятор на Макроассемблере для небольшого подмножества L0 языка L. Это подмножество должно быть достаточно малым, чтобы его легко можно было реализовать, и достаточно большим, чтобы использовать его на следующем шаге. Следующий шаг состоит в переписывании транслятора с L0 на самом L0 и его отладке. Теперь мы попытаемся с помощью "раскрутки" (Bootstrapping) шаг за шагом подняться до языка L. На каждом шаге i, i=1, 2, ..., n, транслятор для L[i-1] расширяется до транслятора с языка Li с помощью добавления новых свойств из языка L. На каждом шаге старые части текущего транслятора можно переписать на новом языке Li, чтобы использовать его новые свойства. Главная причина расширения транслятора с L0 до компилятора с Ln=L за несколько шагов вместо одного в том, что на каждом шаге мы имеем более мощный язык Li для написания очередного расширения, что сильно облегчает работу [1, с.511-512].
"Иногда трудно противостоять давлению, оказываемому для включения различных возможностей, которые "тоже было бы неплохо иметь в наличии". Вполне реальна опасность, что желание угодить всем будет мешать задаче получить целостный проект. Я всегда старался выяснить, какую цену придется заплатить за получаемый выигрыш. Например, когда рассматривается включение некоторого свойства языка или добавление особого режима компиляции для достаточно часто встречающейся конструкции, нужно сопоставить получаемую выгоду и дополнительную стоимость его реализации и просто его присутствия, которое ведет к увеличению системы. Разработчики языка при этом часто терпят неудачу"[2].
Учтите, что некоторые расширения языка LISP послужили основанием для того, чтобы ошибочно считать его громоздким языком, занимающим память объемом в мегабайты!
Аналогично можно написать интерпретаторы для совсем других языков, даже для императивных, таких как Pascal, хотя, чтобы сделать это, нужно обычно переписать интерпретируемый язык в форме S-выражений [1, с.126].
Не следует также забывать и о том, что система LISP является скорее интерпретирующей, чем компилирующей: машинная программа для вычисления функции не может быть составлена вне процесса вычисления, до него, потому что окончательный вид функции неизвестен заранее.
Со следующего шага мы начнем рассматривать вопросы создания транслятора с языка LISP на muLISPe.