На этом шаге мы рассмотрим работу со стеком.
Функция PUSH помещает S-выражение в стек:
(PUSH S-выражение Стек)
Вызов PUSH добавляет в начало списка, являющегося значением атома Стек, S-выражение, обновляя значение атома Стек.
Функция POP выталкивает элемент из стека. Ее синтаксис:
(POP Стек)
$ (SETQ Y (4 5)) (4 5) $ (PUSH (3) Y) ((3) 4 5) $ (POP Y) (3) $ Y (4 5)
(DEFUN PUSH (LAMBDA (A STACK) (SETQ STACK (CONS A (EVAL STACK))) ))
(DEFUN MKTOWER (LAMBDA (NUM ALPHABET TOWER) (LOOP ( (ZEROP NUM) (REVERSE TOWER) ) (PUSH (POP ALPHABET) TOWER) (SETQ NUM (- NUM 1)) ) ))
(DEFUN PRNSTR (LAMBDA (LST) (LOOP ( (NULL LST) ) (PRIN1 (POP LST)) ) ))
(SETQ GENSYM 0) (DEFUN GENSYM (LAMBDA (NUM LST) (SETQ NUM (- 4 (LENGTH GENSYM))) (LOOP ( (ZEROP NUM) ) ( PUSH 0 LST ) ( SETQ NUM (- NUM 1)) ) (PROG1 (PACK (NCONC (CONS (QUOTE G) LST) (LIST GENSYM))) (SETQ GENSYM (+ GENSYM 1)) ) ))
Y = A LST = ((A B) A (C (A (A D)))),
(DEFUN MAIN (LAMBDA (Y LST) (SETQ W (COPY LST LST Y)) (COPY1 W W) )) ; ---------------------------- ; (DEFUN COPY (LAMBDA (LST LST1 Y) ; Построение списка, конгруэнтного списку LST и ; ; содержащего различные (!) атомы вида G*** вместо ; ; вхождений атома Y ; (COND ( (NULL LST) NIL ) ( (AND (ATOM LST) (EQ LST Y)) (GENSYM) ) ( (AND (ATOM LST) (NOT (EQ LST Y))) LST ) ( T (CONS (COPY (CAR LST) LST1 Y) (COPY (CDR LST) LST1 Y) ) ) ) )) ; --------------------------- ; (DEFUN COPY1 (LAMBDA (LST LST1) ; Построение списка, конгруэнтного списку LST и со- ; ; держащего "глубины погружения" атомов G*** в список ; ; LST вместо них самих ; (COND ( (NULL LST) NIL ) ( (AND (ATOM LST) (EQ (CAR (UNPACK LST)) G)) (POISK LST LST1) ) ( (AND (ATOM LST) (NOT (EQ (CAR (UNPACK LST)) G))) LST ) ( T (CONS (COPY1 (CAR LST) LST1) (COPY1 (CDR LST) LST1)) ) ) )) ; ----------- ; (SETQ GENSYM 0) (DEFUN GENSYM (LAMBDA (NUM LST) ; Формирование новых атомов ; (SETQ NUM (- 4 (LENGTH GENSYM))) (LOOP ( (ZEROP NUM) ) ( PUSH 0 LST ) ( SETQ NUM (- NUM 1)) ) (PROG1 (PACK (NCONC (CONS (QUOTE G) LST) (LIST GENSYM))) (SETQ GENSYM (+ GENSYM 1)) ) )) ; ------------------------ ; (DEFUN POISK (LAMBDA (X LST) ; Нахождение "глубины погружения" X в список LST ; (COND ( (MEMBER X LST) 1 ) ( (MEMBER2 X (CAR LST)) (+ 1 (POISK X (CAR LST))) ) ( T (POISK X (CDR LST)) ) ) )) ; -------------------------- ; (DEFUN MEMBER2 (LAMBDA (X LST) ; Предикат MEMBER2 устанавливает вхождение элемента X ; ; в многоуровневый список LST ; (COND ( (NULL LST) NIL) ( T (OR (COND ( (ATOM (CAR LST)) (EQ X (CAR LST)) ) ( T (MEMBER2 X (CAR LST)) ) ) (MEMBER2 X (CDR LST))) ) ) ))
Функция (POP SYMBOL) возвращает "верхушку" (CAR) стека (списка), который называется SYMBOL, и заменяет значение SYMBOL на оставшуюся часть (CDR) стека. Например:
$ (SETQ STACK-LIST '(A B C D E F)) (A B C D E F) $ (POP STACK-LIST) A $ (POP STACK-LIST) B $ (POP STACK-LIST) C $ STACK-LIST (D E F)
Если SYMBOL не является символом, то возникает прерывание по ошибке "Несимвольный аргумент".
Если значение SYMBOL - не точечная пара, то функция POP возвращает NIL.
Данная специальная функция - это LISP-аналог выражения на машинном языке, предназначенного для выборки информации из "верхушки" стека.
Приведем реализацию функции в виде макроса:
(DEFMACRO POP (SYM) (LIST 'PROG1 (LIST 'CAR SYM) (LIST 'SETQ SYM (LIST 'CDR SYM))) )
Функция (PUSH FORM SYMBOL) оценивает FORM, "проталкивает" результат в стек (в SYMBOL) и заменяет значение SYMBOL на увеличенный стек. Функция PUSH возвращает увеличенный стек (список). Например:
$ (SETQ STACK-LIST NIL) NIL $ (PUSH 'A STACK-LIST) (A) $ (PUSH 'B STACK-LIST) (B A) $ (PUSH 'C STACK-LIST) (C B A) $ STACK-LIST (C B A)
Если SYMBOL не является символом, то возникает прерывание по ошибке "Несимвольный аргумент".
Данная функция - это LISP-аналог выражения на машинном языке, предназначенного для размещения информации в "верхушке" стека.
Приведем реализацию функции в виде макроса:
(DEFMACRO PUSH (OBJ SYM) (LIST 'SETQ SYM (LIST 'CONS OBJ SYM)) )
Со следующего шага мы начнем рассматривать работу с файлами.