                                 ВВЕДЕНИЕ

     Интегральная микроэлектроника сделала компьютеры реальным  и  исключи-
тельно эффективным средством научно-технической революции.  Компьютеризация
стала экономически целесообразной и открывает небывалые возможности  совер-
шенствования производства, научных исследований, систем управления,  обслу-
живания и других сфер народного хозяйства.  Наибольшей  трудностью  в  деле
практического освоения этих возможностей, наряду с  разработкой  адекватных
методов применения компьютеров в тех или иных  конкретных  целях,  является
создание необходимых прикладных  программ.  Эта  трудность  обусловлена  не
только нехваткой программистов и все еще крайне низкой  продуктивностью  их
труда, но в большей степени тем, что для создания  надежных  и  эффективных
прикладных программ требуется основательное знание специфики  каждого  кон-
кретного применения, и следовательно создавать их должны не просто програм-
мисты, а компетентные в соответствующих областях люди. И надо иметь в виду,
что разработчику программ, о которых  идет  речь,  совершенно  недостаточно
"компьютерной грамотности" в смысле знакомства с Бейсиком  или  Паскалем  -
как правило, он должен программировать на языке ассемблера.
     Из сказанного следует, что освоение в народном хозяйстве богатых  воз-
можностей компьютерной техники можно существенно ускорить созданием широко-
доступной системы программирования. Такая система должна удовлетворять сле-
дующим требованиям:
     - нетрудность освоения и использования непрофессиональными программис-
       тами;
     - универсальность языка, такая же, как у языка ассемблера;
     - трудоемкость программирования существенно меньше, чем в ассемблерных
       системах;
     - надежность программ, обеспечиваемая практически осуществимой провер-
       кой их корректности;
     - удобообслуживаемость, то есть понятность, модифицируемость и самодо-
       кументируемость программ;
     - развиваемость и адаптивность к применениям языка и возможностей сис-
       темы;
     - мобильность (переносимость) системы вместе с созданными в ней  прог-
       раммами в отношении компьютеров разной архотектуры;
     - удовлетворительная машинная эффективность (компактность и быстродей-
       ствие) как самой системы, так и создаваемых в ней программ.
     Всем этим требованиям в  значительной  мере  удовлетворяет  Диалоговая
система структурированного программирования ДССП, созданная проблемной  ла-
бораторией электронных вычислительных  машин  Московского  государственного
университета им. М.В.Ломоносова (ПНИЛ ЭВМ МГУ).
     Первая версия ДССП была разработана и реализована на машинах "Электро-
ника НЦ-03Д", "Электроника НЦ-04Т" в 1980-1982 гг. [ ].  Вторая,  пересмот-
ренная с учетом применения первой версия, называемая  ДССП-80,  реализована
на машинах "Электроника 60", "Электроника НЦ-80-20", ДВК-2 в 1983-1985  гг.
[ ]. В настоящее время эта версия системы адаптирована на ряде  других  ма-
шин, обладающих архитектурой PDP-11 (СМ-3, СМ-4, СМ-1300, БК-0010, ДВК-3) и
перенесена на машины, построенные на базе микропроцессоров К580 и Z80  (РО-
БОТРОН А-5120, РОБОТРОН 1715, Ямаха).
     Последующие главы составляют описание ДССП.

                 1. Общая характеристика ДССП

     Диалоговая система структурированного программирования  ДССП  призвана
уменьшить трудоемкость, повысить надежность и  обеспечить  широкую  доступ-
ность программирования микрокомпьютеров  путем  систематического  внедрения
дисциплины структурированного программирования в сочетании с диалоговым ре-
жимом и нетрадиционной архитектурой системы, базирующейся на стеках, слова-
ре и процедурном коде. Основу ДССП составляет  эмулируемый  на  компьютерах
стековый процессор с тщательно  разработанными  средствами  конструирования
структурированных программ (ДССП-процессор).  Прототипом  этого  процессора
послужила созданная в ПНИЛ ЭВМ МГУ в  конце  60-х  годов  экспериментальная
цифровая машина "Сетунь 70" []. Диалоговое управление ДССП-процессором осу-
ществлено на внешнем (символьном) языке при помощи словаря и компилятора по
образцу системы FORTH [], но с возможностью компиляции процедур в  нисходя-
щей последовательности и удаления излишних словарных входов.

                    1.1. Базовый язык ДССП

     Базовый язык ДССП - Развиваемый Адаптивный Язык (РАЯ) является  языком
низкого уровня в том смысле, что в нем представлены объекты,  типичные  для
языка ассемблера (биты, байты, машинные слова и элементарные  операции  над
ними). От традиционного языка ассемблера РАЯ отличается постфиксным синтак-
сисом, строгой дисциплиной управления и наличием эффективных средств попол-
нения и развития языка. Таким образом, ДССП составляет альтернативу  ассем-
блерным системам программирования,  обладающую  рядом  важных  преимуществ:
легкость освоения, значительное повышение производительности труда програм-
миста и качества создаваемых программ, развиваемость, адаптивность, мобиль-
ность. Однако, надо иметь в виду, что преимущества эти получены за счет ко-
ренной перестройки архитектуры, метода программирования и даже самого строя
мышления программиста. ДССП не совместима с традиционными системами, и поэ-
тому  внедрение  ее  неизбежно  связано  с  болезненной  ломкой   традиций.
     Постфиксный  синтаксис  языка  РАЯ  обусловлен  стековой  организацией
ДССП-процессора. Процессор выполняет  операции  над  значениями  операндов,
предварительно помещенными (засланными) в стек или сформированными в  стеке
предшествующими операциями, поэтому в программе операции должны  находиться
после операндов. Например, вычисление выражения 3*x-7 программируется в ви-
де последовательности
     3  x  *  7 Выполняя эту программу, процессор засылает в стек встретив-
шиеся в ней данные и производит над стеком указанные операции. На языке РАЯ
описание этого процесса получается за счет введения  в  постфиксную  запись
программы комментариев, отражающих текущее состояние стека:
     []  3  x  [3,x]  *  [3*x]  7  [3*x,7]  -  [3*x-7]
     Существенно, что операции определены не над поименованными данными,  а
над содержимым (над элементами) стека. Например, операция вычитания означа-
ет: "Взять из стека вычитаемое, затем взять из стека уменьшаемое, произвес-
ти вычитание и разность заслать в стек". Операция обособлена от операндов и
работает как процедура, параметрами которой являются элементы  стека.  Под-
становка значений параметров осуществляется засылкой их в надлежащем поряд-
ке в стек.
     Пополнение и развитие языка РАЯ реализуется в значительной степени как
расширение набора используемых в нем операций путем  определения  процедур.
Так, рассмотренное только что вычисление выражения 3*x-7 можно  оформить  в
виде процедуры с именем, скажем, LF, которая по правилам языка РАЯ  опреде-
ляется в виде
     :  LF  [x]  3  *  7  -  [x*3-7]  ;
     Двоеточие означает "Определить процедуру". LF - имя определяемой  про-
цедуры, [x] - состояние затрагиваемой этой процедурой  части  стека.  Далее
следует тело процедуры и точка с  запятой,  означающая  конец  определения.
     В результате ввода и выполнения определения процедуры ее имя  оказыва-
ется занесенным в словарь и таким образом обретает статус операции, которую
ДССП-процессор умеет выполнять. Встретив это  имя  в  программе,  процессор
воспринимает его как предписание выполнить содержащуюся в определении  про-
цедуры последовательность операций. Теперь выражение 3*x-7 можно запрограм-
мировать в виде
     x  LF
     Вводимые посредством определений процедуры могут использоваться нарав-
не с базовыми операциями языка в определениях процедур. Например, процедура
**2 возведения числа в квадрат, определенная командой
     :  **2  [x]  C  [x,x]  *  [x**2]  ; где операция C (Copy)  засылает  в
стек копию верхнего элемента ("вершины") стека, в свою очередь  может  быть
употреблена в определении процедуры **4  возведения  числа  в  4-ю  степень
     :  **4  [x]  **2  **2  [x**4]  ;
     Процедура **2, входящая в тело процедуры **4, называется  вложенной  в
нее. Вложенность процедур имеет первостепенное значение  в  ДССП,  является
основным средством структурирования программ. Головная процедура, представ-
ляющая создаваемую процедуру в целом, определяется  при  помощи  небольшого
числа непосредственно вложенных в нее по возможности укрупненных  процедур,
каждая из которых затем определяется при помощи вложенных в нее менее круп-
ных процедур, которые разлагаются на еще более детальные и т.д. до  опреде-
лений, содержащих только непосредственно выполняемые процессором  операции.
     В результате такой декомпозиции, называемой также нисходящим  програм-
мированием, получается четко упорядоченная программа в форме  иерархии  ко-
ротких процедур, вполне посильных для понимания и  исчерпывающей  проверки.
Противоположностью нисходящему является восходящее программирование -  раз-
витие языка путем пополнения его операциями-процедурами все более  высокого
уровня.
     Команда в ДССП - это последовательность слов  вызывающая  определенное
действие процессора. В простейшем случае команда состоит из  одного  слова.
Так, имя процедуры (мнемокод операции) вызывает выполнение  этой  операции,
имя данного вызывает засылку в стек соответствующего значения. Примеры  од-
нословных команд: SORT, ABS, ВРАЩАТЬ, +, <, -357, PI, Z.
     В общем случае команда является  словосочетанием  (фразой),  поскольку
имя действия может требовать дополнения в виде одного или нескольких  слов.
Так, действие, обозначаемое мнемокодом RP - "Повторять", требует в качестве
дополнения имя процедуры (операции, данного).  Мнемокод  BR0  -  "Выполнить
первое, если изымаемое число равно нулю, иначе выполнить второе" -  требует
дополнения из двух имен, первого и второго. Мнемокод BR - "Выполнить по вы-
бору одно из перечисленных" - требует дополнения, содержащего  произвольное
количество пар слов и слово ELSE в  качестве  предпоследнего.  Примеры:  RP
STEP, BR0 PA PB, BR A1 PA A2 PB A3 PC ELSE PP.  Однословные  команды  можно
рассматривать как указания "Выполнить <имя процедуры>" и  "Заслать  в  стек
<имя данного>".
     Особым типом команд-словосочетаний,  не  используемых  в  определениях
процедур, являются сами определения, а также команды объявления  (описания)
данных.
     Имена данных описываются при помощи мнемокодов, определяющих структуру
объявляемого данного. Например:
     VAR  X    - "Создать переменную X",
 [5] VCTR ROW  - "Создать вектор ROW[0:5]",
     CNST BASE 2 8 10 16 ;  - "Создать вектор констант BASE[0:3] с перечис-
ленными значениями компонент",
     Понятия типа данных в базовом языке ДССП нет. В описании  определяется
только формат элементов данного: бит, байт, 16-битное слово, 32-битное сло-
во. Для указания формата команду-описатель дополняют спереди одним из слов:
BIT, BYTE, DBL. В случае, когда такого дополнения нет, по умолчанию  прини-
мается формат 16-битного слова. Так, приведенные только что описания  отно-
сятся к 16-битным словам. Вектор  BASE,  например,  с  компонентами-байтами
описывается в виде
     BYTE  CNST  BASE  2  8  10  16  ;
     Команды объявления данных и определения процедур могут быть  дополнены
спереди также некоторыми другими уточняющими словами, например: INT  "Опре-
деляемую процедуру предназначить для обработки прерывания", ::  "Определяе-
мое имя зафиксировать в словаре как неудаляемый словарный вход".
     Все объекты языка РАЯ представляют собой разделенные  пробелами  слова
из литер, в число которых входят латинские и русские, строчные и  заглавные
буквы, цифры, математические  и  другие  специальные  знаки  согласно  ГОСТ
13052-74. Цепочка пробелов равносильна одному пробелу. Кроме того, раздели-
телем слов является конец строки. ДССП-процессор  опознает  поступающие  на
его вход слова по первым семи литерам.
     Программа на языке РАЯ состоит из описаний данных и определений проце-
дур. Имена объявленных данных являются глобальными, то есть  доступными  на
протяжении всей программы. Все объявления данных рекомендуется размещать  в
начале  программы.  Определения  процедур  образуют  нисходящую   иерархию.

                  2. Описание операций и команд.

                 Операции, выполняемые над стеком.

      Стек  операндов  является  одним  из  главных  элементов  архитектуры
ДССП-процессора. Большинство команд процессора используют  стек,  потребляя
из него необходимые им операнды и засылая в него результаты.  Интерпретация
данных, находящихся в стеке, зависит от сути решаемой задачи, т. е.  в  ко-
нечном счете возложена на программиста. Вследствие того, что значение,  по-
павшее в стек, фактически теряет свое имя, по тексту программы трудно опре-
делить, к каким операндам применяется та или иная операция, каковы  ее  ре-
зультаты. Поэтому для явного указания операндов и  результатов  процедур  в
языке РАЯ используются комментарии. При этом не требуется (да и  не  всегда
возможно) описывать все содержимое стека. Комментировать же  верхнюю  часть
стека, затрагиваемую выполняемой над ним процедурой, совершенно необходимо,
так как без этого теряется наглядность программы, затрудняется ее проверка.
     Для достижения единообразия программ эти комментарии  нужно  писать  с
учетом нескольких простых правил. Как и всякий комментарий, описание содер-
жимого стека, заключается в квадратные скобки.  Это  описание  представляет
собой список операндов, находящихся в стеке, перечисленных  через  запятую.
Каждый элемент списка характеризует содержимое одной позиции стека.  Значе-
ния позиций стека перечисляются слева направо, начиная с элемента, лежащего
на наибольшей глубине, и кончая вершиной стека. В качестве описания отдель-
ного операнда может выступать число, имя, выражение или любая другая содер-
жательная запись, поясняющая смысл находящегося в  стеке  значения.  Иногда
для некоторой позиции стека можно указать несколько возможных  значений.  В
этом случае значения перечисляются через косую черту.
     Приведем пример комментария, отражающего  состояние  стека  операндов:
     [нач.адр.,N+1,1/0] Во время выполнения программы, в том месте где  на-
