Языки логического программирования

Язык РЕФАЛ: сложные конструкции Рефала-2

Показывать лекцию целиком

Спецификации переменных

В том случае, когда нужно ограничить множество значений, которое может принимать переменная (левой части рефал-предложения), в описание переменной вводится спецификация, которая должна находиться между типом переменной и индексом без пробелов. Спецификация может быть определена непосредственно в круглых скобках либо именем спецификатора (для предопределенных имен спецификаторов ). Например, переменная S('+-')z может принимать значения только знаков '+' или '-'. При этом цепочка символов '+-' определяется как спецификатор переменной Sz. В правой части рефал-предложения спецификация не пишется. Между скобками спецификации и спецификатором может быть любое количество пробелов.

Каждый спецификатор в общем случае представляет собой описание некоторого множества термов (допустимые значения переменной). Это описание строится из некоторого набора элементарных множеств, обозначения которых мы будем называть элементами. В качестве элементов могут быть использованы любые символы, а также следующие конечные множества:

  • S - множество всех символов;
  • B - множество структурных термов;
  • W - множество всех термов;
  • F - множество символов-меток;
  • N - множество символов-чисел;
  • R - множество символов-ссылок;
  • 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,

    где $$P_{i} (i\in \overline {0,n}),\setminus Q_{i} (i\in \overline {1,n})$$ - произвольные цепочки элементов спецификатора (возможно, пустые). Если P0 - пустая цепочка, то считается P0=W (множеству всех термов). Наличие цепочки элементов спецификатора в круглых скобках означает, что элементы множества этой цепочки удаляются, а цепочка без круглых скобок ведет к добавлению в суммарное множество элементов множества этой цепочки. Поэтому множество спецификатора рассматривается как множество:

    $$(\dots ((P_{0} \setminus Q_{n}) \cup P_{n}) \setminus \dots Q_{1}) \cup P_{1}$$.

    Так, например, переменная 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

    Структура рефал-программы и ее модулей

    Рефал-программа состоит из одного или нескольких модулей - частей программы, которые компилируются отдельно. Каждый модуль программы представляет собой последовательную запись директив программы и комментариев. Каждый комментарий записывается в отдельной строке и начинается с литеры "*". Перед этим символом могут стоять пробелы в любом количестве, а после - любой текст, который игнорируется при выполнении программы.

    Каждая директива находится в отдельной строке и имеет следующий вид:

    [<идентификатор>] [<ключевое слово>] [<информация>]

    Присутствие всех трех частей директивы необязательно. Между отдельными частями директивы должен быть хотя бы 1 пробел, но если идентификатор директивы отсутствует, то строка директивы начинается с пробела. Так, директива описания функции содержит только ее идентификатор и, возможно, информацию в виде рефал-предложения. Директива рефал-предложени я содержит только информацию. Директива спецификатора имеет идентификатор спецификатора, ключевое слово S и в качестве информации директивы сам спецификатор. Если все 3 компоненты директивы отсутствуют, то это пустая директива, которая используется для улучшения общего вида программы.

    Ключевые слова директив приведены в табл. 3.1.

    Ключевое словоДиректива Примечание
    START Начало модуля(программы) имя директивы модуля (программы)
    END Конец модуля (программы) без имени
    ENTRY Объявление входов модуля функции модуля, используемые в других модулях
    EXTRN Объявление внешних функций функции других модулей, используемые в данном
    R Рефал-предложение отождествление справа
    L Рефал-предложение отождествление слева (по умолчанию отсутствует)
    S Объявление имени спецификатора

    Необязательное имя модуля (программы) дается директивой START, а конец модуля (программы) отмечается директивой END без имени (директива начинается с пробела).

    Имена всех функций модуля, которые могут быть использованы в других программах и модулях, должны быть объявлены входами директивой ENTER (без имени). Имена функций других модулей, используемых в программе, должны быть объявлены внешними директивой EXTRN. Благодаря директиве EXTRN программа связывается с внешним миром, так как функции ввода исходных данных и вывода результатов описываются на других языкахТакие первичные функции мы опишем в следующем разделе. (ассемблер, С). Модуль может не содержать директивы 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.      
           END

    Здесь функция модуля M1 с внутренним именем COMMUN имеет вызов в модуле M2 с внутренним именем "общение".

    Каждое имя, которое употребляется внутри модуля, должно быть описано либо как имя внутренней функции или спецификатора, либо как имя внешней функции или спецификатора в директиве EXTRN.

    Упражнения

  • Разработайте рефал-функцию, которая отделяет от выражения самый большой идентификатор справа и заключает его в структурные скобки.
  • Разработайте спецификатор, который ограничивает множество символов цифрами (кроме 0) и символами-числами.
  • Разработайте спецификатор, который ограничивает множество термов любыми термами кроме составных символов.
  • Разработайте рефал-функцию, которая реверсирует последовательность структурных и функциональных термов.
  • Разработайте двухмодульную программу, один из модулей которой содержит описание функций выделения в стуктурные скобки самого левого идентификатора, переменной, самого левого числа и самой левого символа арифметической операции, а другой модуль производит лексический анализ выражения, определенного аргументом у функции лексического анализа, функция которого описана с помощью функций первого модуля.
  • Вернуться к учебному плану