Применение
(DEFUN mul-N (N) #'(LAMBDA (x) (* x N))) ; конструктор семейства функций, множащих ; аргумент на N (funcall (mul-N 25) 7) ; применение частной функции, умножающей на 25
Правильность выражений с такими функциями требует корректной подстановки параметров и учета
x+1 : Number -> Number x+y : (Number Number) -> Number
Отсутствие таких средств в языке можно компенсировать соответствующими комментариями .
Суперпозицию функций можно характеризовать следующими
S(h,g) = { при h: X -> Y, g: Y -> Z строит f=g(h) — суперпозиция }
: (X->Y Y->Z)->(X->Z)
(defun super (f g)
#'(LAMBDA (x) (funcall f (funcall g x)) ))
; конструктор суперпозиции функций
(funcall (super #'CAR #'CDR) '(1 2 3))
; применение суперпозиции CAR и CDR
Двойное применение функции можно определить независимо или через суперпозицию —
W f = ((LAMBDA (x)(f (f x))) = S (f,f)
{ дважды применяется функция }
: (Number->Number) -> (Number->Number)
или более точно:
: (X->X) -> (X->X),
где X — произвольный
(DEFUN duble (f) #'(LAMBDA (x) (funcall f(funcall f x)) )) ; конструктор двойного применения функции (funcall (duble #'CAR) '(((1) 2) 3)) ;= (1) (defun duble (f) (funcall #'super f f)) ; двойное применение функции через суперпозицию (funcall (duble #'CAR) '(((A B) B) C)) ; = (A B)
Можно ввести обозначения:
Atom — атомы, Number — число, List (X) — NIL или списки из элементов типа X, Bool — NIL или T, Some — любой объект, (X . Y) – консолидация X и Y, Y != X – элементы типа Y кроме элементов типа X.
Соответственно пишутся
cons : (X List (X)) -> List (X)
car : List (X) -> X
cdr : List (X) -> List (X)
eq : (Atom Atom) -> Bool
atom : Some -> Bool
: (Atom -> T) | (List (X) -> NIL)
null : Some -> Bool
: (NIL -> T) | (Some != NIL -> NIL)
(List(X)\=NIL -> NIL)
Таким же образом можно специфицировать и
EVAL [e, al]:(Some List( (Atom . Some ) )) -> Some
| |
| List( (Atom . Some) )
Some{ могут попасть и неправильные выражения }
APPLY [fn, (a1 a2 …), al] : (List( Some ) -> Some
| | | List( Some )
| | | List((Atom . Some) )
| | | ) -> Some
| | |
| | | List((Atom . Some))
| List(Some)
(List(Some) -> Some
Отображающий функционал также может характеризоваться
map [x, f]
:( List(X) (X -> Y) ) -> List(Y)
(DEFUN map (x f)
(COND (x (CONS (funcall f (CAR x))
(map (CDR x) f )))))
(map '((1) (2) (3)) #'CAR ) ;= (1 2 3)
Можно специфицировать функцию, непосредственно преобразующую свой
mapf [f]
: List(X -> Y) -> ( List(X) -> List(Y))
(DEFUN mapf (f) #'(LAMBDA (x)
(COND (x (CONS (funcall f (CAR x))
(funcall (mapf f ) (CDR x)) ))) ))
(funcall (mapf #'CAR ) ;=(1 2 3)
Аргумент может быть списком функций, результаты которых следует собрать в общий список.
manyfun [lf] : List(X->Y) -> (X -> List(Y))
| | |_____список результатов функций
| |
| |_____тип аргумента отдельной функции
|
|____________________список функций
(DEFUN manyfun (lf) #'(LAMBDA (x)
(COND (lf (CONS (funcall (CAR lf) x)
(funcall (manyfun (CDR lf)) x) ))) ))
(funcall (manyfun '(CAR CDR length))
'(1 f (2 T)(3 D e)) ) ;= (1 (f (2 T)(3 D e)) 4)
Таким образом можно как бы "просачивать" определения функций над простыми данными, распределять их по структурам данных и тем самым распространять простые функции на сложные данные подобно матричной арифметике. Похожие построения предлагаются Бэкусом в его программной статье о функциональном стиле программирования и в языке
Существует ряд языков функционального программирования, требующих или допускающих спецификацию объектов, что, кроме дисциплины программирования, дает средства для корректной работы с пакетами, сопряжения с модулями на других языках, оптимизирующих
Результативность
В качестве примера такого языка рассмотрен
<а-гр> ::= А | А <а-гр>
<в-гр> ::= В | В <в-гр>
<слог> ::= <а-гр> <в-гр>
| <в-гр> <а-гр>
| <в-гр> <а-гр> <в-гр>
В этой А " и " В " — is-, выделяющий списки, представляющие правильно построенные слоги в соответствии с приведенными правилами.
Пусть тексты этого языка представляются списками из однобуквенных атомов A и B. Допустим, имеются предикаты is-A и is-B, выделяющие одноэлементные списки (A) и (B), соответственно.
(DEFUN is-a (x)(COND ((EQ(CAR x) 'a)
(null (CDR x))) ))
; распознаватель A
(DEFUN is-b (x)(COND ((EQ(CAR x) 'b)
(null (CDR x))) ))
; распознаватель B
Типовые List (X) -> Bool. Таким же должен быть и is-. При ее построении будет применена вспомогательная функция более высокого порядка is-alt, которая из произвольных предикатов конструирует новый предикат, перебирающий варианты правил и выдающий , если ни одно из них не подходит. Функция is-alt может быть определена следующим образом:
(DEFUN is-alt (p q)
; конструктор распознавателя альтернатив
#'(LAMBDA (x)
(COND ((funcall p x )T)
((funcall q x) T)
(T NIL))))
Ее типовый
(List(X)->Bool List(X))->Bool ) )-> List(X))->Bool
Можно использовать эквивалент:
(DEFUN is-alt (p q)
#'(LAMBDA (x)
(if (funcall p x) T (funcall q x))
)
Предикат both, работающий как логическая связка "и", можно реализовать как обычную функцию с типовым (Bool Bool) -> Bool.
(DEFUN both (x y) (COND ( x y)(T NIL)) ) ; проверка одновременности условий
Еще одна вспомогательная функция высокого порядка is- из произвольных предикатов конструирует новый предикат, выясняющий, не выделяют ли исходные предикаты смежные звенья цепочки. Типовый is-alt, т.к. их результаты используются при разборе и анализе текста в одинаковых позициях.
(DEFUN is-chain (p q) #'(LAMBDA (x )
; конструктор распознавателя цепочек
(COND ((null x) (both (funcall p x)
(funcall q NIL)) )
; пустая цепочка
((both (funcall p x) (funcall q NIL)) T)
; префикс без суффикса
((both (funcall p NIL) (funcall q x)) T)
; суффикс без префикса
((both (funcall p (CONS (CAR x)NIL))
(funcall q (CDR x)) ) T)
; допустимое разбиение
(T(funcall (is-chain (LAMBDA(y)(funcall p(CONS(CAR x)y)))
q )
( CDR x) ))
; сдвиг границы разбиения вправо
)))
Из данного is-a можно бы и без is-a-gr, распознающий группу из любого числа символов A:
(defun is-a-gr (x ) (if x ; распознаватель цепочек из A (cond ((eq (car x) 'a) (is-a-tl (cdr x)) ) ; <а-гр> ::= А | А <а-гр> (t nil) ) Nil)) (defun is-a-tl (x)(cond ((null x)T)((eq (car x)'A)(is-a-tl (cdr x )) )))) ; хвост цепочки из A
Но использование конструкторов is-alt и is-, показанное на примере is-b-gr, позволяет построить определение,
(DEFUN is-b-gr (x ) (funcall (is-alt #'is-b is-chain #'is-b #'is-b-gr)) x )) ; распознаватель цепочек из B ; <в-гр> ::= В | В <в-гр>
Теперь опробованные приемы конструирования is-, активно опираясь на чисто внешнее,
(DEFUN is-syllable (x )
; распознаватель слога
(funcall (is-alt (is-chain #'is-b-gr #'is-a-gr)
; слог вида BA
(is-alt (is-chain #'is-a-gr #'is-b-gr)
; слог вида AB
(is-chain #'is-b-gr (is-chain #'is-a-gr #'is-b-gr))
; слог вида BAB
) ) x ))
(is-syllable '(a b))
(is-syllable '(b a))
(is-syllable '(b a b ))
(is-syllable '(b b b b a a b b ))
Сопоставляя правила и полученное определение
| Грамматика | |
|---|---|
<слог>::= |
( |
<в-гр> <а-гр> |
(is-alt (is- |
<а-гр> <в-гр> |
(is-alt (is- |
<в-гр>
<а-гр> <в-гр>
|
(is-chain #'is-b-gr
(is-chain #'is-a-gr #'is-b-gr))
|
) ) x )) |
Конечно, построенное выше определение не отличается эффективностью.
Пусть
( (Тексты (Имя Вариант ...)...)
; первое имя — обозначение системы текстов
; за ним следуют варианты поименованных текстов
(Вариант Элемент ...)
; Вариант представляет собой
; последовательность Элементов
(Элемент Имя Лексема (Варианты))
; Элемент — это или Имя, или Лексема,
; или Варианты в скобках
)
Для
( (пример (ма ((ш н)
(ш а))
( ш н ) )
(н ина)
)
Построение , ass-all, swin, gram,
(DEFUN unic (vac) (remove-duplicates (mapcar 'CAR vac) ))
;; список уникальных начал
(DEFUN ass-all (Key Vac)
;; список всех вариантов продолжения
;; что может идти за ключом
(COND
((Null Vac) NIL)
((EQ (caar Vac) Key) (CONS (cdar Vac)
(ass-all Key (CDR Vac)) ))
(T (ass-all Key (CDR Vac)) )
) )
(DEFUN swin (key varl) (COND
;; очередной шаг свертки или снять скобки при
;; отсутствии вариантов
((null (CDR varl))(CONS key (CAR varl)))
(T (list key (gram varl)) )
))
(DEFUN gram (ltext)
;; левая свертка, если нашлись общие начала
( (LAMBDA (lt) (COND
((EQ (length lt)(length ltext)) ltext)
(T (mapcar
#'(LAMBDA (k) (swin k (ass-all k ltext )
))
lt )
) ) ) (unic ltext)
) )
(DEFUN bnf (main ltext binds) (CONS (CONS main
(gram ltext)) binds))
names, words, , d-, d-names, h-all, all-t, pred, sb-nm, , level1, lang
Функции names, words и задают алфавит и разбивают его на терминальные и
(DEFUN names (vac) (mapcar 'CAR vac))
;; определяемые символы
(DEFUN words (vac) (COND
;; используемые символы
((null vac) NIL)
((ATOM vac) (CONS vac NIL ))
(T (union (words (CAR vac))
(words (CDR vac)))) ))
(DEFUN lexs (vac) (set-difference (words vac)
(names vac)))
;; неопределяемые лексемы
Функции d- и d-names формируют нечто вроде встроенной базы данных, хранящей определения символов для удобства дальнейшей работы.
(DEFUN d-lex ( llex)
;; самоопределение терминалов
(mapcar #'(LAMBDA (x) (set x x) ) llex) )
(DEFUN d-names ( llex)
;; определение нетерминалов
(mapcar #'(LAMBDA (x) (set (CAR x )(CDR x )) )
llex) )
Функции h-all, all-t и pred раскрывают слияния общих фрагментов
(DEFUN h-all (h lt)
;; подстановка голов
(mapcar #'(LAMBDA (a)
(COND
((ATOM h) (CONS h a))
(T (append h a)) )
) lt) )
(DEFUN all-t (lt tl)
;; подстановка хвостов
(mapcar #'(LAMBDA (d)
(COND
((ATOM d) (CONS d tl))
(T(append d tl))
) ) lt) )
(DEFUN pred (bnf tl)
;; присоединение предшественников
(level1 (mapcar #'(LAMBDA (z) (chain z tl )) bnf)
))
Функции sb-nm, и LeveL1 строят развернутые, линейные тексты из частей, выполняя подстановку определений, сборку и выравнивание.
(DEFUN sb-nm (elm tl)
;; подстановка определений имен
(COND
((ATOM (EVAL elm)) (h-all (EVAL elm) tl))
(T (chain (EVAL elm) tl))
) )
(DEFUN chain (chl tl)
;; сборка цепочек
(COND
((null chl) tl)
((ATOM chl) (sb-nm chl tl))
((ATOM (CAR chl))
(sb-nm (CAR chl) (chain (CDR chl) tl) ))
(T (pred (all-t (CAR chl) (CDR chl)) tl)) ))
(DEFUN level1 (ll)
;; выравниваие
(COND
((null ll)NIL)
(T (append (CAR ll) (level1 (CDR ll)) )) ))
На основе приведенных вспомогательных функций общая схема lang:
(DEFUN lang ( frm ) ;; вывод заданной системы текстов (d-lex (lexs frm)) (d-names frm) (pred (EVAL (caar frm)) '(()) ) )
Вот и тесты к этой задаче, предложенные И.Н. Скопиным, справедливо предположившим, что для решения задач
(lang (print (bnf 'vars
'((m a s h a)(m a s h i n a)(s h i n a))
'((n (i n a))) )))
(lang '((vars (m a ((s h a)(s h n))) (s h n) )
(n (i n a)) ) )
Цель
Идентификатор ::= БУКВА
| Идентификатор БУКВА
| Идентификатор ЦИФРА
Удобное для эффективного
Идентификатор ::= БУКВА | БУКВА КонецИд
КонецИд ::= БУКВА КонецИд
| ЦИФРА КонецИд
| ПУСТО
(рис 13.1) Этот пример показывает, что удобные для анализа формулы приведены к виду, когда каждую альтернативу можно выбрать по одному текущему символу. Система CLOS поддерживает ООП с выделением методов для одноэлементных классов, распознаваемых простым сравнением. Тем самым обеспечено удобное построение программ над структурами, подобными
Например, определение:
<а-гр> ::= А | А <а-гр>
<в-гр> ::= В | В <в-гр>
<слог> ::= <а-гр> <в-гр>
| <в-гр> <а-гр>
| <в-гр> <а-гр> <в-гр>
можно привести к виду, не требующему возвратов при анализе:
<а-гр> ::= А <а-кон>
<а-кон> ::= <пусто> | A <а-кон>
<в-гр> ::= B <в-кон>
<в-кон> ::= <пусто> | B <в-кон>
<слог> ::= A <а-кон> B <в-кон>
|B <в-кон> A <а-кон> <в-кон>
Если программирование сводит алгоритм решения задачи к программе из определенной последовательности шагов, то конструирование строит программу решения задачи из решений типовых вспомогательных задач. Для задачи реализации языка программирования ключевой (но не единственной) типовой задачей является определение реализуемого языка. Ее решение открывает возможности автоматизированного конструирования анализаторов и компиляторов. Автоматизацию конструирования системы программирования обеспечивают методы
Все это хорошо изученные задачи, имеющие надежные решения, знания которых достаточно для создания своих языков программирования и проведения экспериментов с программами на своих языках. Существует ряд программных инструментов, поддерживающих автоматизацию процесса создания и реализации языков программирования и более общих информационных систем обработки формализованной информации, например YACC,
Применение
(DEFUN mul-N (N) #'(LAMBDA (x) (* x N))) ; конструктор семейства функций, множащих ; аргумент на N (funcall (mul-N 25) 7) ; применение частной функции, умножающей на 25
Правильность выражений с такими функциями требует корректной подстановки параметров и учета
x+1 : Number -> Number x+y : (Number Number) -> Number
Отсутствие таких средств в языке можно компенсировать соответствующими комментариями .
Суперпозицию функций можно характеризовать следующими
S(h,g) = { при h: X -> Y, g: Y -> Z строит f=g(h) — суперпозиция }
: (X->Y Y->Z)->(X->Z)
(defun super (f g)
#'(LAMBDA (x) (funcall f (funcall g x)) ))
; конструктор суперпозиции функций
(funcall (super #'CAR #'CDR) '(1 2 3))
; применение суперпозиции CAR и CDR
Двойное применение функции можно определить независимо или через суперпозицию —
W f = ((LAMBDA (x)(f (f x))) = S (f,f)
{ дважды применяется функция }
: (Number->Number) -> (Number->Number)
или более точно:
: (X->X) -> (X->X),
где X — произвольный
(DEFUN duble (f) #'(LAMBDA (x) (funcall f(funcall f x)) )) ; конструктор двойного применения функции (funcall (duble #'CAR) '(((1) 2) 3)) ;= (1) (defun duble (f) (funcall #'super f f)) ; двойное применение функции через суперпозицию (funcall (duble #'CAR) '(((A B) B) C)) ; = (A B)
Можно ввести обозначения:
Atom — атомы, Number — число, List (X) — NIL или списки из элементов типа X, Bool — NIL или T, Some — любой объект, (X . Y) – консолидация X и Y, Y != X – элементы типа Y кроме элементов типа X.
Соответственно пишутся
cons : (X List (X)) -> List (X)
car : List (X) -> X
cdr : List (X) -> List (X)
eq : (Atom Atom) -> Bool
atom : Some -> Bool
: (Atom -> T) | (List (X) -> NIL)
null : Some -> Bool
: (NIL -> T) | (Some != NIL -> NIL)
(List(X)\=NIL -> NIL)
Таким же образом можно специфицировать и
EVAL [e, al]:(Some List( (Atom . Some ) )) -> Some
| |
| List( (Atom . Some) )
Some{ могут попасть и неправильные выражения }
APPLY [fn, (a1 a2 …), al] : (List( Some ) -> Some
| | | List( Some )
| | | List((Atom . Some) )
| | | ) -> Some
| | |
| | | List((Atom . Some))
| List(Some)
(List(Some) -> Some
Отображающий функционал также может характеризоваться
map [x, f]
:( List(X) (X -> Y) ) -> List(Y)
(DEFUN map (x f)
(COND (x (CONS (funcall f (CAR x))
(map (CDR x) f )))))
(map '((1) (2) (3)) #'CAR ) ;= (1 2 3)
Можно специфицировать функцию, непосредственно преобразующую свой
mapf [f]
: List(X -> Y) -> ( List(X) -> List(Y))
(DEFUN mapf (f) #'(LAMBDA (x)
(COND (x (CONS (funcall f (CAR x))
(funcall (mapf f ) (CDR x)) ))) ))
(funcall (mapf #'CAR ) ;=(1 2 3)
Аргумент может быть списком функций, результаты которых следует собрать в общий список.
manyfun [lf] : List(X->Y) -> (X -> List(Y))
| | |_____список результатов функций
| |
| |_____тип аргумента отдельной функции
|
|____________________список функций
(DEFUN manyfun (lf) #'(LAMBDA (x)
(COND (lf (CONS (funcall (CAR lf) x)
(funcall (manyfun (CDR lf)) x) ))) ))
(funcall (manyfun '(CAR CDR length))
'(1 f (2 T)(3 D e)) ) ;= (1 (f (2 T)(3 D e)) 4)
Таким образом можно как бы "просачивать" определения функций над простыми данными, распределять их по структурам данных и тем самым распространять простые функции на сложные данные подобно матричной арифметике. Похожие построения предлагаются Бэкусом в его программной статье о функциональном стиле программирования и в языке
Существует ряд языков функционального программирования, требующих или допускающих спецификацию объектов, что, кроме дисциплины программирования, дает средства для корректной работы с пакетами, сопряжения с модулями на других языках, оптимизирующих
Результативность
В качестве примера такого языка рассмотрен
<а-гр> ::= А | А <а-гр>
<в-гр> ::= В | В <в-гр>
<слог> ::= <а-гр> <в-гр>
| <в-гр> <а-гр>
| <в-гр> <а-гр> <в-гр>
В этой А " и " В " — is-, выделяющий списки, представляющие правильно построенные слоги в соответствии с приведенными правилами.
Пусть тексты этого языка представляются списками из однобуквенных атомов A и B. Допустим, имеются предикаты is-A и is-B, выделяющие одноэлементные списки (A) и (B), соответственно.
(DEFUN is-a (x)(COND ((EQ(CAR x) 'a)
(null (CDR x))) ))
; распознаватель A
(DEFUN is-b (x)(COND ((EQ(CAR x) 'b)
(null (CDR x))) ))
; распознаватель B
Типовые List (X) -> Bool. Таким же должен быть и is-. При ее построении будет применена вспомогательная функция более высокого порядка is-alt, которая из произвольных предикатов конструирует новый предикат, перебирающий варианты правил и выдающий , если ни одно из них не подходит. Функция is-alt может быть определена следующим образом:
(DEFUN is-alt (p q)
; конструктор распознавателя альтернатив
#'(LAMBDA (x)
(COND ((funcall p x )T)
((funcall q x) T)
(T NIL))))
Ее типовый
(List(X)->Bool List(X))->Bool ) )-> List(X))->Bool
Можно использовать эквивалент:
(DEFUN is-alt (p q)
#'(LAMBDA (x)
(if (funcall p x) T (funcall q x))
)
Предикат both, работающий как логическая связка "и", можно реализовать как обычную функцию с типовым (Bool Bool) -> Bool.
(DEFUN both (x y) (COND ( x y)(T NIL)) ) ; проверка одновременности условий
Еще одна вспомогательная функция высокого порядка is- из произвольных предикатов конструирует новый предикат, выясняющий, не выделяют ли исходные предикаты смежные звенья цепочки. Типовый is-alt, т.к. их результаты используются при разборе и анализе текста в одинаковых позициях.
(DEFUN is-chain (p q) #'(LAMBDA (x )
; конструктор распознавателя цепочек
(COND ((null x) (both (funcall p x)
(funcall q NIL)) )
; пустая цепочка
((both (funcall p x) (funcall q NIL)) T)
; префикс без суффикса
((both (funcall p NIL) (funcall q x)) T)
; суффикс без префикса
((both (funcall p (CONS (CAR x)NIL))
(funcall q (CDR x)) ) T)
; допустимое разбиение
(T(funcall (is-chain (LAMBDA(y)(funcall p(CONS(CAR x)y)))
q )
( CDR x) ))
; сдвиг границы разбиения вправо
)))
Из данного is-a можно бы и без is-a-gr, распознающий группу из любого числа символов A:
(defun is-a-gr (x ) (if x ; распознаватель цепочек из A (cond ((eq (car x) 'a) (is-a-tl (cdr x)) ) ; <а-гр> ::= А | А <а-гр> (t nil) ) Nil)) (defun is-a-tl (x)(cond ((null x)T)((eq (car x)'A)(is-a-tl (cdr x )) )))) ; хвост цепочки из A
Но использование конструкторов is-alt и is-, показанное на примере is-b-gr, позволяет построить определение,
(DEFUN is-b-gr (x ) (funcall (is-alt #'is-b is-chain #'is-b #'is-b-gr)) x )) ; распознаватель цепочек из B ; <в-гр> ::= В | В <в-гр>
Теперь опробованные приемы конструирования is-, активно опираясь на чисто внешнее,
(DEFUN is-syllable (x )
; распознаватель слога
(funcall (is-alt (is-chain #'is-b-gr #'is-a-gr)
; слог вида BA
(is-alt (is-chain #'is-a-gr #'is-b-gr)
; слог вида AB
(is-chain #'is-b-gr (is-chain #'is-a-gr #'is-b-gr))
; слог вида BAB
) ) x ))
(is-syllable '(a b))
(is-syllable '(b a))
(is-syllable '(b a b ))
(is-syllable '(b b b b a a b b ))
Сопоставляя правила и полученное определение
| Грамматика | |
|---|---|
<слог>::= |
( |
<в-гр> <а-гр> |
(is-alt (is- |
<а-гр> <в-гр> |
(is-alt (is- |
<в-гр>
<а-гр> <в-гр>
|
(is-chain #'is-b-gr
(is-chain #'is-a-gr #'is-b-gr))
|
) ) x )) |
Конечно, построенное выше определение не отличается эффективностью.
Пусть
( (Тексты (Имя Вариант ...)...)
; первое имя — обозначение системы текстов
; за ним следуют варианты поименованных текстов
(Вариант Элемент ...)
; Вариант представляет собой
; последовательность Элементов
(Элемент Имя Лексема (Варианты))
; Элемент — это или Имя, или Лексема,
; или Варианты в скобках
)
Для
( (пример (ма ((ш н)
(ш а))
( ш н ) )
(н ина)
)
Построение , ass-all, swin, gram,
(DEFUN unic (vac) (remove-duplicates (mapcar 'CAR vac) ))
;; список уникальных начал
(DEFUN ass-all (Key Vac)
;; список всех вариантов продолжения
;; что может идти за ключом
(COND
((Null Vac) NIL)
((EQ (caar Vac) Key) (CONS (cdar Vac)
(ass-all Key (CDR Vac)) ))
(T (ass-all Key (CDR Vac)) )
) )
(DEFUN swin (key varl) (COND
;; очередной шаг свертки или снять скобки при
;; отсутствии вариантов
((null (CDR varl))(CONS key (CAR varl)))
(T (list key (gram varl)) )
))
(DEFUN gram (ltext)
;; левая свертка, если нашлись общие начала
( (LAMBDA (lt) (COND
((EQ (length lt)(length ltext)) ltext)
(T (mapcar
#'(LAMBDA (k) (swin k (ass-all k ltext )
))
lt )
) ) ) (unic ltext)
) )
(DEFUN bnf (main ltext binds) (CONS (CONS main
(gram ltext)) binds))
names, words, , d-, d-names, h-all, all-t, pred, sb-nm, , level1, lang
Функции names, words и задают алфавит и разбивают его на терминальные и
(DEFUN names (vac) (mapcar 'CAR vac))
;; определяемые символы
(DEFUN words (vac) (COND
;; используемые символы
((null vac) NIL)
((ATOM vac) (CONS vac NIL ))
(T (union (words (CAR vac))
(words (CDR vac)))) ))
(DEFUN lexs (vac) (set-difference (words vac)
(names vac)))
;; неопределяемые лексемы
Функции d- и d-names формируют нечто вроде встроенной базы данных, хранящей определения символов для удобства дальнейшей работы.
(DEFUN d-lex ( llex)
;; самоопределение терминалов
(mapcar #'(LAMBDA (x) (set x x) ) llex) )
(DEFUN d-names ( llex)
;; определение нетерминалов
(mapcar #'(LAMBDA (x) (set (CAR x )(CDR x )) )
llex) )
Функции h-all, all-t и pred раскрывают слияния общих фрагментов
(DEFUN h-all (h lt)
;; подстановка голов
(mapcar #'(LAMBDA (a)
(COND
((ATOM h) (CONS h a))
(T (append h a)) )
) lt) )
(DEFUN all-t (lt tl)
;; подстановка хвостов
(mapcar #'(LAMBDA (d)
(COND
((ATOM d) (CONS d tl))
(T(append d tl))
) ) lt) )
(DEFUN pred (bnf tl)
;; присоединение предшественников
(level1 (mapcar #'(LAMBDA (z) (chain z tl )) bnf)
))
Функции sb-nm, и LeveL1 строят развернутые, линейные тексты из частей, выполняя подстановку определений, сборку и выравнивание.
(DEFUN sb-nm (elm tl)
;; подстановка определений имен
(COND
((ATOM (EVAL elm)) (h-all (EVAL elm) tl))
(T (chain (EVAL elm) tl))
) )
(DEFUN chain (chl tl)
;; сборка цепочек
(COND
((null chl) tl)
((ATOM chl) (sb-nm chl tl))
((ATOM (CAR chl))
(sb-nm (CAR chl) (chain (CDR chl) tl) ))
(T (pred (all-t (CAR chl) (CDR chl)) tl)) ))
(DEFUN level1 (ll)
;; выравниваие
(COND
((null ll)NIL)
(T (append (CAR ll) (level1 (CDR ll)) )) ))
На основе приведенных вспомогательных функций общая схема lang:
(DEFUN lang ( frm ) ;; вывод заданной системы текстов (d-lex (lexs frm)) (d-names frm) (pred (EVAL (caar frm)) '(()) ) )
Вот и тесты к этой задаче, предложенные И.Н. Скопиным, справедливо предположившим, что для решения задач
(lang (print (bnf 'vars
'((m a s h a)(m a s h i n a)(s h i n a))
'((n (i n a))) )))
(lang '((vars (m a ((s h a)(s h n))) (s h n) )
(n (i n a)) ) )
Цель
Идентификатор ::= БУКВА
| Идентификатор БУКВА
| Идентификатор ЦИФРА
Удобное для эффективного
Идентификатор ::= БУКВА | БУКВА КонецИд
КонецИд ::= БУКВА КонецИд
| ЦИФРА КонецИд
| ПУСТО
(рис 13.1) Этот пример показывает, что удобные для анализа формулы приведены к виду, когда каждую альтернативу можно выбрать по одному текущему символу. Система CLOS поддерживает ООП с выделением методов для одноэлементных классов, распознаваемых простым сравнением. Тем самым обеспечено удобное построение программ над структурами, подобными
Например, определение:
<а-гр> ::= А | А <а-гр>
<в-гр> ::= В | В <в-гр>
<слог> ::= <а-гр> <в-гр>
| <в-гр> <а-гр>
| <в-гр> <а-гр> <в-гр>
можно привести к виду, не требующему возвратов при анализе:
<а-гр> ::= А <а-кон>
<а-кон> ::= <пусто> | A <а-кон>
<в-гр> ::= B <в-кон>
<в-кон> ::= <пусто> | B <в-кон>
<слог> ::= A <а-кон> B <в-кон>
|B <в-кон> A <а-кон> <в-кон>
Если программирование сводит алгоритм решения задачи к программе из определенной последовательности шагов, то конструирование строит программу решения задачи из решений типовых вспомогательных задач. Для задачи реализации языка программирования ключевой (но не единственной) типовой задачей является определение реализуемого языка. Ее решение открывает возможности автоматизированного конструирования анализаторов и компиляторов. Автоматизацию конструирования системы программирования обеспечивают методы
Все это хорошо изученные задачи, имеющие надежные решения, знания которых достаточно для создания своих языков программирования и проведения экспериментов с программами на своих языках. Существует ряд программных инструментов, поддерживающих автоматизацию процесса создания и реализации языков программирования и более общих информационных систем обработки формализованной информации, например YACC,
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.