ходится данный комментарий, стек операндов должен  содержать  три  позиции,
причем в вершине может находится 1 или 0, в подвершине - числовое значение,
равное N+1, а в подподвершине - некоторое число, интерпретируемое  как  на-
чальный адрес.
     Для удобства указания требуемой позиции стека  мы  будем  использовать
понятие глубины залегания. Будем считать, что вершина стека лежит на глуби-
не 1, подвершина - на глубине 2 и т.д. В частности, значение,  обозначенное
в примере как "нач.адр" лежит на глубине 3.
     Изучение базового языка ДССП мы начнем с  команд  засылки  значений  в
стек. Простейшей (и наиболее часто используемой) командой этого типа  явля-
ется числовой литерал, т. е. явное задание константы, которую  надо  помес-
тить в стек. Пусть, например, мы хотим заслать в стек числа 28,  -5  и  11.
Для этого необходимо ввести с клавиатуры строку:     28  -5  11
и нажать клавишу "ВК" (возврат каретки).
     Процессор распознает введенные числа и поочереди зашлет их в стек, так
что в вершине окажется 11. _тобы убедиться в этом,  достаточно  распечатать
значение вершины стека на экране дисплея. Для этого служит команда  ДССП  с
именем . (точка). Набрав на клавиатуре литеру "точка" и нажав "ВК", получим
на экране ответ: 11, что соответствует последнему засланному в стек  значе-
нию. Повторное выполнение "точки" приводит к тому же результату -  эта  ко-
манда лишь визуализирует вершину, не изменяя состояния стека.
     Для того, чтобы выдать на экран все содержимое стека, в  ДССП  имеется
команда .. (две точки). Выполнив ее, получим на экране строку:
     [  28   -5   11]
     Как видно, форма распечатки соответствует принятым соглашениям о  ком-
ментировании состояния стека (за исключением того, что вместо  запятой  ис-
пользуется пробел). Команда .. не изменяет содержимого стека.
     Для представления одной позиции стека  в  памяти  машины  используется
16-битное слово (2 байта), числа представляются в дополнительном коде.  Со-
ответственно ДССП-процессор может правильно воспринять только целые  числа,
лежащие в диапазоне от -32768 до +32767. Если введенное число не представи-
мо 16-ю битами (с учетом знака), то происходит отбрасывание старших не уме-
щающихся битов. Например, выполнение строки:
     34567  .
Вызовет печать числа -30969, а не 34567, как хотелось бы.  Изменение  знака
числа произошло вследствие того, что старший (знаковый) бит стал равен еди-
нице, а это в дополнительном коде является признаком отрицательного  числа.
     В рассмотренных примерах предполагалось, что ДССП-процессор  находится
в режиме десятичного ввода/вывода чисел. Для установки этого режима в языке
РАЯ имеется команда B10.
     Во многих задачах требуется интерпретировать обрабатываемые данные  не
как числа, а как двоичные коды, т. е. 16-битные машинные слова. В ДССП есть
возможность работать с кодами, представленными в двоичной, восьмеричной или
шестнадцатеричной системе счисления. Для установки нужного режима достаточ-
но выполнить одну из трех команд: B2, B8 или B16, после чего процессор  бу-
дет воспринимать и распечатывать все  вводимые  коды  в  указанной  системе
счисления.
     Данной возможностью можно пользоваться для перевода десятичных чисел в
системы счисления с основаниями 2, 8 и 16. Например, для перевода числа  29
нужно ввести и выполнить следующую строку:
     B10  29  B2 . B8 . B16 .
В результате процессор выдаст на экран ряд чисел:
     0000000000011101    000035   001D
которые являются представлениями десятичного числа 29 в трех указанных сис-
темах счисления. Заметим, что коды печатаются в их машинном  представлении,
т. е. с ведущими нулями и  без  знаков  "+",  "-".  При  выполнении  строки
     B10  -2  B8 .
будет выдано число 177776, которое является восьмеричным представлением  -2
в дополнительном коде.
     При работе с шестнадцатеричными кодами могут возникать коллизии  между
числовыми литералами и именами команд ДССП-процессора.  Например,  16-ичное
число B8 будет истолковано как команда установки восьмеричного режима, а не
как 16-ичная константа. Для  избежания  неопределенности  следует  начинать
числовые литералы с незначащего нуля, например 0B8.
     Основу системы команд ДССП-процессора составляют операции преобразова-
ния данных, находящихся в стеке.  Общее  правило,  регламентирующее  работу
этих операций, состоит в том, что каждая операция потребляет  (удаляет)  из
стека требующиеся ей операнды и засылает на их место  значения  результатов
(если таковые имеются).
     Рассмотрим команды процессора, реализующие четыре арифметических  опе-
рации: сложение, вычитание, умножение и деление целых чисел. Для их изобра-
жения в языке РАЯ используются слова: +, -, * и / соответственно. _тобы по-
лучить в стеке сумму двух чисел, например 123 и 45, нужно заслать эти числа
в стек и выполнить команду +. Для этого достаточно ввести с клавиатуры сле-
дующую строку (предполагается, что установлен режим десятичного ввода/выво-
да):
     123   45   +   <ВК>
Если теперь выдать на экран содержимое стека (с  помощью  команды  ..),  то
станет виден результат сложения:     [  168]
     Аналогичным образом работает коммутативная операция умножения.

     При выполнении некоммутативных операций вычитания и деления в качестве
уменьшаемого (делимого) берется подвершина стека, а вычитаемым  (делителем)
служит вершина. Например, для вычисления разности  151-68  нужно  выполнить
строку:     151   68
       Программа выполнения арифметического действия в языке РАЯ характери-
зуется тем, что операция находится после соответствующих ей операндов.  Та-
кая запись арифметических выражений носит название постфиксной  (или  поль-
ской инверсной) записи и широко используется в стековых микрокалькуляторах.
Пусть, например, нам необходимо вычислить значение арифметического  выраже-
ния:     ((127+81)*15-(31+117)*21)*3
     В постфиксной записи это выражение будет выглядеть так:
     127  81  +  15  *  31  117  +  21  *  -  3  *
Данная строка (в которой слова отделены друг от друга  пробелами)  является
готовой программой для вычисления нашего выражения ДССП-процессором.
     Команда деления / отличается от других  арифметических  операций  тем,
что ее результатом являются два значения - частное и остаток. _астное  ока-
зывается в подвершине стека, а остаток - в вершине. _астное отрицательно  в
том случае, если делимое и делитель разных  знаков.  Остаток  всегда  имеет
знак делимого. Приведем несколько примеров использования команды деления.
     -125  7  /  [-17,-6]  /  [2,-5]  /  [0,2]  /  [0,0]
     При выполнении вычислений могут возникать исключительные ситуации: пе-
реполнение и деление на нуль. ДССП-процессор никак не реагирует на  них  (в
частности, при делении на нуль содержимое стека не меняется),  контроль  за
корректностью использования операций возлагается на программиста.
     При программировании часто приходится увеличивать или уменьшать  нахо-
дящееся в стеке значение на 1 и на 2. В язык РАЯ введены специальные коман-
ды, выполняющие указанные действия над вершиной стека. Они обозначены  сло-
вами: 1+, 1-, 2+, 2-.
     Выполнение этих команд эквивалентно засылке в  стек  нужной  константы
(1 или 2) с последующим  выполнением  требуемого  арифметического  действия
(+ или -). Например, 2+ эквивалентно паре слов:         2 + .
     В базовом языке ДССП-процессора имеются также команды T0 и T1, изменя-
ющие значение вершины (Top) стека на 0 и 1 соответственно, не  зависимо  от
того, какое значение было в вершине до указанной команды. Примеры:
     -5  [-5]  T1  [1]  T0  [0]
     Для работы с числовыми данными предназначены также команды NEG, ABS  и
SGN. Команда NEG изменяет знак вершины стека на противоположный, ABS  заме-
няет значение вершины стека его модулем, SGN - потребляет числовое значение
из вершины стека и помещает на его место знак извлеченного числа: -1 - если
число отрицательно, 1 - если положительно, 0 - если равно нулю. Например:
     5  NEG  [-5]  ABS  [5]  SGN  [1]
     Имеющиеся в базовом языке команды MIN и MAX позволяют  выбирать  соот-
ветственно меньшее и большее из двух целых чисел. Операндами для  этих  ко-
манд служат два числа, находящиеся в вершине и  подвершине  стека.  Команда
MIN оставляет в стеке минимальное из чисел-параметров, MAX  -  максимальное
из них. Например:
     -5  0  15  MIN  [-5,0]  MAX  [0]
     Для нахождения наименьшего (наибольшего) из трех чисел, находящихся  в
стеке, достаточно дважды применить команду MIN (MAX):
     [127,-2,13]  MIN  MIN  [-2]
     Помимо команд, ориентированных на работу с  числовыми  данными,  набор
команд ДССП-процессора включает ряд операций, предназначенных для  преобра-
зования 16-битных кодов. Эти операции трактуют элемент стека  как  машинное
слово, биты которого пронумерованы справа налево таким образом,  что  самый
левый бит имеет номер 15, а самый правый номер 0. Убывающая нумерация  ком-
понент повторяет принятую для многих микропроцессоров нумерацию  битов  ма-
шинного слова.
     К командам, выполняемым над кодами, прежде всего относятся:
     - побитная инверсия вершины стека INV, изменяющая значение каждого би-
       та вершины, т. е. заменяющая 0 на 1, а 1 на 0;
     - побитная конъюнкция вершины и подвершины стека &, устанавливающая  в
       i-м бите результата, i=15,14,...,0, значение 1, если i-е биты  обоих
       операндов равны 1, а в прочих случаях полагающая i-й бит равным 0;
     - побитная дизъюнкция вершины и подвершины стека &0, устанавливающая в
       i-м бите результата, i=15,14,...,0, значение 0, если i-е биты  обоих
       операндов равны 0, а в прочих случаях полагающая i-й бит  равным  1;
     - побитное сложение (неэквивалентность) '+' вершины и подвершины,  ус-
       танавливающее в i-м бите результата значение 0, если i-е биты  обоих
       операндов имеют одинаковые значения, и полагающее i-й бит результата
       равным 1, если значения i-х битов операндов различны.
     В приведенных далее  примерах  предполагается,  что  установлен  режим
восьмеричного ввода/вывода (выполнена команда B8).
     525 INV  [177252]  722 &  [202]  136 &0  [336]  325 '+'  [13]
     Побитную конъюнкцию часто используют для обнуления (очистки)  разрядов
слова. Для этого выполняют конъюнкцию исходного слова с маской,  содержащей
нули в тех разрядах, которые нужно очистить и единицы - в остальных  разря-
дах. Например, если нужно обнулить биты с 3-го по 5-й в некотором слове  X,
нужно произвести его побитную конъюнкцию с маской 177707. Для  X=235  полу-
чим:       [235]  177707  &  [205]
     Побитная дизъюнкция может быть использована для занесения нужной  ком-
бинации битов в предварительно очищенную группу разрядов слова. Пусть, нап-
ример, нужно занести двоичную комбинацию 010 в биты с 3-го  по  5-й  слова,
оставшегося в стеке в результате последнего примера. Это можно сделать так:
     [205]  20  &0  [225]
     К операциям манипулирования кодами относятся также команды логического
сдвига:
     - сдвиг влево SHL - каждый бит вершины стека, начиная с 15-го принима-
       ет значение следующего за ним в порядке убывания номеров, а  послед-
       ний, нулевой бит принимает значение 0;
     - сдвиг вправо SHR - каждый бит вершины стека, начиная с 0-го принима-
       ет значение следующего за ним в порядке возрастания номеров, а  15-й
       бит принимает значение 0;
     - сдвиг по вершине SHT - верхний элемент изымается из стека и рассмат-
       ривается как целое число N, указывающее сколько сдвигов  и  в  каком
       направлении надо произвести в вершине стека:  при  N>0  производится
       сдвиг влево, при N<0 - вправо.
     Примеры:
     B8  125  SHR  [52]  SHL  [124]  -2 SHT  [25]
     Операциями сдвига влево можно пользоваться для умножения чисел на 2  в
степени N, где N - натуральное число, определяющее количество сдвигов. Нап-
ример, умножение числа -5 на 8 можно выполнить, сдвинув это число на 3 раз-
ряда влево:
     B10  -5  3  SHT  [-40]
     При этом следует учитывать возможность возникновения переполнения:
     B10  5000  SHL  SHL  [20000]  SHL  [-25536]
     Сдвиг вправо можно использовать как операцию деления  нацело  на  2  в
степени N только для положительных чисел, так как  старший  (знаковый)  бит
при сдвигах вправо обнуляется. Например:
     5  SHR  [2] тогда как
     -1  SHR  [32767]
     Для обработки двоичных кодов предназначена также команда  ДССП-процес-
сора SWB. Ее функция заключается в перестановке байтов вершины стека.  Про-
иллюстрируем работу этих команд, используя  режим  шестнадцатеричного  вво-
да/вывода (в этом режиме каждый байт изображается двумя  16-ричными  цифра-
ми):
     B16  0ABCD  [ABCD]  SWB  [CDAB]  SWB  [ABCD]
     Важную роль в языке РАЯ играют команды манипулирования стеком. Они  не
изменяют значения данных, находящихся в стеке, а лишь меняют их  расположе-
ние, облегчая доступ к операндам, находящимся в глубине стека.
     Имеется три команды удаления элементов стека: D, DD, DS (Drop - выбро-
сить). Команда D удаляет из стека один (верхний) элемент, DD - два  элемен-
та, например:
     [1,2,3,4]  D  [1,2,3]  DD  [1]  D  []
     DS удаляет из стека все элементы (очищает стек):
     [1,2,3]   DS   []
     Команда копирования вершины стека C (Copy - копировать) производит за-
