Реализации Common Lisp: интерпретатор и компилятор
В Common Lisp тип выполнения кода зависит от того, что реализует система Lisp и как вы ее используете. Часто реализации Common Lisp имеют несколько способов выполнения кода: интерпретатор и один или несколько компиляторов. Это может быть даже в одной работающей реализации, и это позволит пользователю переключаться между ними.
Интерпретатор: выполнение непосредственно из структуры данных Лиспа. Это не интерпретатор кода виртуальной машины, как JVM. Нельзя ожидать, что интерпретатор проверяет полное дерево/граф кода во время выполнения. Интерпретатор обычно смотрит только на текущую верхнюю форму, которую он выполняет.
Компилятор: компилирует код Лиспа в C, некоторый байт-код или машинный код. Поскольку компилятор генерирует код перед его запуском, он выполняет проверку синтаксиса всего кода (возможное исключение, см. примечание внизу), которое он видит.
Оценка верхнего уровня: может использоваться интерпретатор, компилятор или их сочетание.
GNU CLISP имеет как интерпретатор, так и компилятор
Пример в GNU CLISP:
ЗАГРУЗКА текстового файла обычно использует интерпретатор:
[1]> (load "test.lisp")
;; Loading file test.lisp ...
;; Loaded file test.lisp
T
Интерпретатор не обнаружит ошибку, потому что он не проверяет все выражение на синтаксическую правильность. Поскольку предложение else с синтаксической ошибкой никогда не используется, интерпретатор никогда не будет его просматривать.
CLISP также имеет компилятор:
[2]> (compile-file "test.lisp")
;; Compiling file /tmp/test.lisp ...
** - Continuable Error
in #:|1 1 (IF T 1 ...)-1| in line 1 : Form too short, too few arguments: (IF)
If you continue (by typing 'continue'): Ignore the error and proceed
The following restarts are also available:
ABORT :R1 Abort main loop
Как видите, компилятор CLISP обнаруживает синтаксическую ошибку и выдает четкое сообщение об ошибке.
SBCL использует компилятор, но также имеет интерпретатор
SBCL по умолчанию использует компилятор, который обнаружит ошибку. Для форм верхнего уровня он использует для некоторых форм более простой механизм оценки. Можно также переключиться на переводчика.
Если вы пишете простую форму IF на SBCL, оценщик не использует полную компиляцию и не перехватывает ошибку:
CL-USER> (if t 1 (if))
1
Если вы напишите тот же код внутри определения функции, ошибка будет обнаружена, потому что определения функций будут скомпилированы по умолчанию:
CL-USER> (defun foo () (if t 1 (if)))
; in: DEFUN FOO
; (IF)
;
; caught ERROR:
; error while parsing arguments to special operator IF:
; too few elements in
; ()
; to satisfy lambda list
; (SB-C::TEST SB-C::THEN &OPTIONAL SB-C::ELSE):
; between 2 and 3 expected, but got 0
;
; compilation unit finished
; caught 1 ERROR condition
WARNING: redefining COMMON-LISP-USER::FOO in DEFUN
FOO
Если бы вы переключились на полный интерпретатор SBCL, ошибка не была бы обнаружена во время определения:
CL-USER> (setf *evaluator-mode* :interpret)
:INTERPRET
CL-USER> (defun foo () (if t 1 (if)))
WARNING: redefining COMMON-LISP-USER::FOO in DEFUN
FOO
Оптимизация и проверка синтаксиса
Обратите внимание, что некоторые оптимизирующие компиляторы могут не проверять синтаксис недостижимого кода.
Сводка
В большинстве реализаций Common Lisp вам нужно использовать компилятор для получения полных синтаксических предупреждений/ошибок.
person
Rainer Joswig
schedule
04.11.2016