Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Языки логического программирования. Учебное пособие
.pdf
Язык РЕФАЛ: сложные конструкции Рефала-2
Спецификации переменных: синтаксис спецификации; спецификатор и
его элементы; элементы-множества спецификатора; общий вид
спецификатора; определение имени спецификатора и его
использование. Структора рефал-программы и ее модулей: директива
программы и ее части; директива комментария; ключевые слова
директив; модульность и объявление входов и внешних имен; пример
двухмодульной программы.
Спецификации переменных
В том случае, когда нужно ограничить множество значений, которое
может принимать переменная (левой части рефал-предложения), в
описание переменной вводится спецификация, которая должна
находиться между типом переменной и индексом без пробелов.
Спецификация может быть определена непосредственно в круглых
скобках либо именем спецификатора (для предопределенных имен
спецификаторов ). Например, переменная S('+-')z может
принимать значения только знаков '+' или '-'. При этом цепочка
символов '+-' определяется как спецификатор переменной Sz. В
правой части рефал-предложения спецификация не пишется. Между
скобками спецификации и спецификатором может быть любое
количество пробелов.
Каждый спецификатор в общем случае представляет собой описание
некоторого множества термов (допустимые значения переменной). Это
описание строится из некоторого набора элементарных множеств,
обозначения которых мы будем называть элементами. В качестве
элементов могут быть использованы любые символы, а также
следующие конечные множества:
S - множество всех символов;
B - множество структурных термов;
W - множество всех термов;
F - множество символов-меток;
N - множество символов-чисел;
R - множество символов-ссылок;
Языки логического программированияВ.С. Рублев
21

O - множество символов-литер (знаков символов);
L - множество прописных букв (латинских и русских);
D - множество десятичных цифр.
В простом случае используется , которая представляет собой
объединение множеств элементов будем называть набор опций,
описывающих необязательные возможности.. Например, функция
Ident проверяет, является ли выражение аргумента идентификатором
(последовательностью больших букв и цифр, начинающейся с буквы), и
возвращает символ 'T' при положительном ответе, а символ 'F' при
отрицательном ответе.
Ident S(L)1 E(LD)2 = 'T'
Ex = 'F'
Функция Ident при интерпретации первого рефал-предложения
проверяет, является ли первый символ выражения аргумента буквой
(для этого первый выделяемый символ S1 имеет спецификацию L) и
являются ли все последующие символы, если они есть (переменная
типа E может интерпретировать пустое значение), буквами или
цифрами. Если это так, то возвращается символ 'T'. А если это не так, то
второе рефал-предложение (всегда выполнимое) возвратит символ 'F',
что и требовалось.
В общем случае спецификатор имеет вид:
P1(Q1)... Pn(Qn)P0,
где - произвольные цепочки элементов
спецификатора (возможно, пустые). Если P0 - пустая цепочка, то
считается P0=W (множеству всех термов). Наличие цепочки элементов
спецификатора в круглых скобках означает, что элементы множества
этой цепочки удаляются, а цепочка без круглых скобок ведет к
добавлению в суммарное множество элементов множества этой
цепочки. Поэтому множество спецификатора рассматривается как
множество:
.
Языки логического программированияВ.С. Рублев
22

Так, например, переменная W(('ABC'))1 может принимать значения
любых термов, кроме символов литер 'A', 'B', 'C', а переменная
S(('A')L('0')D)2 может принимать значения любых символов,
кроме буквы 'A' и цифры '0'.
Для спецификатора можно задать имя с тем, чтобы употреблять это имя
вместо выражения спецификатора. Это делается описанием имени
спецификатора:
<имя спецификатора> S <спецификатор>
Пусть, например, вводятся имена спецификаторов для операций типа
сложения и для операций типа умножения:
ADDOP S '+-'
MULTOP S '*/'
Теперь имена спецификаторов, ограниченные с обеих сторон
символами двоеточие ":", можно употреблять в спецификациях.
Например, переменная S:ADDOP:1 может принимать значения только
символов операций типа сложения, а переменная
S((:ADDOP::MULTOP:)S)2 может принимать значения всех
символов, кроме символов арифметических операций.
Рассмотрим еще 1 пример: функция Separate отделяет от выражения
аргумента самый большой идентификатор слева и заключает его в
структурные скобки, оставляя неизменным оставшуюся часть
выражения. Если же такого идентификатора нет, то функция помечает
выражение символом '*'. Решение, основанное на функции Ident не
годится, так как нужно знать, где заканчивается идентификатор. Однако
если использовать отождествление справа налево, то мы получаем
следующее простое решение.
Separate R S(L)1 E(LD)2 Ex = (S1 E2) Ex
Ex = '*' Ex
Структура рефал-программы и ее модулей
Рефал-программа состоит из одного или нескольких модулей - частей
Языки логического программированияВ.С. Рублев
23