сылку в стек копии текущего значения его вершины. Это равносильно  дублиро-
ванию верхнего элемента стека: прежняя вершина становится подвершиной, а ее
копия - новой вершиной. Пример:
     [5]  C  C  [5,5,5]
     Покажем применение  этой  команды  на  примере  вычисления  многочлена
p(x)=3*x**2+4*x-5 по схеме Горнера: p(x)=(3*x+4)*x-5. Считаем, что значение
x содержится в вершине стека.
     [x]  C  3  *  [x,3x]  4  +  *  [x(3x+4)]  5  -  [p(x)]
     Наряду с командой копирования вершины стека в языке РАЯ имеются  также
команды C2, C3, C4, копирующие элементы, находящиеся на глубине 2, 3, 4. Их
работу можно пояснить следующими примерами:
     [1,2,3]  C2  [1,2,3,2]  C4  [1,2,3,2,1] [1,2,3,2,1]  C3  [1,2,3,2,1,3]
     Имеется также команда CT копирования элемента, находящегося на  глуби-
не, которая указана в вершине стека. Выполняя CT, процессор изымает из сте-
ка верхний элемент, использует его значение как указатель глубины залегания
копируемого элемента и засылает копию последнего в стек.  Так,  копирование
элемента, находящегося на глубине 5, задается парой команд 5  CT,  выполняя
которые, процессор зашлет в стек число 5, а затем выполнит команду CT.  Вы-
полнение CT с параметрами 1, 2, 3, 4 эквивалентно  соответственно командам:
C, C2, C3, C4.
     Команды обмена E2, E3, E4 (Exchange - обменять) производят перестанов-
ку первого (верхнего) элемента стека соответственно со 2-м, 3-м, 4-м, т. е.
с находящимся на глубине 2, 3, 4 элементом. Например:
     [a,b,c]  E3  [c,b,a]  E2  [c,a,b]
     Для обмена на большую глубину служит команда ET, употребляющая, так же
как CT, значение вершины стека в качестве указателя глубины залегания  эле-
мента, который обменивается с первым элементом. Например:
     [a,b,c,d,e]  5  ET  [e,b,c,d,a]
     Команда ET с параметрами 2, 3, 4 эквивалентна командам Е2, Е3, Е4.
     Для иллюстрации использования команд копирования и  обмена  рассмотрим
учебную задачу. В стеке заданы три числа [a,b,c]. Требуется получить в сте-
ке: [a+b,b+c,a+c]. Можно предложить следующую программу, смысл которой  по-
нятен из комментариев.
     [a,b,c]  C3  C3  C3  [a,b,c,a,b,c]  +  [a,b,c,a,b+c]
     E4  [a,b+c,c,a,b]  +  [a,b+c,c,a+b]  E4
     [a+b,b+c,c,a]   +   [a+b,b+c,a+c]
     Этот пример хорошо показывает, как велика роль комментариев,  отражаю-
щих состояние стека операндов.
     В программах часто приходится сравнивать между собой числовые величины
и выполнять различные процедуры в зависимости от результатов  сравнения.  В
языке РАЯ имеются команды сравнения <, =, >. Они определены над числами и в
качестве результата выдают числовые значения 0 и 1. Так, команда <  потреб-
ляет из стека два элемента и засылает в стек число 1, если значение нижнего
элемента оказалось меньше значения верхнего, а в противном случае  засылает
0. Например, в результате выполнения последовательности 5  -20  <   в  стек
будет заслан 0. Команда = засылает 1 в  случае  равенства  потребленных  ею
элементов. Команда > засылает 1, когда нижний элемент больше верхнего.
     Для программирования нестрогих сравнений (меньше или равно, больше или
равно) используется команда NOT, которая заменяет значение  вершины  стека,
не равное нулю, нулем, а равное нулю - единицей. Например, вычисление логи-
ческого выражения  x>=5, где x - некоторое  число,  находящееся  в  вершине
стека, можно задать следующим образом:
     [x]  5  <  NOT  [1/0]
     Дальнейшее расширение возможностей программирования условий  обеспечи-
вается применением, наряду с командами сравнения, логических операций конъ-
юнкции & (логическое И) и дизъюнкции  &0 (логическое ИЛИ). Пусть, например,
требуется получить в стеке 1, если находящееся в вершине число x  принадле-
жит полусегменту [5,10) или равно 2, и нуль - в противном случае. Это можно
реализовать следующей последовательностью команд:
     [x]  C  5 <  NOT  [x,x>=5]  C2  10  <  [x,x>=5,x<10]
     &  [x,(x>=5)&(x<10)]  E2  2  =  &0  [1/0]
     Средства управления программой в зависимости от результатов  сравнения
будут рассмотрены в дальнейшем.

                      2.2. ДССП-процессор

     Отдельные команды и короткие последовательности  команд  можно  выпол-
нять, подавая их на вход процессора непосредственно с клавиатуры терминала.
При этом ДССП-процессор имитирует работу постфиксного калькулятора.  Вводи-
мые с клавиатуры числа и мнемокоды операций разделяются пробелами.  Введен-
ный текст отображается в виде строки на экране терминала. Сигналом  оконча-
ния ввода и командой процессору "Выполнить  введенное  предписание"  служит
нажатие клавиши <ВК>, обозначаемой также  <CR>,  <RETURN>.  Поступающие  на
вход процессора числа заносятся в стек, а команды - выполняются над стеком.
Полученный в вершине стека результат вычисления можно скопировать на  экран
терминала командой . (точка). Например, чтобы вычислить выражение  (2-5)*30
и вывести на экран полученный результат, вводим:
     2  5  -  30  *  .  <ВК>
После нажатия клавиши <ВК> процессор выдает результат, так что  вся  строка
будет иметь вид
     *   2  5  -  30  *  .     -90
     *
Звездочка в начале строки выдается процессором в качестве сигнала,  что  он
ждет ввода.
     В рассмотренном примере процессор воспринимал и  обрабатывал  вводимые
числа как целые десятичные. В действительности при вводе производился пере-
вод этих чисел в двоичный дополнительный код, а при выводе - обратный пере-
вод в десятичную систему. ДССП-процессор допускает также режимы  двоичного,
восьмеричного и 16-ричного ввода/вывода.
     Нажатия клавиш вызывают подачу на вход процессора кодов,  представляю-
щих обозначенные на этих клавишах литеры (буквы, цифры,  знаки  препинания,
символы операций). Последовательность вводимых литер образует входную стро-
ку, максимальная ее длина 80 литер.
     Обрабатывая входную строку, процессор вычленяет в ней слова  сочетания
литер, разделенные друг от друга пробелами, и интерпретирует их. Если обра-
батываемое слово является известным процессору именем процедуры или  данно-
го, то процессор выполняет действия, которые должно вызывать по определению
это имя. Если же слово не известно процессору, то он пытается интерпретиро-
вать его как число с учетом установленного режима ввода/вывода.
     _ислами признаются слова, состоящие из допустимых в данном режиме цифр
и, может быть, содержащие в качестве первой  литеры  знак  минус.  Принятое
число переводится в двоичный дополнительный код и засылается в стек операн-
дов в виде 16-битного слова. При этом, если значение  числа  оказалось  вне
диапазона представимых значений [-32768,32767], то оно заменяется сравнимым
по модулю 2**16 значением из этого диапазона.
     В том случае, когда обрабатываемое слово не известно процессору  и  не
может быть принято в качестве числа, процессор выдает  на  экран  терминала
сообщение: "не знаю <обрабатываемое слово>" и ждет ввода дальнейших предпи-
саний.
     Ввод данных в виде произвольного текста производится в форме текстовых
литералов, представляющих собой текст,  заключенный  в  кавычки,  например:
"Текстовый литерал". Поступление текстового литерала на вход процессора вы-
зывает запись заключенного между кавычками текста в главную память  в  виде
цепочки байтов-литер. При этом в стек засылается адрес первого байта и чис-
ло байтов (длина текста). Текстовый литерал,  дополненный  спереди  точкой,
воспринимается процессором как команда "выдать находящийся между  кавычками
текст на экран терминала".
     Код отдельной литеры засылается в стек в качестве младшего байта  вер-
шины при поступлении на вход процессора этой литеры вместе с  предпосланным
ей знаком #. Например, знакосочетание #Д зашлет в стек код буквы Д.
     Имена определяемых процедур и объявляемых данных заносятся в  словарь,
устанавливающий связь этих имен с поименованными объектами, то есть с  раз-
мещенными в главной памяти телами процедур и описателями данных.  Поиск  по
словарю выполняется процессором при распознавании слов из входной строки. В
результате выполнения определения процедуры в словарь  заносится  имя  этой
процедуры и указатель (адрес) ее тела, которое представляет собой  последо-
вательность указателей процедур и данных, составляющих определение. Другими
словами, внутреннее представление тела процедуры  получается  заменой  имен
процедур и данных в ее определении указателями соответствующих тел, которые
в свою очередь являются такимиже последовательностями указателей, а в  слу-
чае примитивов - цепочками машинных команд. Такое внутреннее  представление
программы мы назаваем процедурным кодом.
     Когда наряду с компиляцией определения процедуры P скомпилированы так-
же определения всех не известных до того процессору вложенных процедур,  то
образуется законченная иерархия указателей, обеспечивающая возможность  вы-
полнения процедуры P путем подачи на вход процессора одного только ее  име-
ни. При этом имена скомпилированных в связи с определением P вложенных про-
цедур, если не требуется обращаться к этим процедурам по отдельности,  сох-
ранять в словаре нет смысла. В ряде случаев оказывается целесообразным зак-
рыть доступ к той или иной части  словаря,  оставив  возможность  выполнять
лишь некоторые процедуры.
     Для того, чтобы удовлетворить подобным требованиям, словарь реализован
в виде совокупности подсловарей, над которой определены операции, позволяю-
щие создавать и уничтожать подсловари и их части, удалять имена,  закрывать
и открывать доступ к тем или иным подсловарям. Каждый  подсловарь  обладает
именем. Имена подсловарей должны начинаться литерой  $,  например:  $PRIME,
$EDIT.
     Подсловарь  $PRIME,  содержащий  базовый  набор  слов,  после  запуска
ДССП-процессора открыт как для доступа к имеющимся в нем словам, так и  для
пополнения новыми словами.
     Обычно текст конструируемой программы не вводится на  вход  процессора
непосредственно с клавиатуры, а формируется в буфере редактора текстов спе-
циально выделенной для этого области памяти объемом около 5 тыс. литер. Ко-
мандой E (Edit - редактировать) устанавливается режим редактирования, в ко-
тором набираемые на клавиатуре слова уже не воспринимаются процессором  как
команды, подлежащие немедленному выполнению, а записываются в буфер  и  од-
новременно отображаются на экран. По окончании ввода и редактирования  тек-
ста содержимое буфера редактора можно выдать на вход процессора командой PF
(Perform - выполнить). При этом будут выполнены все содержащиеся  в  тексте
команды. В частности, процессор выполнит команды объявления данных и  опре-
деления процедур, находящиеся в буфере.
     По завершении выполнения процедуры и данные доступны по именам,  наби-
раемым с клавиатуры и можно произвести проверку правильности программы, вы-
полняя процедуры в восходящей последовательности.
     Несколько слов о вводе и выводе данных. Основными внешними устройства-
ми служат терминал, магнитный диск и принтер. В базовом языке  имеются  ко-
манды обмена отдельными байтами и последовательностями (строками) байтов, а
также команды манипулирования файлами.

                     Определение процедур

     В качестве основного приема программирования ДССП предоставляет  поль-
зователю возможность определять поименованные последовательности  операций,
называемые процедурами. Пусть требуется, например, вычислить значения квад-
ратного трехчлена 3*x**2-4*x+9 для задаваемых значений x.  В  таком  случае
следует определить процедуру, реализующую формулу  трехчлена  и  выдачу  на
терминал результата, а затем применять эту процедуру к конкретным значениям
x. Искомая  процедура,  назовем  ее  PX,  определяется  следующим  образом:
     :  PX  [x]  C  3  *  4  -  *  9  +  [3x**2-4x+9]  .  D  []  ;
   Двоеточие означает операцию "определить процедуру", причем имя процедуры
следует за двоеточием после разделительного пробела. Определяющая  последо-
вательность команд (тело процедуры) располагается вслед за именем процедуры
и заканчивается точкой с запятой. Короче, процедура определяется  в  форме:
     :  <имя процедуры>  <тело процедуры>  ;
     В языке РАЯ требуется комментировать состояние стека операндов в нача-
ле и в конце процедуры. В теле процедуры комментарии расставляются  по  ус-
мотрению программиста в трудных для понимания местах.
     Комментарии помогают человеку понять и использовать процедуру, процес-
сор же просто игнорирует все, что заключено в скобки. Поэтому при вводе оп-
ределения отдельной процедуры с терминала комментарии можно опустить.
     После того как определение процедуры введено и нажатием  клавиши  "ВК"
процессору сообщено о конце ввода, на экране терминала появляется  звездоч-
ка, сигнализирующая о выполнении команды "определить процедуру" и готовнос-
ти процессора продолжить диалог. Теперь можно применить процедуру PX к  за-
даваемым с клавиатуры значениям x, например к 2, 3, 4 (выдаваемое процессо-
ром подчеркнуто):
     *  2  PX   <ВК>     13
     __              ______
     *  3  PX   <ВК>     24
     __              ______
     *  4  PX   <ВК>     41
     __              ______
      Определим   более   общую   процедуру   вычисления   трехчлена   вида
a2*x**2+a1*x+a0, позволяющую задавать значения как x, так и a0, a1, a2. На-
зовем ее PXA:
     :  PXA  [a0,a1,a2,x]  C  E4  E3  [a0,x,a1,x,a2]  *  +
             [a0,x,a2*x+a1]  *  +  [a2*x*x+a1*x+a0] ;
     При использовании PXA в стеке должны находиться в требуемой последова-
тельности значения a0, a1, a2, x. Например: a0=1, a1=2, a2=-3, x=4
     *  1  2  -3  4  PXA  >  D   <ВК>     -39
     __                               _______
     *
     __
     В теле процедуры, наряду с базовыми операциями процессора, могут нахо-
