Шаг 100.
Проектирование интерпретатора. Текст учебного интерпретатора

    На этом шаге мы приведем текст учебного интерпретатора.

    Программа. Учебный интерпретатор LISP на диалекте muLISP.

   (PROG1 "" (PUTD DEFUN (QUOTE (NLAMBDA (FUNC DEF)
                                (PUTD FUNC DEF) FUNC ))))
   ; ------------------------------------- ;
   ; Интерпретатор LISP на диалекте muLISP ;
   ; ------------------------------------- ;
   (DEFUN muLISP (LAMBDA NIL
   ; Диалог с пользователем ;
      (PRINT "Учебный muLISP-92  1.01  (06/10/92)")
      (PRINT
      "Copyright (C) McCarthy & Hyvonen & Seppanen & RGPU")
      (TERPRI) (PRIN1 " <-- ")
      ( LOOP
           (SETQ EXPRESSION (READ))
           ( (EQUAL EXPRESSION (LIST SYSTEM1)) 'BYE-BYE )
           (PRIN1 " --> ") (PRINT (EVAL1 EXPRESSION NIL))
           (PRIN1 " <-- ")
      )
   ))
   ; ------------------------------ ;
   (DEFUN EVAL1 (LAMBDA (FORMA SWQZI)
     (COND  ( (ATOM FORMA)    ; FORMA является атомом ;
               (COND  ( (EQ FORMA T1)    T1    )
                      ( (EQ FORMA NIL1)  NIL1  )
                      ( (NUMBERP FORMA)  FORMA )
                      ; Поиск в A-списке SWQZI значения ;
                      ; атома FORMA                     ;
                      ( (NULL (ASSOC FORMA SWQZI))
                          ; Поиск в списке свойств  ;
                          ; значения свойства VALUE ;
                          ; атома FORMA             ;
                          (COND ( (NULL (GET FORMA VALUE))
                                     FORMA )
                                (  T  (GET FORMA VALUE) ))
                      )
                      (  T  (CDR (ASSOC FORMA SWQZI)) )
               )
            )
            ; ---------------- ;
            ( (ATOM (CAR FORMA))
              ; Голова списка FORMA - атом ;
               (COND  ( (EQ (CAR FORMA) QUOTE1)
                            (CADR FORMA) )
                      ; -------------------- ;
                      ( (EQ (CAR FORMA) COND1)
                            (EVAL-COND (CDR FORMA) SWQZI) )
                      ; --------------------------------- ;
                      ( (EQ (CAR FORMA) SETQ1)
                      ; Помещение значения атома     ;
                      ; (CAR FORMA) в список свойств ;
                           (PUT (CADR FORMA) VALUE
                                (CADDR FORMA)) )
                      ; -------------------- ;
                      ( (EQ (CAR FORMA) GETD1)
                      ; Моделирование функции GETD ;
                            (GET (CADR FORMA) FUN)
                      )
                      ; ---------------------------------- ;
                      ;  Вызов  б а з и с н ы х  функций:  ;
                      ;  CAR1, CDR1, CONS1, ATOM1, EQUAL1, ;
                      ;  Вызов вспомогательных функций:    ;
                      ;  PLUS1,DIFFERENCE1,TIMES1          ;
                      ;  GREATERP1,LESSP1                  ;
                      ; ---------------------------------- ;
                      ( (MEMBER (CAR FORMA)
                            (QUOTE
                               (CAR1 CDR1 CONS1 ATOM1 EQUAL1
                                PLUS1 DIFFERENCE1 TIMES1
                                GREATERP1 LESSP1)
                            )
                        )
                           (APPLY1 (CAR FORMA)
                                   (EVAL-SPISOK (CDR FORMA)
                                                SWQZI)
                                    SWQZI)
                      )
                      ; --------------------- ;
                      ( (EQ (CAR FORMA) DEFUN1)
                      ; LAMBDA-определение помещается в   ;
                      ;          список свойств           ;
                      ; в свойство FUN имени (CADR FORMA) ;
                           (PUT (CADR FORMA) FUN
                                (CADDR FORMA))
                      )
                      ; ---------------- ;
                      ; Создание макроса ;
                      ( (EQ (CAR FORMA) DEFMACRO1)
                      ; NLAMBDA-определение помещается в ;
                      ; список свойств в свойство NFUN   ;
                      ;       имени (CADR FORMA)         ;
                            (PUT (CADR FORMA) NFUN
                                 (LIST
                                   NLAMBDA1
                                   (CADR (CADDR FORMA))
                                   (CADDR (CADDR FORMA))))
                      )
                      ; -------------------------------- ;
                      ; Вызов функции пользователя.      ;
                      ; Вызываемые пользователем функции ;
                      ; определены предложением LAMBDA1, ;
                      ; которое является свойством FUN   ;
                      ;           имени функции          ;
                      ; -------------------------------- ;
                      ( (GET (CAR FORMA) FUN)
                        ; Функция GET возвращает значение   ;
                        ; свойства FUN имени (CAR FORMA)    ;
                        ; или NIL, если такого свойства нет ;
                             (APPLY1 (GET (CAR FORMA) FUN)
                                     (EVAL-SPISOK (CDR FORMA)
                                                  SWQZI)
                                      SWQZI)
                      )
                      ; --------------------------------- ;
                      ; Вызов функции пользователя.       ;
                      ; Вызываемые пользователем функции  ;
                      ; определены предложением NLAMBDA1, ;
                      ; которое является свойством NFUN   ;
                      ;           имени функции           ;
                      ; --------------------------------- ;
                      ( (GET (CAR FORMA) NFUN)
                             (APPLY1
                                (GET (CAR FORMA) NFUN)
                                (NOT-EVAL-SPISOK (CDR FORMA))
                                 SWQZI)
                      )
                      ; ------------------------------ ;
                      (  T  (PRIN1 "Unknown function: ")
                            (PRINT (CAR FORMA)) )
               )
            )
            ; -------------------------------------------- ;
            ; FORMA - предложение вида:                    ;
            ; ((LAMBDA1 Формальные_параметры Тело_функции) ;
            ;              Фактические_параметры)          ;
            ( (EQ (CAAR FORMA) LAMBDA1)
                  (APPLY1
                     (CAR FORMA)
                     (EVAL-SPISOK (CDR FORMA) SWQZI) SWQZI)
            )
            ; --------------------------------------------- ;
            ; FORMA - предложение вида:                     ;
            ; ((NLAMBDA1 Формальные_параметры Тело_функции) ;
            ;              Фактические_параметры )          ;
            ; --------------------------------------------- ;
            ( (EQ (CAAR FORMA) NLAMBDA1)
                  (APPLY1
                     (CAR FORMA)
                     (NOT-EVAL-SPISOK (CDR FORMA)) SWQZI)
            )
            ; -------------------------- ;
            (  T  (PRINT "Syntax error") )
     )
   ))
   ; ----------------------------------------- ;
   (DEFUN APPLY1 (LAMBDA (FUNCT ARGUMENTS SWQZI)
   ; Функция возвращает результат применения функции ;
   ;          FUNCT к аргументам ARGUMENTS           ;
      (COND ( (ATOM FUNCT)            ; FUNCT - атом ;
                 (COND ( (EQ FUNCT CAR1)
                            (COND
                               ( (EQ (CAR ARGUMENTS) NIL1)
                                     NIL1 )
                               (   T   (CAAR ARGUMENTS) ))
                       )
                       ; ------------- ;
                       ( (EQ FUNCT CDR1)
                           (COND ( (EQ (CAR ARGUMENTS) NIL1)
                                      NIL1 )
                                 ( (NULL (CDAR ARGUMENTS))
                                      NIL1 )
                                 ( T  (CDAR ARGUMENTS) ))
                       )
                       ; -------------- ;
                       ( (EQ FUNCT CONS1)
                           (COND ( (EQ (CADR ARGUMENTS) NIL1)
                                     (LIST (CAR ARGUMENTS)) )
                                 (  T  (CONS (CAR ARGUMENTS)
                                       (CADR ARGUMENTS))) )
                       )
                       ; -------------- ;
                       ( (EQ FUNCT ATOM1)
                           (COND ( (ATOM (CAR ARGUMENTS))
                                      T1 )
                                 (  T  NIL1) )
                       )
                       ; --------------- ;
                       ( (EQ FUNCT EQUAL1)
                           (COND ( (EQUAL (CAR ARGUMENTS)
                                          (CADR ARGUMENTS))
                                      Т1 )
                                 (  T  NIL1 ))
                       )
                       ; -------------- ;
                       ( (EQ FUNCT PLUS1)
                           (PLUS (CAR ARGUMENTS)
                                 (CADR ARGUMENTS))
                       )
                       ; -------------------- ;
                       ( (EQ FUNCT DIFFERENCE1)
                           (DIFFERENCE (CAR ARGUMENTS)
                                       (CADR ARGUMENTS))
                       )
                       ; --------------- ;
                       ( (EQ FUNCT TIMES1)
                           (TIMES (CAR ARGUMENTS)
                                  (CADR ARGUMENTS))
                       )
                       ; ------------------ ;
                       ( (EQ FUNCT GREATERP1)
                           (COND ( (GREATERP
                                      (CAR  ARGUMENTS)
                                      (CADR ARGUMENTS)) T1 )
                                 (   T   NIL1 ))
                       )
                       ; --------------- ;
                       ( (EQ FUNCT LESSP1)
                           (COND ( (LESSP
                                      (CAR  ARGUMENTS)
                                      (CADR ARGUMENTS)) T1 )
                                 (   T   NIL1 ))
                       )
                       ; ----------------------------- ;
                       (  T  (APPLY1 (EVAL1 FUNCT SWQZI)
                                      ARGUMENTS SWQZI) )
                 )
            )
            ; ---------------------- ;
            ( (EQ (CAR FUNCT) LAMBDA1)
                 (EVAL1 (CADDR FUNCT)
                        (SOZDAI-SWQZI (CADR FUNCT)
                                      ARGUMENTS SWQZI))
            )
            ; ----------------------- ;
            ( (EQ (CAR FUNCT) NLAMBDA1)
                 (EVAL1 (CADDR FUNCT)
                        (SOZDAI-SWQZI (CADR FUNCT)
                                      ARGUMENTS SWQZI))
            )
            ; --------------------------- ;
            (   T  (PRINT "Syntax error") )
      )
   ))
   ; ------------------------------------- ;
   (DEFUN EVAL-COND (LAMBDA (VETVI CONTEKST)
   ; Определение семантики условного оператора COND1 ;
       (COND ( (NULL VETVI) NIL1 )
             ( (NOT (EQ (EVAL1 (CAAR VETVI) CONTEKST) NIL1))
                        (EVAL1 (CADAR VETVI) CONTEKST) )
             ( T (EVAL-COND (CDR VETVI) CONTEKST) )
       )
   ))
   ; ---------------------------------------- ;
   (DEFUN EVAL-SPISOK (LAMBDA (NEWYCHISL SWQZI)
   ; Вычисление списка значений аргументов ;
   ;           вызываемой функции          ;
      (COND ( (NULL NEWYCHISL) NIL )
            (  T   (CONS (EVAL1 (CAR NEWYCHISL) SWQZI)
                         (EVAL-SPISOK
                            (CDR NEWYCHISL) SWQZI)) )
      )
   ))
   ; -------------------------------------- ;
   (DEFUN NOT-EVAL-SPISOK (LAMBDA (NEWYCHISL)
   ; Запрет вычисления списка значений аргументов ;
   ;            вызываемой функции                ;
      (COND ( (NULL NEWYCHISL) NIL )
            (  T   (CONS (CAR NEWYCHISL)
                         (NOT-EVAL-SPISOK
                             (CDR NEWYCHISL))) )
      )
   ))
   ; -------------------------------------------------- ;
   (DEFUN SOZDAI-SWQZI (LAMBDA (FORMAL FACTICH OKRUGENIE)
   ; Заполнение ассоциативного списка A связей OKRUGENIE ;
      (COND ( (NULL FORMAL)  OKRUGENIE )
            ( (NULL FACTICH) OKRUGENIE )
            (  T  (ACONS (CAR FORMAL) (CAR FACTICH)
                         (SOZDAI-SWQZI (CDR FORMAL)
                                       (CDR FACTICH)
                                       OKRUGENIE)) )
      )
   ))
   ; ---------------------------- ;
   (DEFUN ACONS (LAMBDA (X Y ALIST)
   ; Добавление в начало ассоциативного списка ALIST ;
   ;             точечной пары (X . Y)               ;
        (CONS (CONS X Y) ALIST)
   ))
Текст этой библиотеки можно взять здесь.

    Заметим, что встраивание "слоя интерпретации" является первым шагом на пути создания оригинальных управляющих структур. Интерпретатор, расположенный между стандартными процедурами LISP и программой пользователя, дает возможность программисту совершать сложные "хирургические" операции, если нет желания приспосабливаться к имеющейся версии интерпретатора, которая обычно скрыта в реализации на уровне языка ассемблера.

    Програмист может изобретать новые структуры управления, поскольку материал, из которого такие структуры строятся, ему вполне доступен. Это тот путь, на котором были реализованы многие языки высокого уровня. Обычно за это приходится, однако, дорого платить. Дополнительный уровень интерпретации, вообще говоря, приводит к существенному снижению скорости работы программы.

    Однако заметим, что интерпретаторы важны по трем очень важным причинам.

    Во-первых, они могут обеспечивать удобную интерактивную среду. Многие пользователи-новички находят, что интерактивная среда более удобна, чем компилятор.

    Во-вторых, интерпретаторы языка обеспечивают превосходные интерактивные отладочные возможности. Даже ветераны-программисты при отладке трудных программ прибегают к помощи интерпретатора языка, потому, что он позволяет динамично устанавливать значения переменных и условий.

    В-третьих, большинство языков запросов к базе данных работают в режиме интерпретации.

    На следующем шаге мы приведем некоторые общие положения по отладке программ.




Предыдущий шаг Содержание Следующий шаг