программы, которые компилируются отдельно. Каждый модуль
программы представляет собой последовательную запись директив
программы и комментариев. Каждый комментарий записывается в
отдельной строке и начинается с литеры "*". Перед этим символом
могут стоять пробелы в любом количестве, а после - любой текст,
который игнорируется при выполнении программы.
Каждая директива находится в отдельной строке и имеет следующий
вид:
[<идентификатор>] [<ключевое слово>] [<информация>]
Присутствие всех трех частей директивы необязательно. Между
отдельными частями директивы должен быть хотя бы 1 пробел, но если
идентификатор директивы отсутствует, то строка директивы начинается
с пробела. Так, директива описания функции содержит только ее
идентификатор и, возможно, информацию в виде рефал-предложения.
Директива рефал-предложени я содержит только информацию.
Директива спецификатора имеет идентификатор спецификатора,
ключевое слово S и в качестве информации директивы сам
спецификатор. Если все 3 компоненты директивы отсутствуют, то это
пустая директива, которая используется для улучшения общего вида
программы.
Ключевые слова директив приведены в табл. 3.1.
Таблица 3.1.
Ключевое
слово
Директива Примечание
START
Начало
модуля(программы)
имя директивы модуля
(программы)
END
Конец модуля
(программы)
без имени
ENTRY
Объявление входов
модуля
функции модуля, используемые в
других модулях
EXTRN
Объявление внешних
функций
функции других модулей,
используемые в данном
R Рефал-предложение отождествление справа
Языки логического программированияВ.С. Рублев
24

L Рефал-предложение
отождествление слева (по
умолчанию отсутствует)
S
Объявление имени
спецификатора
Необязательное имя модуля (программы) дается директивой START, а
конец модуля (программы) отмечается директивой END без имени
(директива начинается с пробела).
Имена всех функций модуля, которые могут быть использованы в других
программах и модулях, должны быть объявлены входами директивой
ENTER (без имени). Имена функций других модулей, используемых в
программе, должны быть объявлены внешними директивой EXTRN.
Благодаря директиве EXTRN программа связывается с внешним миром,
так как функции ввода исходных данных и вывода результатов
описываются на других языках1) (ассемблер, С). Модуль может не
содержать директивы EXTRN, если он предназначен для использования
в других модулях и программах (в этом случае директива ENTRY должна
быть обязательно). Имена входов и внешних функций даются их
идентификаторами. Но если в одном модуле используется
идентификатор внешней функции, отличный от ее описания в другом
модуле, то в скобках дается имя этой внешней функции в модуле ее
описания.
Смысл директивы SWAP мы дадим при описании специальных видов
памяти, с которой может работать программа.
Приведем пример двухмодульной программы.
M1 START
ENTRY COMMUN
EXTRN DREAM
COMMUN E1 '+' E2 = k/DREAM/ E1. k/DREAM/ E2.
END
M2 START
ENTRY DREAM
EXTRN общение(COMMUN)
DREAM Sx E1 = Sx k/общение/ E1.
Языки логического программированияВ.С. Рублев
25

END
Здесь функция модуля M1 с внутренним именем COMMUN имеет вызов в
модуле M2 с внутренним именем "общение".
Каждое имя, которое употребляется внутри модуля, должно быть
описано либо как имя внутренней функции или спецификатора, либо
как имя внешней функции или спецификатора в директиве EXTRN.
Упражнения
1. Разработайте рефал-функцию, которая отделяет от выражения
самый большой идентификатор справа и заключает его в
структурные скобки.
2. Разработайте спецификатор, который ограничивает множество
символов цифрами (кроме 0) и символами-числами.
3. Разработайте спецификатор, который ограничивает множество
термов любыми термами кроме составных символов.
4. Разработайте рефал-функцию, которая реверсирует
последовательность структурных и функциональных термов.
5. Разработайте двухмодульную программу, один из модулей которой
содержит описание функций выделения в стуктурные скобки
самого левого идентификатора, переменной, самого левого числа
и самой левого символа арифметической операции, а другой
модуль производит лексический анализ выражения,
определенного аргументом у функции лексического анализа,
функция которого описана с помощью функций первого модуля.
1)
Такие первичные функции мы опишем в следующем разделе.
Языки логического программированияВ.С. Рублев
26

Язык РЕФАЛ: первичные функции и примеры
составления программ
Первичные функции Рефала-2: функции ввода/вывода; арифметические
функции; функции лексического анализа; функции для работы с
символами-метками. Синтаксический анализатор для языка
арифметических выражений: описание синтаксиса языка формами
Бэкуса-Наура; программа анализатора и ее близость к языку БНФ.
Программа суммирования последовательности чисел и ее особенности.
Первичные функции
Во многих случаях возникает необходимость в функциях, которые не
могут быть описаны средствами Рефала. К ним прежде всего относятся
функции операций ввода/вывода, осуществляющие связь со внешним
миром. Помимо этого, такими функциями являются ряд функций
арифметических и логических операций, а также функции работы с
особыми видами памяти Рефала. Эти функции пишутся обычно на
других языках и называются первичными. С точки зрения работы
Рефал-машины исполнение вызова первичной функции осуществляется
за 1 шаг ее работы.
Функции ввода/вывода
Функции ввода/вывода предназначены для организации диалогового
взаимодействия между пользователем и программой. Для ввода строки
с клавиатуры используется функция card. Для вывода информации на
экран используются операции print, prout, которые различаются
возвращаемым значением и способом представления информации на
экране. Ввод/вывод может быть переназначен в произвольный файл
стандартным образом.
Функция card осуществляется вызовом
k/card/ .
и дает возможность читать строку символов из входного потока. После
вызова функции программа переходит в состояние ожидания ввода
Языки логического программированияВ.С. Рублев
27