диться процедуры, определяемые пользователем.  Например,  можно  определить
процедуру P, которая дополнительно к вычислениям,  выполняемым  PXA,  будет
выдавать копию результата на терминал и удалять результат из стека.
     :  P  [a0,a1,a2,x]  PXA  [a2*x*x+a1*x+a0]  .  D  []  ;
     В частности, тело процедуры может включать имя самой определяемой про-
цедуры, т. е. процедура может быть рекурсивной. Например:
     :  TIME  [t]  1-  [t-1]  TIME  ;
     Эта процедура уменьшает на 1 значение вершины стека и снова обращается
к себе же, т. е. работает как счетчик времени.
     Счетчик TIME в принципе не  может  остановиться:  процедура  вычитания
единицы будет выполняться снова и снова, пока работает процессор. Но в ДССП
имеются средства, позволяющие управлять ходом процесса в зависимости от по-
лучаемых результатов - операции управления ходом программы.

              Выполнение по условию и повторения

     Условия выполнения или невыполнения  процедуры  формулируются  относи-
тельно знака числа, точнее, относительно знака значения, которым обладает в
текущий момент вершина стека. Основная команда условного выполнения  проце-
дуры - BRS  (BRanch on Sign ветвиться по знаку) предписывает выполнить одну
из трех названных вслед за BRS процедур в  зависимости  от  знака  текущего
значения вершины стека. Выполняя BRS, процессор изымает  из  стека  верхний
элемент, тестирует его значение, и если оно отрицательно, то выполняет пер-
вую из названных процедур, если равно нулю, то вторую, а если положительно,
то третью. Так команда
     BRS  N  Z  P
     вызовет удаление из стека одного элемента и  выполнение  процедуры  N,
если удаленное значение отрицательно, выполнение процедуры P, если  положи-
тельно, и выполнение процедуры Z, если равно 0.
     Примером использования команды BRS служит следующее определение проце-
дуры SGN
     : SGN  [X]  BRS  -1  0  1  [SGN(X)]  ;
 Эта процедура заменяет содержащуюся в вершине стека величину X числом  -1,
если  X<0, числом 0, если X=0, и числом 1, если X>0. Процедура SGN  имеется
в ДССП в качестве базовой операции процессора.
     Команда BRS, наряду с выбором одной процедуры из трех данных,  обеспе-
чивает  возможность  реализации  двузначных  операторов  вида   IF-THEN   и
IF-THEN-ELSE . Например, предложению  if x>0 then P1 else P0  соответствует
команда BRS P0 P1 P2, а предложению if x=0 then P - команда BRS P NOP P,  в
котором NOP - имя пустой операции. Но в ДССП имеется более эффективная реа-
лизация двузначных условий - команды IF-, IF0, IF+, BR-, BR0, ВR+.
     Команды группы IF соответствуют оператору IF-THEN . Например,  команда
IF- P предписывает изъять из стека верхний элемент и тестировать его  знак,
причем если этот элемент имеет знак минус, то выполнить процедуру P. Коман-
ды IF0 P и IF+ P предписывают выполнить процедуру P соответственно  в  слу-
чае, когда изъятый элемент равен нулю, и в случае, когда его значение поло-
жительно.
     В качестве примера, иллюстрирующего применение команд группы IF,  при-
ведем определение команды базового языка ABS,  вычисляющей  модуль  вершины
стека.
     :  ABS  [X]  C  [X,X]  IF-  NEG  [ЭXЭ]  ;
     Команды BR-, BR0 и BR+ соответствуют оператору IF-THEN-ELSE, предписы-
вая  выбирать одну из двух называемых вслед за  ними  процедур.  Если  знак
изъятого из стека элемента совпадает с имеющимся в обозначении команды,  то
выполняется процедура, названная первой, а если не совпадает, то выполняет-
ся вторая процедура. Например, команда BR0  P0  P1  предписывает  выполнить
процедуру P0 в случае, когда изъятый из стека элемент равен  нулю,  а  если
это условие не удовлетворено, то выполнить процедуру P1.
     Рассмотренные команды позволяют экономно запрограммировать  выполнение
процедуры в зависимости от данных условий. Наиболее часто встречающиеся ус-
ловия вида x<0, x=0, x>0 прямо реализуются  командами  группы  IF.  Условия
x<=0, x#0, x>=0 программируются с помощью команд BR-, BR0, BR+ путем  упот-
ребления в качестве первой процедуры пустой операции NOP. Например, предло-
жению if x<0 then P соответствует команда BR+ NOP P. Примером использования
команд группы BR может служить следующая реализация команды базового  языка
NOT, заменяющей нулевое значение вершины стека единицей, а ненулевое -  ну-
лем.
     :  NOT  [x]  BR0  1  0  [0/1]  ;
     Ветвление программы часто производится после команд сравнения  (<,  =,
>), вырабатывающих логическое значение 1 или 0 в зависимости от  результата
сравнения двух чисел. Команду базового языка MAX, например,  можно  запрог-
раммировать следующим образом:
     :  MAX  [x,y]  C2  C2  <  [x,y,1/0]  IF+  E2  D  [max(x,y)]  ;
     В группу команд ветвления входит также команда выбора BR, записываемая
в виде:
     BR  A1 P1  A2 P2  ...  AK PK ...  AN PN  ELSE P0
     Реализуя эту команду, процессор сначала  выполняет  процедурууказатель
A1 и сравнивает занесенное ею в стек значение с находящимся под ним  значе-
нием прежней вершины стека. Если значения совпали, то  из  стека  удаляются
два верхних элемента и выполняется сопоставленная  указателю  A1  процедура
P1, после чего производится переход к команде, следующей  за  командой  BR.
Если же сравниваемые значения не совпали, то из стека удаляется  один  вер-
хний элемент и те же действия производятся с парой A2 P2, затем, если  сов-
падения не получилось, то с парой A3 P3 и т.д. по AN  PN   включительно.  В
случае, когда ни одна из попыток не дала совпадения, выполняется  названная
после слова ELSE процедура P0. Обычно в роли процедур-указателей  выступают
числовые константы, например:
     [x]  C  [x,x]  BR  5 NEG  -3 ABS  0 NOT  ELSE T0  [y]
     В результате выполнения данной строки в вершине стека  будет  получено
значение y=-5, если x=5; y=3, если x=-3; y=1, если x=0 и y=0  во  всех  ос-
тальных случаях.
     В качестве иллюстрации того, как используются операции  условного  вы-
полнения процедур, осуществим модификацию приведенной в предыдущем  разделе
процедуры TIME с тем, чтобы счетчик останавливался при заданном условии:
     :  TIME  [t]  1-  [t-1]  C  IF+ TIME  [0]  ;
     Теперь эта процедура TIME вызывает себя только при положительном  зна-
чении вершины стека. Счетчик сработает ровно N раз, если к  началу  первого
выполнения TIME вершина содержит положительное число N. Например, чтобы по-
лучить 7 срабатываний, надо задать
     7  TIME   <ВК>
     Поскольку IF+ в определении TIME, как и всякая условная операция, изы-
мает из стека тестируемый элемент, а элемент этот необходим для последующих
операций, то его приходится дублировать,  помещая  перед  IF+  операцию   C
(Copy).
     Рекурсия не является основным средством многократного выполнения  про-
цедуры. Для программирования циклов в языке РАЯ имеются команды RP  (Repeat
- повторять) и DO (Do - делать, выполнять).
     Команда RP W  предписывает выполнять процедуру W снова и снова неогра-
ниченное число раз. _тобы повторения могли прекратиться, тело  процедуры  W
должно содержать операцию EX (Exit выйти), выполняемую при  заданном  усло-
вии. Операция EX осуществляет переход к выполнению процедуры, которая  сле-
дует по тексту программы за повторяемой процедурой, содержащей эту операцию
EX. Так, счетчик, реализованный выше в  виде  рекурсивной  процедуры  TIME,
можно запрограммировать как повторение процедуры W, которая определена так:
     :  W  [t]  1-  [t-1]  C  IF0 EX  [t-1]  ;
     _тобы счетчик сработал 25 раз, надо выполнить строку
     25  RP W
     Наряду с операцией EX, которая употребляется в командах выполнения  по
условию, имеются операции условного выхода EX-, EX0, EX+, производящие  тот
же эффект, что и команды IF- EX, IF0 EX, IF+ EX, т. е. потребляющие из сте-
ка верхний элемент, тестирующие его знак и  выполняющие  выход,  если  знак
совпадает с указанным в обозначении операции.
     В качестве примера рассмотрим задачу нахождения наибольшего общего де-
лителя двух натуральных чисел методом Евклида. Суть метода состоит  в  том,
что надо вычитать из большего числа меньшее до тех пор, пока числа не  ста-
нут равны друг другу. По достижении равенства и будет найден наибольший об-
щий делитель.
     Программирование будем вести методом  нисходящей  разработки.  Сначала
определим процедуру НОД, фиксирующую  общую  схему  алгоритма.  Параметрами
этой процедуры служат находящиеся в стеке два числа M и N , для которых на-
ходится наибольший общий делитель. В теле процедуры НОД должен  быть  задан
циклический процесс преобразования находящихся в стеке значений. В  резуль-
тате этого процесса в стеке должны остаться два равных числа - любое из них
можно принять в качестве наибольшего общего делителя. С учетом этих рассуж-
дений, процедуру НОД можно определить следующим образом.
     :  НОД [M,N]  RP ШАГ  [нод(M,N),нод(M,N)]  D  [нод(M,N)] ;
     Теперь необходимо запрограммировать один шаг  итерационного  процесса,
т.е. определить процедуру ШАГ. Параметрами для нее служат два числа,  нахо-
дящиеся в стеке. Нужно сравнить эти числа и выйти из цикла, если они равны,
в противном случае - вычесть из большего меньшее. Это можно сделать, напри-
мер, так :
     :  ШАГ  [M,N]  C2 C2 -  [M,N,M-N]  BRS NOP EX E2
     [min(M,N),max(M,N)]  C2  -  [min(M,N),max(M,N)-min(M,N)] ;
     Теперь в программе не осталось неопределенных процедур и можно присту-
пить к ее проверке. Проверку следует вести снизу-вверх, т. е. сначала нужно
убедиться в правильности работы процедуры ШАГ и лишь затем - НОД.
     Операция базового языка DO вызывает повторение названной вслед за  ней
процедуры N раз, где N - число, содержащееся в вершине стека к моменту  вы-
полнения DO. Например, чтобы процедура P выполнилась  8  раз,  надо  задать
      8   DO  P    <ВК>
     Если в теле процедуры P имеется хотя бы одна операция выхода  и  усло-
вие ее выполнения окажется удовлетворенным до того, как произойдет заданное
число повторений, то повторения будут прекращены путем выхода из  процедуры
подобно тому, как это делается в случае операции RP. Например, при повторе-
нии посредством DO описанной выше процедуры W, в определении которой содер-
жится IF0 EX, запись
     [T]  30  DO  W
     вызовет 30 повторений W, если значение T>=30. Если же 0<T<30, то  про-
цедура W выполнится T раз.
     Если к моменту выполнения операции DO в вершине стека оказалось  нуле-
вое или отрицательное значение, то следующая за DO процедура не  выполнится
ни разу.
     Для иллюстрации использования операции  DO  определим  процедуру  NUM,
подсчитывающую количество не равных нулю битов в 16-битном слове x,  задан-
ном в вершине стека.
     Счетчик количества единиц разместим в подвершине стека. Подсчет единиц
будет заключаться в 16-кратном повторении процедуры NUMI, в  которой  будем
исследовать один бит слова x. По выходе из цикла в подвершине стека  должно
находиться искомое число.
     B10
     :  NUM  [x]  0  E2  [N,x]  16  DO NUMI  [N,x]  D  [N]  ;
     Для подсчета ненулевых битов воспользуемся тем, что единица в  старшем
(15-м) бите слова служит признаком отрицательного числа.  Если  исследуемое
слово отрицательно, то надо прибавить к N единицу. В конце  процедуры  NUMI
нужно сдвинуть исследуемое слово на один разряд влево.
     :  NUMI  [N,x]  C  IF-  N+  [N,x]  SHL  [N,shl(x)]  ;
     Реализация процедуры N+ совсем проста: нужно прибавить единицу к  под-
вершине стека, не меняя вершины.
     :  N+  [N,x]  E2  1+  E2  [N+1,x]  ;
     Повторяемые процедуры могут содержать в своих телах операции RP и  DO,
приводящие к возникновению вложенных циклов, причем глубина вложенности до-
пустима любая. При этом имеется операция EXT выхода из вложенного  цикла  с
указанием глубины вложенности в вершине стека.

                       Именуемые данные

     Стек операндов является основным, но не единственным механизмом  мани-
пулирования данными в ДССП. Имеется также возможность, наряду с определени-
ями процедур, объявлять элементы и стандартно  организованные  совокупности
элементов (так называемые структуры) данных, доступные затем для  использо-
вания по их именам. Реализуя объявления данных, процессор резервирует  тре-
бующюся для их хранения память и обеспечивает необходимые механизмы доступа
к этой памяти.
     Базовый язык ДССП включает ряд рассмотренных  ниже  слов-директив  для
объявления переменных и массивов. В порядке расширения языка системы в него
могут быть введены другие слова этого рода и, соответственно,  другие  эле-
менты и структуры данных.
     Слово VAR объявляет 16-битную числовую  переменную.  Например,  запись
     VAR  X
     объявляет переменную X, т. е. сообщает процессору, что имя X есть  имя
переменной. Процессор связывает с этим именем 16-битную  ячейку  памяти,  в
которой будет храниться значение данной  переменной.  Команда  присваивания
переменной X значения, которое содержится в вершине стека операндов,  имеет
вид
     !  X
     Выполняя эту команду, процессор изымает из стека верхний элемент и за-
писывает его значение в отведенную для переменной X ячейку.
     Команда, состоящая только из имени переменной, перед которым нет лите-
ры !, вызывает засылку в стек значения этой переменной, причем засылка про-
изводится путем копирования содержимого соответствующей ячейки  памяти,  т.
е. значение переменной остается неизменным. Таким образом, всякое вхождение
в программу имени переменной X, если ему  непосредственно  не  предшествует
словво, предписывающее иное действие, будет засылать в стек текущее  значе-
ние этой переменной, подобно тому, как засылаются непосредственно  заданные
числа (числовые литералы).
     В качестве примера приведем другой вариант рассмотренной выше процеду-
ры PXA вычисления значения квадратного  трехчлена  p(x)=a2*x**2+a1*x+a0  по
схеме Горнера. Параметры для этой процедуры не будем  засылать  в  стек,  а
разместим в переменных.
     VAR A0  VAR A1  VAR A2  VAR X
     :  PXA  []  A2  X  *  A1  +  X  *  A0  +  [p(x)] ;
     Хотя этот вариант программы несколько длиннее,  он  проще  и  понятнее
предыдущего.
     Слово VCTR объявляет одномерный массив (вектор) 16-битных ячеек,  при-
чем номер старшего элемента этого массива задается значением вершины.  Нап-
ример, в результате выпонения записи
     9  VCTR  ROW
     процессор резервирует 10 последовательно адресуемых слов памяти, обра-
зуя вектор ROW(0:9). Сначала производится засылка числа 9 в стек,  а  затем
выполняется процедура VCTR, употребляющая верхний элемент стека для опреде-
ления длины создаваемого вектора ROW.
     Засылка в стек значения j-го элемента вектора ROW,  0<=j<=9,  задается
командой
     [j]  ROW  [ROW(j)]
     Используя в качестве параметра находящийся в стеке номер элемента, имя
вектора ROW вызывает замену этого номера значением соответствующего элемен-
та. Если же непосредственно перед именем вектора ROW находится слово !,  то
указываемому вершиной элементу нанного вектора  присваивается значение под-
вершины, и глубина стека уменьшается на 2. Например, обнулить  5-й  элемент
вектора ROW можно так:
     []  0  5  !  ROW  []
     Имеется также возможность соэдания векторов-констант, то есть векторов
16-битных чисел, значения которых определены при его объявлении и  в  даль-
нейшем не изменяются. Так, вектор 16-битных констант VC длины L+1  объявля-
ется с помощью слова CNST в виде:
     CNST  VC  k0  k1  ...  kL  ;
     где k0, k1, ... kL - числовые литералы. Обращение к  элементам  векто-
ра-константы производится так же, как к компонентам обычных векторов.  Нап-
ример:
     1  VC  [k1]
     Многомерный массив 16-битных слов объявляется с помощью слова ARR, пе-
ред которым указываются максимальные значения индекса по каждому  измерению
и число измерений. Например, трехмерный массив TIR(0:8,0:2,0:24) объявляет-
ся так:
     8  2  24  3  TIR
     _исло 3, находящееся непосредственно перед ARR,  означает  размерность
объявляемого массива.
     Засылка элемента массива в стек  достигается  заданием  индекса  этого
элемента в сопровождении имени массива. Например, команда  засылки  в  стек
элемента TIR(0,2,2) выражается в виде
     0  2  2  TIR
     Соответсятвенно, присваивание этому элементу текущего значения вершины
стека задается командой
     0  2  2  !  TIR
     Все рассмотренные примеры иллюстрировали создание структур из  16-бит-
ных слов. Однако, язык позволяет также определять структуры  8-битных  бай-
тов. Для этого перед словом, определяющим структуру, ставится префикс BYTE.
Например,
     5  BYTE  VCTR  X
     - определение 6-ти компонентного вектора байтов X;
     BYTE  CNST  Y  65  66  67  ;
     - определение 3-х компонентного байтового вектора-константы Y;
     10  20  2  BYTE  ARR  MTRX
     - определение матрицы байтов MTRX(0:10,0:20).
     _тение элементов байтовых структур производится  точно  также,  как  в
случае структур 16-битных слов. При этом извлекаемое значение помещается  в
младший байт вершины стека, а старший байт вершины обнуляется.  В  качестве
значения, присваиваемого элементу байтовой структуры, также берется младший
байт находящегося в стеке 16-битного слова.
     Байтовые структуры данных чаще всего используются для хранения и обра-
ботки текстовой информации. Это объясняется тем, что для кодирования  одной
литеры в памяти компьютера отводится один байт. Для задания кодов  литер  в
языке РАЯ имеется конструкция #l, где l - любая литера, имеющаяся на клави-
атуре дисплея. ДССП-процессор воспринимает эту конструкцию как команду  за-
сылки в стек кода литеры l. Например:
     #1  [49]
     #   [32 - код пробела]
     Данная конструкция производит те же действия, что и числовой  литерал,
равный коду указанной литеры, однако ее использование является более  пред-
почтительным, так как, во-первых, освобождает от  необходимости  запоминать
коды и, во-вторых, делает программы более понятными.  Можно,  в  частности,
дать следующее определение вектора-константы Y:
     BYTE  CNST  Y  #A  #B  #C  ;
     Помимо префикса BYTE, в языке РАЯ имеются также префиксы для  создания
структур отдельных битов и двойных (32-битных) слов. Префикс BIT,  употреб-
ленный перед определением структуры, говорит о том, что элементом структуры
является отдельный бит. Например строка
     200  BIT  VCTR  SCALE
     предписывает создать одномерный массив битов SCALE(0:200), а строка
     BIT  VAR  FLAG
     - однобитную
     (двузначную) переменную FLAG. Следует иметь  в  виду,  что  для  любой
структуры данных отводится целое число байтов памяти (например под перемен-
ную FLAG будет отведен один  байт),  поэтому  экономия  памяти  достигается
только при использовании массивов битов. _тение и запись элементов  битовых
структур производится так же, как в случае байтовых  и  словных  данных  (с
учетом того, что допустимы лишь значения 0 и 1). Команда  получения  адреса
элемента (апостроф) помещает в стек два числа: адрес слова памяти  (в  под-
вершину) и номер бита в нем (в вершину). Доступ к элементам битовых  данных
осуществляется в несколько раз медленнее по сравнению с байтовыми и словны-
ми структурами.
     Префикс DBL служит для  создания  структур  32-битных  слов.  В  стеке
32-битное значение размещается в двух позициях: старшая половина - в верши-
не, младшая половина - в подвершине.  В  остальном  работа  со  структурами
двойных слов аналогична структурам, описанным выше.

            Работа с памятью по физическим адресам

     Рассмотренные средства обеспечивают возможность  именования  данных  и
манипулирования данными независимо от адресной системы компьютера. Но в ба-
зовый язык входят, кроме того, средства, позволяющие манипулировать адреса-
ми элементов памяти. Адрес переменной или элемента массива X  засылается  в
стек командой
     '  X
     В случае с элементом массива этой команде предпосылается значение  ин-
декса (индексов).
     Команда базового языка @ заменяет находящийся в  вершине  стека  адрес
слова памяти значением, которое содержит это слово. Например, значение  пе-
ременной Y можно поместить в стек, выполнив следующую строку:
     []  '  Y  @  [Y]
     Команда @B заменяет адрес значением  соответствующего  байта,  полагая
старший байт вершины стека равным нулю.
     Имеются также команды записи значений в память. Команда !T  записывает
по адресу, изъятому из вершины стека, 16-битное значение подвершины. Коман-
да !TB вызывает аналогичную запись младшего байта подвершины в байт,  адре-
суемый вершиной. Например, присвоить значение 15 пятому элементу  байтового
вектора  BV(0:5) можно следующими командами:
     []  15  5  '  BV  !TB  []
     Необходимость работы с памятью по физическим  адресам  возникает  лишь
при оздании программ, зависящих от архитектуры конкретного компьютера, нап-
ример, при создании драйверов ввода/вывода. Поэтому данные  средства  пред-
назначены в основном для системного программиста.

              Дополнительные операции для работы
                      с данными и памятью

     В целях получения большей эффективности и компактности программ в язык
РАЯ введены следующие операцции (работающие только с 16-битными  переменны-
ми).
     !0   <имя переменной> - обнулить переменную;
     !1   <имя переменной> - присвоить единицу переменной;
     !1-  <имя переменной> - уменьшить значение переменной на единицу;
     !1+  <имя переменной> - увеличить значение переменной на единицу;
     !-   <имя переменной> - вычесть из переменной значение вершины стека;
     !+   <имя переменной> - прибавить к переменной значение вершины стека.
     Каждая из этих операций легко программируется с использованием  команд
чтения и записи переменных. Например,
     !0  X   эквивалентно   0  !  X
     !1+ X   эквивалентно   X  1+  !  X
     !-  X   эквивалентно   X  E2  -  !  X
     Использование данных операций  повыщает  эффективность  и  наглядность
программ.
     На практике часто требуется присвоить какое-либо  одно  значение  всем
элементам массива. Для этого в языке РАЯ имеется операция !!!  <имя  масси-
ва>. Ее действие заключается в присваивании  значения  вершины  стека  всем
компонентам указанного массива. Операция !!! применима как к байтовым,  так
и к словным массивам.
     Пример использования:
     []  #   !!!  BUF  []
     - код литеры "пробел" записывается во все компоненты байтового массива
BUF.
     Набор команд ДССП-процессора включает, в качестве дополнения, три  ко-
манды, позволяющие читать и записывать отдельные биты ячеек памяти  компью-
тера. Это команды @BI, !BI0, !BI1. Параметрами для каждой из них служат на-
ходящиеся в стеке адрес слова памяти и номер бита в этом  слове  (напомним,
что биты нумеруются справа налево, начиная с нуля).  Команда  @BI  заменяет
указанные параметры значением выбранного бита (0 или  1),  команды  !BI0  и
!BI1 присваивают выбранному биту соответственно значение 0 и 1, удаляя свои
параметры из стека.
     В языке РАЯ имеются также средства для работы со строками байтов, рас-
положенными в памяти. Для задания строки байтов в стек помещаются два пара-
метра: начальный адрес строки (т. е. адрес ее первого байта) и длина строки
(количество байтов в ней).
     Команда !!!MB служит для присваивания всем байтам строки  одного  (за-
данного в стеке) значения. Она потребляет из стека три параметра:  [b,a,l],
где b - присваиваемое значение, a и l соответственно начальный адрес и дли-
на байтовой строки. Пусть, например, нужно обнулить элементы с 3-го по 10-й
байтового массива TXT(0:20). Для этого можно выполнить следующую строку:
     []  0  3  ' TXT  8  !!!MB  []
     в результате чего восемь последовательных элементов указанного  масси-
ва, начиная с 3-го, получат значение 0. Аналогичная команда !!!M предназна-
чена для заполнения одним и тем же значением строки 16-битных слов.
      Команда  !SB  выполняет  пересылку  байтовых  строк.  Ее   параметры:
[a1,l,a2], где a1 и l - начальный адрес и длина пересылаемой строки,  a2  -
начальный адрес строки, в которую выполняется пересылка. В  результате  вы-
полнения команды !SB в памяти с адреса a2 будет расположена байтовая строка
длины l, являющаяся точной копией строки, находившейся по адресу a1 до  вы-
полнения пересылки. Строка-источник и строка-приемник могут  перекрываться.
Пусть, например, требуется переместить элементы байтового  массива  M(0:10)
следующим образом: M(10):=M(9), M(9):=M(8), ..., M(1):=M(0). Для этого мож-
но воспользоваться командой !SB:
     []  0  '  M  10  C2  1+  [a,10,a+1]  !SB  []
     в результате произойдет перемещение строки из 10 байтов на один байт в
сторону увеличения адресов памяти.
     Команда !SB удобна для работы со сторками литер (напомним, что  каждая
литера кодируется одним байтом). Она позволяет, например, присваивать  бай-
товому массиву значение явно заданной литерной строки.  Для  задания  такой
строки служит текстовый литерал, т. е. заключенная в кавычки последователь-
ность литер, например "ТЕКСТОВЫЙ ЛИТЕРАЛ". Эта конструкция, встретившись  в
программе, вызывает засылку в стек начального адреса и длины байтовой стро-
ки, содержащей заключенный в кавычки текст. Данные  параметры  могут  затем
использоваться командой !SB. Например, фрагмент
     []  "ТАБЛИЦА"   0  '  TN  !SB  []
     вызовет пересылку литерала "ТАБЛИЦА" в массив TN.
     Команда SRCHB обеспечивает поиск заданного байта в строке.  Параметры:
[b,a,n], где b - байт, первое вхождение которого надо найти, a и  n  задают
соответственно адрес начала и длину строки, в которой ведется  поиск.  Если
n>0, то поиск ведется с адреса a до адреса a+n-1 (в сторону возростания ад-
ресов), если n<0, то поиск ведется с адреса a до адреса  a+n+1  (в  сторону
убывания адресов). В результате выполнения этой команды в стеке оказывается
значение d, равное смещению относительно адреса a до первого вхождения бай-
та b. Если такое вхождение не обнаружено, то d=n. Примеры:
     #T  "TEXT"  SRCHB  [0]
     #A  "TEXT"  SRCHB  [4]
     #E  "TEXT"  [#E,a,4]  1-  +  -4  [#E,a+3,-4]  SRCHB  [-2]
     Заканчивая рассмотрение средств работы с данными, остановимся на  воп-
росе, связанном с хранением данных во внешней памяти компьютера, т.  е.  на
магнитных дисках. В языке РАЯ имеется команда SAVE <имя файла>, предписыва-
ющая сохранить копию находящейся в главной памяти системы на диске вместе с
определенными пользователем объектами. При этом области памяти,  отведенные
под данные операциями VAR, VCTR, ARR, на диск не выводятся. Вследствие это-
го при загрузке сохраненной системы с диска значения  указанных  данных  не
определены (они должны определяться  во  воремя  выполнения  программы).  В
большинстве случаев это оправданно, так как нет  необходимости  расходовать
дисковую память для хранения рабочих переменных, буферов и т.п. Однако, бы-
вают данные, значения которых должны быть определены сразу  после  загрузки
системы с диска. В качестве примера  можно  привести  переменную,  хранящую
скорость обмена данными с некоторым внешним устройством.  При  переходе  на
другую скорость обмена достаточно изменить значение данной  переменной,  не
внося никаких исправлений в программу.
     Указанием процессору, что значения элементов некоторой структуры  дан-