строки. По окончании ввода строки следует нажать клавишу "Enter".
Возвращаемым значением является введенная строка.
Функция print осуществляется вызовом
k/print/ <E>.
где E - произвольное рефал-выражение (возможно, и пустое), и
выводит c новой строки это выражение. При пустом выражении
пропускается 1 печатная строка. При непустом выражении символылитеры выводятся в виде соответствующих литер, структурные скобки
выводятся как круглые скобки, а составные символы выводятся с
ограничителями ' вместо "/". Возвращаемым значением является
выводимое выражение.
Например, функция
k/print/ 'функция'(/f1/).
возвратит выражение
'функция'(/f1/).
При этом на устройство вывода будет выдана строка
'функция'('f1') ,
Функция prout осуществляется вызовом
k/prout/ <E>.
где E - произвольное рефал-выражение (возможно, и пустое), и
выводит c новой строки это выражение. Отличием от функции print
является то, что всегда возвращается пустое выражение.
Арифметические функции
Функции работают только с целыми числами, каковыми являются в
представлении Рефала - символы-числа с возможно предшествующим
знаком минус '-'. Например, '-'/7/, /0/, /2007/. Нуль
Языки логического программированияВ.С. Рублев
28

представляется либо нулевым символом-числом, либо пустым
выражением.
Все арифметические функции допускают использование пустого
выражения в качестве аргумента и воспринимают его как нуль.
К арифметическим функциям относятся:
add - сложение;
mul - умножение;
sub - вычитание;
dr - деление нацело с остатком;
div - деление нацело;
p1 - инкремент (увеличение на 1);
m1 - декремент (уменьшение на 1).
Для преобразования целых чисел в символьный вид и обратно
используются функции symb и numb.
Функции add, mul, sub осуществляются вызовом
k/op/ (<N1>) <N2>. ,
где op - одна из операций add, mul, sub, а N1 и N2 - макроцифры.
Этот вызов возвращает макроцифру (для положительного результата
знак '+' не ставится) суммы, произведения или разности N1-N2 в
зависимости от операции. Например, следующие вызовы функции
приведут к таким результатам:
k/add/ ('-'/5/) /3/. -> '-'/2/
k/add/ () /2/. -> /2/
k/mul/ ('-'/5/) /3/. -> '-'/15/
k/mul/ (/2/). -> /0/
k/sub/ ('-'/5/) /3/. -> /8/
k/sub/ () /2/. -> '-'/2/
Функция dr осуществляется вызовом
k/dr/ (<N1>) <N2>. ,
Языки логического программированияВ.С. Рублев
29

где N1 - делимое, а N2 - делитель. Она возвращает выражение
<Q> (<R>) ,
где Q - частное, а R - остаток. Попытка делить на 0 приводит к
аварийному завершению. Знаки частного и остатка определяются
следующим образом: сначала производится деление нацело без учета
знаков делимого и делителя, а затем частному и остатку приписываются
знаки так, чтобы выполнялось соотношение:
N1 = Q*N2 + R
т. е. остаток (не равный нулю) всегда имеет знак делимого, а знак
частного определяется знаками делимого и делителя (при одинаковых
положителен, при разных отрицателен). Например, следующие вызовы
функции приведут к таким результатам:
k/dr/ (/5/) /3/. -> /1/ (/2/)
k/dr/ (/5/) '–'/3/. -> '–'/1/ (/2/)
k/dr/ ('–'/5/) /3/. -> '–'/1/ '–'(/2/)
k/dr/ ('–'/5/) '–'/3/. -> /1/ '–'(/2/)
Функция div в отличие от функции dr возвращает только частное. В
остальном же подобна ей. Например, следующие вызовы функции
приведут к таким результатам:
k/div/ (/5/) /3/. -> /1/
k/div/ (/5/) '–'/3/. -> '–'/1/
k/div/ ('–'/5/) /3/. -> '–'/1/
k/div/ ('–'/5/) '–'/3/. -> /1/
Функции p1, m1 имеют 1 аргумент и возвращают соответственно
макроцифру, увеличенную на 1 или уменьшенную на 1. Например,
следующие вызовы приведут к таким результатам:
k/p1/ '–'/2007/. -> '–' /2006/
k/p1/. -> /1/
k/m1/ /2007/. -> /2006/
k/m1/. -> '–'/1/
Языки логического программированияВ.С. Рублев
30
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