ных должны выводиться на диск по команде SAVE, служит префикс FIX, помещае-
мый перед определеним структуры, например
     FIX  VAR  SPEED      20  FIX  BYTE  VCTR  TABL
     Работа с так определенными структурами данных ничем не  отличается  от
работы со структурами, определенными обычным образом.

                Команды управления процессором

     В языке РАЯ имеется немногочисленная  группа  команд,  предназначенных
для управления ДССП-процессором, а  точнее  -  эмулятором  ДССП-процессора.
     Команда RESTART вызывает перезапуск процессора.  При  этом  происходит
очистка стека, выдается сообщение
     ДССП версия ХХ.ХХ.ХХ
     Свободно  ХХХХХW
     *
     и процессор переходит в режим ожидания ввода  команд.  Данная  команда
бывает полезной при отладке программ. Она также выполняется при возникнове-
нии ошибочных ситуаций: выходе индекса за границы массива, исчерпании  сво-
бодной памяти и др.
     Команда \G служит для продолжения выполнения программы после  останова
на неопределенном слове. Если при выполнении процедуры процессор  встречает
ссылку на неопределенное слово, он выдает сообщение:
     останов
     не знаю <слово>
     .
     где точка - приглашение ДССП-процессора, сигнализирующее  о  том,  что
процессор находится в состоянии останова на неопределенном  слове.  В  этом
режиме можно выполнять любые команды процессора, так же, как в обычном  ре-
жиме, когда приглашеним служит звездочка. Выйти  из  данного  режима  можно
двумя способами - либо выполнив команду \G (тогда процессор  продолжит  вы-
полнение прерванной процедуры, пропустив неопределенное слово), либо по ко-
манде RESTART.
     Команда EXEC предписывает процессору выполнить процедуру, адрес  кото-
рой находится в вершине стека. Для получения адреса процедуры служит коман-
да '' (два апострофа), за которой указано имя процедуры.  Например,  в  ре-
зультате выполнения команды
     ''  ABS
     в стек будет заслан адрес процедуры ABS. Данные команды позволяют  пе-
редавать процедуру в качестве параметра другой процедуре.
     К группе команд управления  процессором  относится  уже  упоминавшаяся
операция SAVE <имя файла>, предписывающая сохранить копию системы на диске,
а также команды, определяющие источник ввода текстовой информации, подавае-
мой на вход процессору. Первоначально таким  источником  служит  клавиатура
дисплея.
     Команда LOAD <имя файла> переключает ввод на дисковый файл с указанным
именем. Команда PF - предписывает вводить команды из буфера редактора  тек-
стов. Команда TEXEC передает на вход процессора текстовую строку, параметры
которой заданы в стеке. По выполнении команд, содержащихся в указанных  ис-
точниках, ввод автоматически переключается на клавиатуру дисплея.

                  Команды управления словарем

     Воспринимаемый процессором входной поток команд  может,  в  частности,
содержать команды определения процедур и  данных,  вызывающие компиляцию во
внутреннее представление и запоминание тела процедуры или выделение  памяти
под указанные данные, а также занесение в словарь ДССП имени скомпилирован-
ной процедуры или структуры данных.
     Словарь устанавливает соответствие между  внешними  (употребленными  в
тексте программы) именами и адресами соответствующих этим  именам  объектов
во внутренним представлении. При обработке определения процедуры или описа-
ния поименованного данного процессор наращивает словарь, образуя в нем  но-
вый словарный вход, содержащий имя (точнее, 7 первых литер имени)  и  адрес
сопоставляемого этому имени тела процедуры или описателя данных.
     При программировании сверху-вниз в телах  процедур  могут  встречаться
ссылки на еще не определенные объекты. В этом случае в  словаре  образуются
словарные входы (заголовки), помеченные признаком неопределенности. Для вы-
дачи на экран дисплея всех неопределенных имен служит команда UNDEF.
     В ходе наращивания словаря имеется возможность образования подсловарей
- поименованных совокупносткй словарных входов. В подслоарь обычно  объеди-
няются процедуры и структуры данных, относящиеся к одной задаче. Во избежа-
ние путаницы между именами подсловарей и  других  объектов  программы,  имя
подсловаря должно начинаться с литеры $. Доступ к подсловарям для их  нара-
щивания или использования можно открывать и закрывать специальными команда-
ми, к числу которых относятся следующие (под именем $v подразумевается про-
извольное имя подсловаря).
     GROW  $v  - наращивать подсловарь $v, то есть, пока не будет предписа-
но иное, вносить имена всех компилируемых процедур и  данных  в  подсловарь
$v;
     USE  $v   - открыть для использования (для поиска в нем имен) подсл-
                 варь $v;
     SHUT  $v  - закрыть воЗможность использования подсловаря $v;
     ONLY  $v  - сделать доступным для использования только подсловарь $v;
     CANCEL    - отменить последнее ONLY.
     Имеется также команда ?$, печатающая на дисплее имена всех подсловарей
их состояния - открыт или закрыт подсловарь для поиска. Наращивается всегда
тот подсловарь, имя которого напечатано верхним.
     Базовые процедуры ДССП составляют подсловарь с именем $PRIME, открытый
для использования и наращивания по умолчаоию, то есть, если не было  коман-
ды, предписывающей наращивание иного подсловаря.
     Пусть, например, операцией ?$  было  распечатано  следующее  состояние
подсловарей.
     $PRG     открыт
     $PRIME   открыт
     $EDIT    закрыт
     $PRIME   открыт
     SYSTEM   закрыт
     Это означает, что в данный момент подсловарь $PRG открыт для наращива-
ния и использоваоия, $PRIME - только для использования, а  $EDIT  и  SYSTEM
недоступны. Отметим, что подсловарь может состоять из нескольких  секций  с
одинаковыми именами.
     Имеются команды удаления из словаря той или иной совокупности  словар-
ных входов и, может быть, связанных с ними процедур и данных. Так,  команда
FORGET $v удаляет все имена, занесенные в словарь (не только  в  подсловарь
$v) после последнего выполнения команды GROW $v вместе с обоЗначеными этими
именами объектами, и отменяет установленное им наращивание  подсловаря  $v.
Например, выполнив операцию FORGET $PRIME над словарем, состояние  которого
было показано выше, получим новое состояние:
     $EDIT    закрыт
     $PRIME   открыт
     SYSTEM   закрыт
     В процессе выполнения команды FORGET на дисплей выдаются имена удаляе-
мых секций.
     Команда PROGRAM $v производит те же действия, что и выполненные  псле-
довательно команды FORGET $v  GROW $v. _еловек воспринимает данную  команду
как заголовок программы. Наличие такой команды  в  начале  любой  программы
приводит к тому, что при повторной загрузке программы (операциями LOAD, PF)
будет удаляться ее старая копия и будет образовываться подсловарь для  хра-
нения объектов новой копии программы.
     Ввиду того, что в готовой программе подавляющее  большинство  процедур
являются вспомогательными, предусмотрена возможность удаления из словаря их
имен с сохранением сопоставленных им внутренних объектов. Команда CLEAR  $v
удаляет из всех секций подсловаря $v все имена, за  исключеним  тех,  перед
которыми в тексте программы (при их определении) стоял предпрефикс ::  (два
двоеточия). Например, в результате выполнения процессором следующего  фраг-
мента программы:
     PROGRAM $EXAM
     ::  FIX  VAR  X
              VAR  Y
     ::  :  X+  []  Y  !+ X  []  ;
     CLEAR $EXAM
     в подсловаре $EXAM останутся только имена X и X+, словарный вход Y бу-
дет удален (хотя переменная, соответствующая слову Y  во  внутреннем  пред-
ставлении, останется).

                     Команды ввода/вывода

     Основным средством взаимодействия пользователя с ДССП является  терми-
нал, которым может служить электронно-лучевой дисплей с клавиатурой,  элек-
трическая пишущая машинка или телетайп. С терминала осуществляется первона-
чальный ввод, редактирование и отладка программ, подготовка  данных  и  все
управление системой. Программы и данные, а также сама  ДССП  сохраняются  в
виде файлов на дисках и могут распечатываться на принтере.  Для  управления
вводом/выводом в наборе базовых процедур  ДССП  имеются  описываемые  далее
средства.
     Программирование работы терминала обеспечивается командами ввода и вы-
вода чисел, литер и последовательностей литер (строк), а  также  некоторыми
дополнительными командами.
     Команда TIB (Terminal Input Byte - ввод байта с терминала)  инициирует
цикл ожидания нажатия клавиши на клавиатуре терминала.  Принажатии  клавиши
8-битный код соответствующей литеры зацылается в стек в виде младшего байта
16-битного слова, причем старшие 8 битов этого слова содержат  нули.  Копия
введенной таким образом литеры отображается на дисплей. Имеется  также  ко-
манда TRB (Terminal Read Byte), отличающаяся от TIB тем, что  засылка  кода
введенной литеры в стек не сопровождается отображением этой литеры на  дис-
плей.
     Команда TIN (Terminal Input Number - ввод числа с терминала) иницииру-
ет цикл ввода в стек и отображения на дисплей набираемого с клавиатуры чис-
ла. Вводимое число должно быть последовательностью цифр, которая может  на-
чинаться знаком "минус", а заканчиваться "ВК". В зависимости от установлен-
ного режима ввода/вывода цифры воспринимаются  процессором  как  16-ричные,
десятичные, восьмеричные или двоичные. Если 16-ричное число начинается циф-
рой, обозначаемой буквой, то перед ней добавляется цифра 0. Введенное число
переводится в двоичный дополнительный код, который засылается в стек в  ка-
честве целочисленного значения 16-битного слова.
     Последовательность, содержащая n набираемых с клавиатуры  литер,  вво-
дится в память компьютера в виде n байтов, располагаемых по последовательно
возрастающим адресам, начиная с адреса a, при помощи команды TIS  (Terminal
Input String), перед которой в стек засылается адрес a  и  число  литер  n.
Пусть, например, объявлен вектор байтов X достаточной длины. Нужно ввести 9
литер, присвоив их значения элементам этого  вектора,  начиная  с  нулевого
элемента:
     0  '  X  9  TIS
     Аналогично с помощию команды TOS задается вывод последовательности  из
n байтов-литер с начальным адресом a:
     [a,n]  TOS  []
     Вывод на терминал непосредственно  включаемых  в  программу  элементов
текста обеспечивается конструкцией
     ."<текст>"
     Например, чтобы при выполнении некоторого фрагмента программы на  дис-
плее появился текст ВВЕДИТЕ НОМЕР ВАРИАНТА, фрагмент должен  содержать  за-
пись ."ВВЕДИТЕ НОМЕР ВАРИАНТА".
     Команда TON (Terminal Output Number) выводит на дисплей чисо,  изымае-
мое из подвершины стека, причем длина поля вывода должна быть задана в вер-
шине. Выводимое число выравнивается по правому краю поля, свободные позиции
слева заполняются пробелами, а если длина числа  превышает  заданную  длину
поля, то происходит отсечение слева. В режиме десятичного ввода/вывода  от-
рицательные числа начинаются знаком минус.
     Команда TOB (terminal output byte) печатает литеру, код которой  задан
младшим байтом вершины стека. Глубина стека уменьшается на 1.
     Имеются также команды, прямо управляющие курсором дисплея:
     CR - переход на начало новой строки,
     SP - пробел, то есть перемещение на одну позицию вправо.
     Команда BELL вызывает короткий звуковой сигнал ("звонок").
     Команды вывода на принтер подобны командам вывода на терминал и  бази-
руются на аналогичной мнемонике< в которой литеры LP  (Line  Printer)  либо
Заменили TO, либо добавлены в качестве ведущих. НаПример, LPCR - переход на
начало новой сТроки, LPSP - пробел, LPN - вывод числа из подвершины в поле,
заданном вершиоой, LPB - ъыъод литеры, LPS - вывод  СтРоки  литер.  Имегтся
также команда ЪN] LPT, перемещающая Печатающую голоВку в позицию N печатае-мой строки и команда LPFF, обеспечивающая прогон листа буоаги.  Для  Печатиявно чаанного тексТа удобно воспольЗоваться текстовыо литералом и  командой
LPS, например:
     "ТАБЛИЦА ЗНА_ЕНИЙ ФУ_КЦИИ"  LPS
        Обсаботка прерываний и исключительных ситуаций

      При программировании периферии возниоает  необходимоСть  обрабатывать
прерывания. В ДССП Эта обработоа программируется слгдующим  образом.  Прог-
раома, предназначенная для обработки псерывания предстаВляет собой  обычную
процедвру ДССП, перед определением которой стоит пРедпрефикс INT,  например
 INT : A I 1+ ! I ;
      Предпрефикс INT обеспечиваеТ сохраоение состояния процессора при пре-
Рывании и воссэановление его по ооончании обработои прерывания.
      Для связыъания пРогРаммы обработки с  конкретным  прерыванием  СлУжит
кооанда LINK:
             <адрес вектора> LINO <имя процедУры>
      При выполнении которой по соответствщющему вектору записывагэсЯ обра-
щение к процедУре обработки прерывания. Команда LINK моЖет осуществлять какстатичесоое связывание процедуры с прерыванием, происходящее в момент  ком-
пиляции программы< Так и динамическое, при выполнении программы.
      Прерываниг процессора - это способ, которым сисэеме сообщается о  со-
бЫтии, проиСшедшем во внешнем мире. События, тсебующие немедленной обработ-ки, могут происходитЬ и в программе. Их называют исключительными  ситуация-
ми. ПримеРы таких ситуаций: деление на ноль, ошибка обмена  с  устройством,
окончание файла ввода и т.п.
      В ДССП исключительные ситуации фиксируются с помощью командных преры-
ваний. Командное прерывание представляет собой поименованную операцию вызо-
ва процедуры реагирования и объявляется следующим образом:
             TRAP <имя вызова> <конечная реакция>

 Например:
 TRAP S X
 TRAP S1 ."Ситуация S1."
      В первом случае конечной реакцией на прерывание S служит процедура X,
во втором при возникновении прерывания S1 на терминал будет выдано  сообще-
ние: Ситуация S1.
      Программа, при выполнении которой возможно возникновение  прерывания,
может установить на него свою реакцию с помощью команды перехвата.  В  ДССП
предусмотрено два типа перехватов: ON и EON. Команды перехвата могут  упот-
ребляться только внутри процедур и имеют формат:
                ON  <имя прерывания> <реакция>
                EON <имя прерывания> <реакция>

 Например:
 : A ... ON S ."Прерывание S" ... ;
 : A1 ... EON S1 ABC ... ;

      ON и EON устанавливают различные типы реакций. Если новая реакция за-
дана командой ON, то при возникновении прерывания выполняется процедура-ре-
акция, после чего прерванная программа продолжает работу. Если реакция  за-
дана командой EON, то вначале стек операндов принимает глубину, которую  он
имел в момент выполнения EON, затем выполняется реакция, а по окончании  ее
сразу завершается выполнение процедуры, в которой была употреблена  команда
EON.
      Рассмотрим примеры. Процедура M вводит с клавиатуры терминала  литеры
и проверяет, цифра ли это. Если введенная литера не является  цифрой,  воз-
буждается прерывание ND.
 TRAP ND ." Не цифра."
      : M [] RP M1 [] ;
      : M1 [] TRB [B] C #0 < C2 #9 > &0 [B,1/0] IF+ ND [B] TOB [] ;
      Конечная реакция на прерывание ND - сообщение: Не цифра.
      Если M вызывается из процедуры P1, в которой установлена своя реакция
на прерывание ND
      : P1 [] ON ND PR1 M [] ;
      : PR1 [B] CR ."Ошибка." D #0 [#0] ;
      то при вводе нецифровой литеры прерывание ND будет  обработано  прог-
раммой реакции PR1 типа ON, что вызовет выдачу с  новой  строки  сообщения:
Ошибка. Введенная литера будет заменена литерой 0, после чего  M  продолжит
работу.
      Если M вызывается из процедуры P2
      : P2 [] EON ND PR2 M [] ;
      : PR2 [] CR ."Ошибка. Конец ввода." [] ;
      то при вводе нецифровой литеры прерывание ND будет  обработано  прог-
раммой реакции PR2 типа EON, что вызовет выдачу с новой  строки  сообщения:
Ошибка. Конец ввода., после чего P2 завершит  работу.  Стек  операндов  при
этом будет пуст.
      При необходимости в программе-реакции можно снова возбудить  прерыва-
ние, распространив его таким образом на программы более высокого уровня.  В
этом случае обрабатывать прерывание будет либо программа, указанная  в  ко-
манде перехевата в объемлющей процедуре, либо  конечная  реакция.  Например

если модифицировать PR2 следующим образом:
      : PR2 [] CR ."Ошибка. Конец ввода." ND [] ?
      то сообщение, выданное на терминал, будет таким: Ошибка. Конец ввода.
Не цифра.

                    Встроенный ассемблер.

      Встроенный ассемблер позволяет определять в ДССП новые процедуры, на-
писанные на машинном языке. Запись процедуры имеет вид:
                    :A  <имя>  <команды>  ;
      Здесь :A - определяющее слово, <имя> - название определяемой процеду-
ры, <команды> - последовательность команд ассемблера, а ; -  признак  конца
опседеления. Имя новой процедуры помещается в словарь системы и использует-
ся для обращения к ней. Команды заносятся в облаСть тел процедур.
      Синтаксис команд встроенного ассемблера немного отличается от  ориги-
нала. Формат команды:
                <метка>  <операция>  <операнды>
      <метка> пРедставляет собой  произвольную  проследовательность  литер,
завершающуюся двоеточием, метки распознаются по первым семи литерам;  <опе-
рация> - мнемокод команды или псевдокоманды; <опесанды> -  ноль,  один  или
два операнда, разделенных пробелами. Пробелами разделяются все поля  коман-
ды. КооменТарии - произвольный текст ъ квадратных скобках  - могут распола-
гаться в любом месте команды и также отделяются от соседних слов пробелами.
      Пример процедуры на языке встроенного ассемблера микропроцессора
К580:
                 :A  EXAM  POP  H
                           MOV  C  M
                           INX  H
                           MOV  B  M   [BC=M(HL)]
                           PUSH B  ;
      Во встроенных ассемблерах возможно употребление всех команд микропро-
цессоров К580 и Z80 [5]. Для К580  сохранены  все  обозначения  команд.  Во
встроенном ассемблере для микропроцессора Z80 изменены  обозначения  команд
условного перехода, вызова подпрограмм и возврата таким образоо, что  усло-
вия включены в мнемокод операции: вместо  CALL  NZ,10  пишется  CALLNZ  10,
вместо RET PE пишется RETPE и т.д. для всех условий.
      В языке ассемблера микропроцессора К580  отсутствует  понятие  метода
адресации. Каждой командой однозначно определяется формат и  размещение  ее
операндов. Так, например, комаода
                         ADD r
      предписывает прибавить к аккумулятору содержимое одного  из  8-битных
регистров процессора (пРи r=A, B, C, D, E, H, L) или содержимое ячейки  па-
мяти, адрес которой находится в регистровой паре HL (при r=M).
      Возможны следующие операнды:
 A, B, C, D, E, H, L - 8-битные регистры;
         M           - байт памяти, адресуемый регистровой
                       парой HL;
 B, D, H, SP, PSW    - 16-битные регистры и регистровые пары;
      <число>        - число в текущей системе счисления;
      #<литера>      - код литеры, например #A, #Z;
       <имя>         - метка или имя процедуры ДССП,
                       интерпретируемые как адрес;
      ' <имя>        - адрес элемента данных ДССП, например
                       ' X. Если X - переменная, то это
                       абсолютный адрес переменной, если
                       массив, то абсолютный адрес нулевого
                       элемента массива.
      При программировании процедур  на  встроенном  ассемблере  необходимо
учитывать, что некоторые регистры процессора в ДССП заняты. На микропроцес-
соре К580:
 A, H, L - рабочие;
 BC      - указатель старшего байта последней занятой позиции
           стека операндов. Стек растет в сторону увеличения
           адресов;
 DE      - указатель интерпретатора;
 SP      - указатель стека возвратов;
      При необходимости использовать занятые системой регистры нужно  обес-
печить сохранение их значений и восстановление в конце ассемблерной  проце-
дуры.
      Пример программы на языке встроенного ассемблера для  микропроцессора
К580. Процедура SRCH подсчитывает число вхождений в строку STR  буквы  U  и
записывает это число в переменную N:
     100  BYTE  VCTR  STR  [текстовая строка]
                 VAR  N    [количество вхождений]
 [SRCH - подсчет числа вхождений U]
         :A  SRCH  PUSH  B
                   LXI  H  '  STR  [HL:='STR(0)]
                   MVI  A  #U      [A:=#U]
                   MVI  B  0       [B:=0]
                   MVI  C  101     [C:=101]
              L1:  CMP  M
                   JNZ  L2
                   INR  B
              L2:  INX  H
                   DCR  C
                   JP   L1
                   LXI  H  '  N
                   MOV  M  B       [N:=кол-во]
                   INX  H
                   MVI  M  0
                   POP  B      ;
      В языке ассемблера Z80 имеются понятия косвенной и индексной  адреса-
ции. Например, команда
                          LD  HL,10
 загружает число 10 на регистровую пару HL, а команда
                          LD  (HL),10
 загружает число 10 по адресу, содержащемуся в HL. Команда
                          LD  IX,50
 загружает число 50 в регистр IX, а команда
                          LD  (IX+5),50
 загружает число 50 в ячейку памяти с адресом, равным увеличенному на 5 со-
держимому регистра IX.
      Во встроенном ассемблере изменен способ записи операндов с  косвенной
и индексной адресацией:
     ассемблер-оригинал             встроенный ассемблер
    (BC) (DE) (HL) (SP)             @BC  @DE  @HL  @SP
    (IX) (IY) (C)                   @IX  @IY  @C
    (IX+d)       (IY+d)             @I

                   Редактор-форматор текстов ДССП.

     Редактор-форматор текстов ДССП (далее РФТ) по сравнению с базовым сис-
темным редактором обладает увеличенным буфером и включает ряд  дополнитель-
ных возможностей. РФТ может использоваться  для  подготовки  текстов  книг,
статей и т.п. Он расчитан на работу с дисплеем 15ИЭ-00-013 и принтером типа
DZM-180 (D-100) с кодировкой КОИ-8.
     Основная часть изложенного ниже справедлива и для базового, и для рас-
ширного редактора. Функции, имеющиеся только в расширенном редакторе, отме-
чены знаком "*".

                         Режимы работы РФТ.

     _асть функций редактора текстов выполняется в режиме  ДССП-процессора,
остальные - в режиме редактирования. В режиме ДССП-процессора осуществляет-
ся загрузка текста с диска и вывод на диск, печать, получение различной ин-
формации. В режиме экранного редактирования производится набор,  редактиро-
вание и форматирование текста.
     После загрузки ДССП и РФТ с  дискеты  на  экран  выдается  приглашение
ДССП-процессора "* ". Команды можно набирать по одной или несколько в стро-
ке, разделяя их пробелами и завершая ввод нажатием клавиши "ВК". При наборе
входной строки возможно употребление клавиш: "<-" для возврата (отмены вве-
денных букв), "->" для повтора входной строки или ее части, "<-Э"  и  "Э->"
для удаления лишних или вставки пропущенных букв. Для исполнения  ДССП-про-
цессор воспринимает входную строку от начала до того места, где нажата кла-
виша "ВК".

                   Организация информации на дискете.

     Вся дискета делится на две части: системную и информационную.  Систем-
ная часть занимает сектора (по 128 байтов) с 1 по 254, информационная  -  с
255 по 1920 (на дискетах 5''). В системной  части  расположен  загрузчик  и
ДССП вместе с РФТ. Информационная часть разбита на 44 файла  фиксированного
объема (по 4801 байтов), пронумерованных от 1 до 44. Файлы 1 и 44 использу-
ются для хранения каталога диска (1-й основной, 44-й копия). Каталог -  это
обычный текстовый файл, в котором пользователь отмечает, чем занят тот  или
иной файл или группа файлов.

             Команды, выполняемые в режиме ДССП-процессора.

DX0, DX1    Переключиться на работу с указанным  дисководом.  По  умолчанию
MX0, MX1    система настроена на устройство,  с  которого  была  загружена.

KE         Удалить весь текст из буфера РФТ. Если текст изменялся, на экран
           будет выдано сообщение:  "Текст  не  сохранен!  Удалить?(Y)  -".
           Нажатие любой клавиши, кроме  "Y",  приведет  к  отмене  команды
           удаления.

IE i       Добавить в конец буфера РФТ текст из i-го файла текущего  диска.
            Перед  началом  чтения  РФТ  выдает   сообщение   "строк   n1",
где n1 - количество уже имеющихся строк в буфере, а после  ввода  текста  в
той же строке появляется второе число n2 - сколько стало строк. В целом  по
окончании операции сообщение выглядит  следующим   образом: "строк n1  n2".
Если свободного места в буфере не хватает для ввода текста  из  файла,  РФТ
выдает сообщение: "Текст не войдет! Вводить? (Y) -". Нажатие любой клавиши,
кроме "Y", приведет к отмене команды ввода. Нажатие "Y" вызовет   ввод  той
части текста из файла, которая умещается в буфере редактора.

OE i      Вывести содержимое буфера РФТ на диск, начиная с i-го файла.  Ес-
          ли номер файла не совпадает с тем, откуда считывался текст,   РФТ
выдает название устройства и номер файла вывода, сопровождая  их  запросом,
например: "MX0   5 подтвердите (Y)". Нажатие любой клавиши, кроме "Y", при-
ведет к отмене команды вывода. После вывода текст сохраняется в буфере РФТ.
При выводе текста необходимо убедиться в том, что он не выходит за  пределы
отведенных ему файлов на дискете. Информация о размере текста  выдается  по
команде "H" в режиме ДССП-процессора или по запросу "АР2",H в режиме редак-
тирования.

NE        Выдать на зкран текущее устройство и номер файла.

O         Вывести содержимое буфера РФТ в текущий файл текущего устройства.
          На экран выдается название устройства и номер файла вывода.

FR        Выдать на экран объем свободного места в буфере РФТ  (в  байтах).

CAT       Выдать на экран каталог диска. Если весь каталог не умещается  на
          экране, то выдача останавливается. Нажатие клавиши "ВК"  отменяет
          дальнейшую выдачу, любой другой клавиши - продолжает.

TYPE i    Выдать на экран содержимое файла i без ввода его в буфер РФТ.
          Управление выдачей - как в команде "CAT".

LPE       Распечатать содержимое буфера РФТ на принтере. Если  эта  команда
         дается впервые после загрузки системы, то  РФТ  запрашивает  дату.
Можно задать дату в произвольной форме или любой текст (не более 10 литер),
завершив ввод нажатием "ВК". Набранный текст будет напечатан в верхнем пра-
вом углу распечатки. Команда LPE никак не отслеживает листование на принте-
ре, оставляя это драйверу.

LPFF      Перевести бумагу на принтере на начало следующей страницы.

E         Вход в режим экранного редактирования.

H         Помощь. На экран выдается  информация  о  командах  РФТ,  текущем
          режиме, объеме текста в буфере РФТ.


               Работа в режиме экранного редактирования.

     Набор и изменение текста проходит в режиме  экранного  редактирования,
для входа в который служит команда E (Edit).
     По этой команде очищается экран и в его верхней части выдается  инфор-
мационная строка "строк n". При нажатии  в  этой  строке  клавиши  "стрелка
вниз" на экран выдается начало находящегося в буфере РФТ текста, при  нажа-
тии клавиши "стрелка вверх" - конец текста.
     По находящемуся на экране тексту можно двигаться в  любом  из  четырех
направлений  и редактировать текст. При выходе курсора  за  границы  текста
(вверх или вниз) на экран выдается очередная часть текста (сверху или  сни-
зу). Текст представляется как бы напечатанным на цилиндре, при этом на  эк-
ране видна какая-то его часть, которую можно редактировать.
     Все происходящие на экране изменения отображаются в  буфере  РФТ.  Для
редактирования текста используются как литерные (например: A, B, 1, #), так
и управляющие клавиши (например: "ВК", "ПС", "ЭЭ->", "СУ"A, "СУ"Е), а также
последовательное нажатие клавиш (например: "АР2",C). Обозначение "СУ"A  оз-
начает, что требуется одновременное нажатие клавиши "СУ" и литерной клавиши
A. Управляющие команды не записываются в буфер РФТ, а вызывают редактирова-
ние текста. Например, команда "СУ"A вызывает присоединение следующей строки
к текущей.
     Для работы с группой строк (перестановка, копирование,  удаление,  пе-
чать) используются маркеры. Маркерами помечается первая и последняя  строка
группы.
     При наборе текста в расширенном редакторе необходимо учитывать следую-
щее:
     1. Если набираемое слово не умещается в строку, то РФТ подает звуковой
сигнал и переносит все слово на следующую строку.
     2. Для удобства набора текстов знаки препинания , . - : ; перенесены в
нижний регистр. Имеется возможность отменить это свойство командой "АР2",W.
     3. После ввода точки первая отличная от пробела русская  литера  будет
заглавной независимо от регистра, в котором она введена.

                Действия клавиш в режиме редактирования.

  "СУ"E    Выйти из режима экранного редактирования.

 "АР2",H   Помощь. На экран выдается информация о командах РФТ, текущем ре-
           жиме, объеме текста в буфере РФТ.

   /\      Сдвинуть курсор вверх. При нажатии этой клавиши курсор  попадает
   ЭЭ      на предыдущую строку текста.  Если  курсор  находился  в  первой
           строке текста то операция не выполняется. Если предыдущей строки
текста на экране нет, то весь текст экрана сдвигается на одну строку вниз и
в первой строке экрана печатается предыдущая строка.

   ЭЭ      Сдвинуть курсор вниз. При нажатии этой клавиши  курсор  попадает
   \/      на следующую строку текста. Если курсор находился в нижней инфор
мационной строке, то операция не выполняется. Если последующей строки  тек-
ста на экране нет, то на экран выводится  следующая строка текста,  сдвигая
остальные строки вверх.

   =>      Сдвинуть курсор вправо. В результате этой операции курсор  пере-
           ходит в  следующую  позицию  строки.  Если  курсор  находится  в
последней позиции строки, то операция не выполняется.

   <=      Сдвинуть курсор влево. В результате этой операции курсор перехо-
           дит в предыдущую позицию строки. Если курсор  находится  в  пер-
           вой позиции строки, то операция не выполняется.

  "ЗБ"     Сдвинуть курсор влево. В результате этой операции курсор перехо-
           дит в предыдущую позицию строки. Если курсор  находится  в  пер-
           вой позиции строки, то операция не выполняется.

  "ГТ"     Сдвинуть курсор вправо на ближайшую позицию, номер которой  кра-
           тен 8. Если курсор находится в последней позиции строки, то опе-
           рация не выполняется.

 "ТАБ"     Поставить курсор на конец текста текущей строки.

  ЪЪЪ      Стереть экран, вывести информационную строку "строк п", то  есть
  Э\       перейти в состояние, аналогичное входу в режим экранного  редак-
    \      тирования.

  "СУ"Q    Переместить курсор на начало слова.

  "СУ"^    Переместить курсор на конец слова.

 "СУ""ЗБ"  Ввести литеру .

  ====     Вставить пустую строку перед текущей. Курсор в результате выпол-
   !!      нения операции не меняет своего положения, то  есть  оказывается
   \/      в образованной строке.

   /\      Удалить текущую строку. Курсор в результате выполнения  операции
   ЭЭ      не меняет своего положения, то есть оказывается в строке, следу-
  ====     за удаленной.

  <=Э      Удалить символ из текущей позиции. По этой операции все символы,
           начиная с текущего и до конца строки, сдвигаются на  одну  пози-
           цию влево. Курсор своего положения не меняет.

  Э=>      Вставить пробел в текущей позиции. По этой операции все символы,
           начиная с текущего и до конца строки, сдвигаются на  одну  пози-
цию вправо. Если в строке уже имеется 75 символов, то операция не  выполня-
ется. Курсор своего положения не меняет.

  "ВК"     Перейти на начало следующей строки. При нажатии этой  клавиши  в
           последней строке текста добавляется новая строка.

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

 "СУ"A     Присоединить следующую строку к текущей позиции. Обратная по от-
           ношению к "ПС" операция. К текущей  позиции  строки  присоединя-
ется ледующая строка. При этом, если она не умещается в данную  строку,  ее
конец остается в старой строке. Курсор своего положения не меняет.

  "СБР"    Перейти к следующему экрану текста. При нажатии  данной  клавиши
           на экран выводятся следующие 24 строки.  Курсор  устанавливается
в первую строку и первую позицию экрана.

"АР2","СБР" Перейти к предыдущему экрану текста. На экран выводятся  преды-
            дущие 24 строки. Курсор устанавливается в первую строку и  пер-
           вую позицию экрана.

"АР2",O    Перейти в режим замены.

"АР2",I    Перейти в режим вставки.

"АР2",W    Поменять регистр (верхний - нижний) для литер   ; - : . ,

  "СТС"    Удалить конец строки. При нажатии этой клавиши из строки  удаля-
           ются символы, начиная с текущего до конца строки. Курсор  своего
           положения не меняет.

    ЭЭ     Отметить маркером текущую строку. Маркерами  можно  отметить  не
    \/     более двух строк. Визуально маркер отображается на экране в виде
     *     пары символов "**" в 78-йи 79-й позициях строки. Курсор устанав-
           ливается на начало текущей строки.

"АР2",ЭЭ   Удалить все имеющиеся маркеры. Курсор устанавливается на  начало
      \/   текущей строки.
       *

 "АР2",C   Скопировать перед текущей строкой отмеченный  маркерами  участок
           текста. По этой операции копируются строки с  первой  отмеченной
маркерами по последнюю включительно. Если отмечена одна строка, то  копиру-
ется только она. Копирование не производится, если текущая строка принадле-
жит к группе копируемых строк (за исключением первой строки группы), или  в
буфере нет места для копируемых строк. В последнем случае  выводится  диаг-
ностика "нет места". Снятие диагностики производится нажатием любой  клави-
ши. Маркеры после нажатия клавиш "АР2",C уничтожаются. Курсор  перемещается
на начало скопированной группы строк.

 "АР2",G   Поставить перед текущей  строкой  отмеченный  маркерами  участок
           текста. При этой операции переставляются строки с  первой  отме-
ченной маркерами по последнюю включительно. Если отмечена одна  строка,  то
переставляется одна строка.  Перестановка  не  производится,  если  текущая
строка принадлежит к группе переставляемых строк (кроме 1-ой  строки  груп-
пы). Маркеры после нажатия клавиш "АР2",G уничтожаются. Курсор перемещается
на начало переставленной группы строк.

 "АР2",D   Удалить участок  текста,  отмеченный  маркерами.  Маркеры  после
           нажатия клавиши "АР2",D уничтожаются. Курсор перемещается на на-
           чало первой следующей за удаленными строками строки.

 "АР2",E   Напечатать на принтере отмеченный маркерами текст. Маркеры после
           нажатия клавиш "АР2",E уничтожаются. Курсор положения не меняет.

"АР2","ПРС"  Задать образец для контекстного поиска.  По  этой  команде  на
             экране стирается  текущая  строка  и  появляется  приглашение:
"текст-". В ответ нужно ввести последовательность литер, завершив ее  нажа-
тием клавиши "ВК". Поиск ведется с начала текущей строки до конца текста  в
буфере. При нахождении образца курсор устанавливается на найденный  участок
текста, а если поиск закончился неудачей выводится  информационная  строка.

  "ПРС"    Продолжить  поиск  образца,  заданного  в  команде  контекстного
           поиска. Поиск возобновляется со следующей за курсором позиции.

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

   ЭЭ===   Выполнить текстовый макрос. По нажатию этой клавиши  РФТ  выпол-
   \/      няет запомненные действия.

"АР2",A    Задать длину строки для форматирования. На экран выдается   сооб
           щение: "длина строки (ВК  -  nn)  -",  где  nn  -  текущая длина
строки. В ответ нужно либо ввести новую длину строки (не  более  75),  либо
нажать "ВК", тогда останется текущая длина.

"АР2",M    Расположить текст данной строки по центру. Центрирование   произ
           водится в пределах длины строки,  указанной  для  форматирования
(по умолчанию 63). Не рекомендуется центрировать строки большей длины.

"АР2","ТАБ"  Форматировать отмеченный маркерами фрагмент текста.  Форматиро
             вание заключается в сборке строк длиной не более указанной ко-
мандой "АР2",A (по умолчанию 63) с переносом слов по правилам русского язы-
ка. Выравнивание по правому краю не производится. Красная строка сохраняет-
ся. Маркеры удаляются. Курсор устанавливается в следующей  за  отформатиро-
ванным участком строке.

                              Сокращения.

     РФТ позволяет вводить сокращения для часто используемых слов и  слово-
сочетаний. Под сокращением понимается  выбранная  пользователем  последова-
тельность литер, обозначающая слово или словосочетание. После того,  как  в
тексте набрано сокращение, нужно нажать клавишу "АР1". Если такого сокраще-
ния нет, то курсор устанавливается на начало сокращения, если есть РФТ рас-
шифрует его. Возможны следующие способы задания сокращений:
     1. Дописывание. Расшифровка задается так:

        :  <СОКР>  "<продолжение>"  ;

   где <СОКР> - название сокращения, являющееся началом сокращаемого слова.
Например:

        :  П  "роцессор"  ;
        :  М  "икрокомпьютерная система"  ;

     2. Замена. Расшифровка задается так:

        :  <СОКР>  "Ъ<текст расшифровки>"  ;

где <текст расшифровки> - полная расшифровка сокращения, включая  начальные
буквы. В  этом  случае  слово-сокращение  в  тексте  полностью  заменяется.
     Названия сокращений при определении должны быть заданы  большими  рус-
скими буквами, а при наборе текста - как большими, так  и  малыми  буквами.
     _асто расшифровка должна появляться в  различных  падежах.  Для  этого
вместо окончания слов в задании расшифровки ставится  символ  *,  например:

        :  ВУ  "Ъвнешн*устройств"  ;

     При употреблении сокращения ВУ при наборе текста вначале будет  выдано
        внешн
и курсор останется в конце этого слова. Нужно дописать необходимое  оконча-
ние, затем нажать пробел - будет выдано следующее слово.
     Всю совокупность сокращений нужно набрать в следующем формате:
        PROGRAM $SLOV
        :  П  "роцессор"  ;
        :  М  "икрокомпьютерная система"  ;
        :  ВУ  "Ъвнешн*устройств"  ;
            .  .  .

после чего сохранить этот текст на диске и выполнить команду PF, по которой
сокращения будут занесены в словарь. Проверив работу сокращений, можно сох-
ранить РФТ со словарем сокращений на диске командой

        SAVE  H  <вк>

                   Разметка и печать текста

     Для печати текста с разбивкой на страницы и нумерацией страниц необхо-
димо сначала его разметить. Разметка определяет для каждого файла  с  какой
страницы и с какой строки на странице должен печататься данный файл. В  ко-
мандном режиме есть директивы RAS - начальной разметки и NRAS - переразмет-
ки. По команде RAS система запрашивает список файлов, подлежащих  разметке.
Номера файлов можно давать по одному или группой,  разделяя  их  пробелами.
После того, как задан самый последний файл, для окончания  разметки  вместо
номера очередного файла нужно набрать слово, не являющееся  числом  (напри-
мер, TT). Информация о разметке записывается на  дискете  вместе  с  каждым
файлом. Текст в файле не изменяетяся. Если после разметки какие-либо  файлы
модифицировались, то можно переразметить текст начиная с первого изменивше-
гося файла командой NRAS.
     Количество строк на странице задается в переменной DLPG (по  умолчанию
30).
     В тексте можно указать места, где должна начинаться новая страица, что
будет учтено при разметке и печати. Для этого в начале первой строки  новой
страницы нужно вставить символ . На печать он не выводится. Вставить  сим-
вол  можно клавишами "СУ""ЗБ".
     Фрагмент текста, который должен находиться на  одной  странице,  нужно
помечать парой символов  в начале первой  и  в  начале  последней  строки
фрагмента. Символы  на печать не выводятся.
     _тобы ввести в буфер РФТ текст с диска вместе с информацией о  размет-
ке, вместо команды IE n нужно воспользоваться командой IEE n. Если в  буфер
РФТ введен текст с разметкой, то нажатие клавиш "СУ"N  вызывает  печать  за
правым краем текста номера страницы и номера строки.
     Печать размеченного текста осуществляется в командном режиме из буфера
РФТ или с диска. Для печати из буфера РФТ текст нужно ввести командой  IEE,
а затем напечатать командой LPF.
     Команда PRF печатает с диска группу размеченных файлов. Возможна  рас-
печатка на терминале и на принтере. В случае терминала на экран выдается 23
строки, после чего выдача останавливается. Для продолжения нужно нажать лю-
бую клавишу. В случае выдачи на принтер запрашивается  интервал  печати  (1
или  2)  и  необходимость  остановки  перед  печатью  очередной   страницы.
