Красноярский Государственный Университет
Фонд алгоритмов и программ
Регистрационный номер 009
01.03.84.
А.А. Бабий
Макроязык АС
Версия 2.0
Руководство пользователя
Макроязык АС предназначен для повышения производительности работы программиста, использующего язык ассемблера.
Макроязык АС -это комплекс макрокоманд, построенных единой идеологии. Программа на языке АС - это программа на языке ассемблера с использование средств АС. Пользователь может написать как программу, состоящую почти из одних макрокоманд АС, так и программу, почти не включающую средств АС, т.е. обычную программу на языке ассемблера.
Примечание. Поскольку макроязык состоит из обычных макрокоманд, синтаксис записи макрокоманд (правила переноса и т.д.) в данном руководстве не описывается: см. руководство по языку ассемблера.
АС состоит из четырёх групп макрокоманд:
INITM - войти в модуль
RETRN - вернуться из модуля
BCALL - вызвать модуль (подключенный реактором)
BLOAD -загрузить, вызвать и уничтожить модуль
Макрокоманды из этой группы обеспечивают: автоматическое базирование модуля; автоматическую организацию цепочки областей сохранения; автоматический приём, передачу и возврат параметров; автоматическое открытие и закрытие файла печати.
BEGIN - начать блок
ENDD - завершить блок
DO -конструкция DO ... WHILE ...
WHILE -конструкция WHILE ... DO
IF - конструкция IF ... THEN ... ELSE ...
CASE -консрукция CASE ... OF ...
Макрокоманды этой группы обеспечивают: описание логики в терминах структурного программирования; организацию внутренних подпрограмм.
@SBPVV - создать поле ввода-вывода с именем PVV
@SBPCR - создать DCB для печати
@SBCPK - создать DCB для ввода с карт
PRNT - напечатать строку
VKRT - считать карту
CONS - обеспечить диалог с оператором
BREAD - ввод блока из файла типа PO или PS
BWRITE - вывод блока из файла типа PO или PS
BCLOSE - закрытие PS-файла (CLOSE+FREEPOOL)
Макрокоманды из этой группы расширяют возможности системных макрокоманд ввода-вывода или упрощают работу с ними. Так, PRNT позволяет более удобно организовывать печать, CONS существенно расширяет возможности WTO или WTOR, BREAD - это просто READ и CHECK.
MDAS - выполнение арифметических операций
BMVC - пересылка без указания длины
BSNAP - отладочные действия
Макрокоманда MDAS упрощает выполнение арифметических операций. Макрокоманд BSNAP расширяет возможности системной макрокоманды SNAP и, кроме того, позволяет автоматически выдать отладочный дамп в момент прерывания по программной ошибке.
Ниже приводится пример программы на языке АС.
Модуль PROBEL убирает лишние пробелы между словами. В результирующем поле слова должны разделяться ровно одним пробелом, перед первым словом пробела быть не должно.
Вызов: BCALL PROBEL, (POLE, LEN, LEN1)
Код возврата в регистре 15:
Результирующее поле распечатывается и выводится на консоль (в случае, если нет ошибок). Вывод производится по реальной длине (LEN1).
PROBEL START
INITM (12), POLE, LEN - забазировались 12 регистром, приняли входные
параметры
MVC KOD, =F'0' код возврата - 0
- проверка длины
L 3, LEN
IF (C, 3, = F'2'), L, THEN, (MVC, KOD, = F '4'), RETURN
IF (C, 3, = F'80'), L, THEN, (MVC, KOD, = F '4'), RETURN
-сжатие (длина поля в регистре 3:
MVI SYM, C' ' поле SYM, содержащее предыдущий символ
LA 4, POLE адрес исходного поля
LA 5, POLE адрес результирующего поля
-цикл по счётчику в регистре 3:
DO PR1, (MVC, SYM, 0(4)), (АН,4,=H'1'), WHILE, (BCT,3)
PR1 IF (CLI, 0(4), 0' '),NE, THEN, (MVC,0 (1,5), 0 (4)), (AH,4,=H'1), ELSE, PR2
PR2 IF (CLI, SYM, C' '), NE, THEN, (MVC, 0(1,5), 0(4)), (AH, 4,=H'1')
-вычисляем реальную длину
DO (S, 5,=A(POLE)), (ST, 5, LEN1)
-если длина нуль, то ошибка
IF (LTR, 5, 5), E, THEN, (MVC, KOD,=F'8'), RETURN
-печать по длине в 5 регистре:
OPEN (@SBPR, OUTPUT)
PRNT ((5), POLE)
-вывод на консоль по длине в 5 регистре
CONS POLE,,(5)
-возврат, формируется код возврата, закрывается
печать
RETURN EQU *
BCLOSE @SBPR
L 15, KOD
RETRN (80, POLE),, LEN1, RC=(15)
*
POLE DS CL80
KOD DS F
LEN DS F
LEN1 DS F
SYM DS C
@SBPVV
@SBPCR
END
Поскольку макроязык состоит из обычных макрокоманд ассемблера ОС ЕС, то на символические имена, или метки, распространяются обычные ограничения: длина не более 8 символов, начинается с латинской буквы, и т.д.
Однако, в макроязыке АС символическое имя часто имеет несколько иной смысл (не метка перехода, а имя вызываемого блока. Подробнее об этом будет сказан в 2.2)и кроме того, на имя накладываются некоторые дополнительные ограничения, а именно:
Понятие блока является одним из основополагающих в макроязыке АС. Блок используется для логического вложения операторов.
На языке ассемблера логическое вложение операторов можно осуществить двумя способами: либо непосредственно поместить внутренний оператор во внешний, либо во внешнем организовать вызов подпрограммы , реализующей внутренний оператор. Проиллюстрируем это на примере программы поиска в таблице:
-непосредственное (физическое) вложение:
LA 3, ATABL адрес таблицы
L 4, KOLEL количество элементов
A1 здесь располагается тело цикла (вкладываемый
оператор)
LA 3'1 (3) переход к следующему элементу
BCT 4, A1
-вложение вызовом:
LA 3, ATABL
L 4, KOLEL
A1 BAL 14, COMP
LA 3, 1(3)
BCT 4, A1
.......................
COMP подпрограмма, содержащая вкладываемый
оператор
BR 14
В языке АС для вложения операторов обычно используется способ с вызовом. Точнее, если оператор или группа операторов оформляется блоком, то обратиться к нему можно, только вызвав его; при этом практически неважно, в каком месте программы он находится. Если же оператор не оформлен блоком, или реализуется обычными командами ассемблера, он вкладывается непосредственно.
Рассмотрим макрорасширение блока с именем, например COMP:
B END COMP
COMP тело блока (команды ассемблера и операторы
АС)
BR14
ENDCOMP EQU *
Из примера видно, что вызвать блок COMP можно только командой BAL 14, COMP. Заметим, и это очень важно, что при непосредственном вложении блок не выполнится: сработает команда
B ENDCOMP
Отметим и то, что передача управления не по BAL (например, командой ВС) приведёт к ошибке: содержимое 14 регистра не определено; блок выполнится, но возврат не сработает.
Программист может организовывать блок двумя способами:
-большинство макрокоманд АС автоматически генерируют команды, необходимые для оформления блоком, если программист укажет для макрокоманды символическое имя, например:
IF (CLI, A, C'K'), E, THEN, RETURN
Не оформляется блоком, а
SR IF (CLI, A, C' K'), E, THEN, RETURN
Оформляется.
Программист может отказаться от организации блока, оставив, однако, имя:
SR IF (CLI, A, C' K'), E, THEN, RETURN, BLOK=N
В этом случае имя SR - обычное символическое имя ассемблера, на которое можно передать управление.
-группу команд и операторов АС можно оформить блоком при помощи макрокоманд BEGIN и ENDD
Например:
COMP BEGIN
ТЕЛО БЛОКА
ENDD COMP
Напишем теперь программу поиска в таблице на языке АС:
LA 3, ATABL
L 4, KOLEL
DO COMP, (LA, 3, 1(3)), WHILE, (BCT,4)
COMP BEGIN
ТЕЛО ЦИКЛА
ENDD COMP
Макрокоманда DO порождает цикл по счётчику в регистре 4. В этом цикле делается вызов блока COMP. После окончания цикла управление, как обычно в ассемблере, передаётся следующей команде, но это - макрокоманда BEGIN, т.е.
B ENDCOMP
, и блок COMР обходится, т.к. ENDCOMP - метка последней команды в ENDD.
Таким образом, логику программы на языке АС можно записать как совокупность блоков, вложенных друг в друга. Поскольку блок, оформленный с помощью BAGIN и ENDD, может содержать параметры, он может использоваться как внутренняя процедура (по терминологии ПЛ/1).
Приложение. Список операторов языка АС, автоматически оформляемых блоком:
BCALL, BLOAD, DO, WHILE, IF, CASE, PRNT, VKRT, CONS, BREAD, WRITE, BCLOSE, MDAS, BSNAP.
Макрокоманды описания логики обычно содержат в себе не только вызовы блоков, но и непосредственно команды ассемблера. Эти команды записываются специальным образом: вся команда заключается в скобки;
Например, команда SR 3,4 запишется так: (SR,3,4).
Приведём ещё несколько примеров:
(SVC, 34) (LA, 3, 8 (6,4)) (STM, 0, 15, SREG)
Отметим, что в таком виде нельзя записывать макрокоманды и псевдокоманды языка ассемблера, например, нельзя написать (GETMAIN, R, LV=800).
Примечание. Команды записываются в АС-виде только, если они состоят в макрокомандах описания логики, во всех остальных случаях они записываются в обычном виде.
Записывая логику при помощи макрокоманд АС, мы в макрокоманде можем указать одну или несколько команд, записанных в АС-виде, вызовы блоков, комментарии и средства выхода. Все эти элементы отделяются друг от друга и от ключевых слов запятыми.
Запись команд в АС-виде рассмотрена в 2.3. вызов блока осуществляется упоминанием его имени. Комментарии записываются в виде */текст/* (кроме АС-комментария внутри макрокоманды, может использоваться и обычный ассемблеровский комментарий). Средства выхода предназначены для преждевременного выхода из блока и имеют вид EXITИМЯ, где ИМЯ - имя блока. Если в группе присутствует средство выхода, блок с именем "ИМЯ" завершается, т.е. срабатывает возврат BR14. Если же макрокоманда, на которую ссылается средство выхода, имеет имя, но не оформлена блоком (BLOK=N), то управление передаётся следующей команде.
Пример групп в логических макрокомандах:
A DO DL, WHILE, (CR, 3, 5), NE
B DO A, WHILE, (CR, 8, 8), L, BLOK=N
SR 3,7
BL IF (CLI, A, C' * '), E, THEN, (LA, 3, 8(6,4)), *'ПЕРЕАДРЕСОВАЛИСЬ'*,
*
BLK, EXITA, ELSE, EXTIB
В IF имеется три группы: группа условия (между IF и E), группа THEN (от THEN до ELSE), и группа ELSE (от ELSE до конца). Заметим разницу в использовании EXIT: EXITA вызывает BR 14 в блоке A, т.е. возврат в блок, вызвавший А (т.е. В). EXIT фактически передаёт управление команде, стоящей после блока В , т.е. SR 3,7.
В макрокомандах IF, DO, WHILE используется код условия. Он образуется просто из расширенной мнемоники команды ВС, а именно:
После команд сравнения:
Е-равно, L-меньше, Н-больше, NL - не меньше, NH - не больше
После арифметических команд:
Z - нуль, М - меньше нуя, Р - больше нуля, О - переполнение, NZ - не нуль, NM - не минус, NP - не плюс, NO - не переполнение.
После команды ТМ:
О - все 1, М - есть 1 и 0, Z - все 0, NO - не все 1, NM - все 1 или 0, NZ - не все 0.
Обычно в этих макрокомандах перед условием стоит команда сравнения. Но это не обязательно, например, можно написать
IF E, THEN , BLK1
Тогда будет использоваться код условия, поученный к моменту выполнения команды IF.
Макрокоманда автоматизирует действия, необходимые при входе в модуль.
Обычно программист, пишущий на языке ассемблера, должен знать правила организации цепочки областей сохранения, базирование и т.д. INITM освобождает программиста от этой рутины: достаточно написать
INITM (R1,...,RN)
Следом за START или CSECT (R1,...,RN - список базовых регистров), и все действия, необходимые для входа в модуль, будут выполнены: отведётся область сохранения программы, сохраняться общие регистры, организуется цепочка областей сохранения, объявятся и загрузятся базовые регистры.
Количество базовых регистров определяется просто: по одному на 4096 байт программы.
Примеры.
A START
INITM (12)
Программа занимает не более 4096 байт
MOD CSECT
INITM (9, 12)
Программа занимает не более 8192 байт. Базовые регистры 9 и 12.
Данная возможность используется только в многосекционных программах. Имя области сохранения, автоматически генерируемое INITM - @@@@SAVE. Если же в многосекционной программе несколько раз указать INITM, имя @@@@SAVE окажется определённым многократно. Чтобы избежать этого, в INITM имеется операнд SAVE, с помощью которого можно изменить имя области сохранения.
Всё вышесказанное относится также и к имени точки входа (по умолчанию @@@@IDNT). Соответствующий операнд - IDNT.
Пример.
A START
INITM (12)
..........
B CSECT
INITM (11), SAVE=SAVEB, IDNT=IDNTB
Внимание: если вход в секцию оформлен INITM с операндом SAVE, нужно внутри секции указывать параметр SAVE во всех макрокомандах BCALL, BLOAD, RETRN, так как они ссылаются на область сохранения.
Данная возможность используется только, если программист хочет воспользоваться возможностями системной макрокоманды SAVE. INITM по умолчанию генерирует сохранение регистров так:
STM 14, 12, 12 (13)
Чтобы воспользоваться системной макрокомандой SAVE, нужно указать в INITM операнд REG=NO. Порядок команд будет такой:
START
SAVE (с нужными операндами)
INITM ..., REG=NO
Данная возможность используется только тогда, когда модуль вызван другим модулем и нужно принять и разместить входные параметры. По стандартам IBM вызванному модулю передаётся список адресов параметров в регистре 1. Как правило, для удобства работы значения или адреса параметров переписываются во внутренние поля модуля, так как работать постоянно со списком параметров неудобно и неэффективно.
INITM избавляет программиста от рутинной работы по приёму параметров: можно указать в INITM список полей и/или регистров, в которые нужно разместить параметры или их адреса. При этом, если параметр принимать не нужно, его можно опустить.
Соответствующий операнд INITM - номер регистра, заключённый в скобки; например, (5). Параметр, передаваемый из вызывающей программы, должен быть выровнен по границе полного слова, иначе возникнет прерывание по спецификации.
Пример.
INITM (12), (5), (10)
Модуль имеет два входных параметра: первый загружается в регистр 5, второй - в регистр 10 (12 регистр - базовый).
Соответствующий операнд INITM - *(R), где R - номер регистра, в который загружается адрес параметра.
Пример.
INITM (12), (5), *(10)
Первый параметр загружается в регистр 5, адрес второго параметра загружается в регистр 10.
Соответствующий операнд INITM - это имя поля, в которое передаётся параметр, например, АВС, или POLE4, или PRA+8.
Длина пересылаемых данных определяется, исходя из модификатора длины в команде DS или DC. Так, если поле PAR задано как
PAR DS CL 80
и указано
INITM (12), PAR
то перешлётся 80 байт.
Если же
PAR DS 8CL10
то перешлётся только 10 байт.
Соответствующий операнд - имя поля, перед которым стоит звёздочка. Например:
INITM (12), *APAR
Поле не обязательно должно быть выровнено по границе слова.
INITM (3, 4, 5), A, *B, (6),,*(8)
Для базирования отводятся регистры 3, 4, 5. Первый параметр передаётся в поле А, адрес второго - в поле В, третий загружается в регистр 6, четвёртый пропускается, адрес шестого параметра загружается в регистр 8.
Макрокоманда INITM имеет следующий вид:
INITM (база)[,список параметров][,REG=NO][, SAVE=имя][,IDNT=имя]
Макрокоманда автоматизирует действия, необходимые для возврата управления вызывающему модулю.
Если вход в модуль был оформлен с INITM, то, чтобы выйти из него, достаточно написать
RETRN
Восстановится содержимое регистров 14-12 и возвратится управление вызывающему модулю.
Для успешного возврата RETRN должна знать адрес области сохранения. По умолчанию считается, что имя области сохранения @@@@SAVE, т.е. определённое по умолчанию в INITM. Если же в INITM имя другое, нужно указать операнд SAVE=ИМЯ с тем же именем, что и в INITM.
Возможно, пользователь захочет воспользоваться возможностями системной макрокоманды RETURN (например, восстановлением части регистров). В то же время ему нужны возможности RETRN по возврату параметров.
Указав RET=NO в макрокоманде RETRN, пользователь возвратит значения параметров в вызывающий модуль, но собственно возврат управления и восстановление регистров не произойдёт.
Подход, принятый в языках программирования высокого уровня (принимаются только адреса параметров), не всегда удобен при программировании на языке ассемблера. Поэтому INITM может принимать не только адреса параметров, но и их значения, однако, при возврате управления нужно тогда вернуть и значения параметров, макрокоманда RETRN представдяет возможности по возврату параметров, аналогичные возможностям INITM по примеру параметров.
Возвращаемые параметры перечисляются в поле операндов макрокоманды RETRN. Операнд может указать только возвращаемый параметр (и тогда длина поля считается равной четырём), либо имеет вид (длина, параметр). Если параметр возвращать не нужно, то соответствующий операнд опускается (например, RETRN ,,,А возвращает только 4 параметр)
Длина возвращаемого параметра не может быть больше 255.
Соответствующий операнд - просто литерал, например, =F'4'. Если литерал имеет длину, не равную 4 байтам, указывается длина, например:
RETRN=F'5', (20,=CL20'ЭТО СИМВОЛЬНЫЙ ЛИТЕРАЛ')
Соответствующий операнд - имя поля, например, АВС. Если возвращаемый параметр имеет длину, не равную 4, нужно указать длину, адрес поля может быть задан в виде D(B), например 154(9), т.е. возвращаемый параметр находится по адресу в регистре 9 плюс 154 байта.
Соответствующий операнд - номер регистра, заключённый в скобки, например, (6). Соответствующий параметр в вызываемой программе должен быть выровнен по границе слова.
Соответствующий операнд имеет вид *ИМЯ, где ИМЯ - имя поля, содержащего адрес пересылаемых данных. Поле, содержащее адрес, должно быть выровнено по границе слова, операнд может иметь вид *D(B). Если длина возвращаемых данных не равна четырём, следует указать длину.
Соответствующий операнд - *(R), где R - номер регистра, содержащего адрес пересылаемых данных.
RETRN ,,(2), (40,*(3)), BC, *KOL+48, (200, 3(8))
Значения первого и второго параметров не возвращаются, третий параметр - содержимое регистра 2 (4 байта), четвёртый - 40 байт по адресу, содержавшемуся в регистре 3, пятый - 4 байта KOL+48 и седьмой - 200 байт по адресу, содержащемуся в регистре 8, плюс 3.
Программист может указать код возврата, который RETRN поместит в регистр 15. Соответствующий операнд может быть записан как RC=(15), и тогда будет использовано текущее значение регистра 15, или же RC=N, где N - целое число, например RC=4.
Макрокоманда RETRN имеет следующий вид:
[имя] RETRN [параметры][RET=NO][SAVE=ИМЯ][RC=код]
Макрокоманда BCALL автоматизирует действия, необходимые при вызове модуля по стандартам IBM.
Вызов модуля без параметров:
BCALL имя
Например, BCALL SUBPROG
Не всегда вызывающему модулю доступно имя точки входа в вызываемый модуль, часто известен только его адрес (например, если модуль был загружен командой LOAD или адрес модуля извлечён из таблицы адресов модулей). Макрокоманда BCALL позволяет задать адрес модуля либо в регистре, либо в поле. Примеры:
BCALL (8) адрес модуля находится в регистре 8
BCALL *APROG адрес модуля находится в поле APROG
BCALL *4(11) адрес модуля находится в поле по адресу в 11 регистре, плюс 4.
BCALL может вызывать не только внешние модули, но и блоки. Это необходимо, если блоку нужно передавать параметры. Перед именем блока указывается символ =, например:
BCALL = BLK1, (PAR1, PAR2)
Если вызываемый модуль или блок имеет параметры, список параметров заключается в скобки; в списке параметры перечисляются через запятую. Список параметров отделяется от имени модуля (или адреса, или имени блока) запятой.
Соответствующий операнд - имя поля, например:
BCALL PROG, (POLE)
Соответствующий операнд имеет вид (R), где R - номер регистра, например:
BCALL PROG, ((4))
Внутри макрокоманды заводится полное слово, в которое выгружается имя регистра. Если параметр возвращаемый, то после BCALL в этом регистре будет возвращённое значение параметра, иначе же содержимое регистра не изменится.
Соответствующий операнд - *(R), где R - номер регистра, содержащего адрес параметра, например:
BCALL PROG,(*(5))
Соответствующий операнд - *ИМЯ, где ИМЯ - имя поля, содержащего адрес параметра, например:
BCALL PROG, (*APARAM)
3.3.3.5. Параметр - литерал
Соотетствующий операнд - литерал, например:
BCALL PROG, (=F'128',=CL64'MESSAGE',=H'0')
Соответствующий операнд имеет вид #D(X,B), где D - смещение, X - индексный регистр, В - базовый регистр, например:
BCALL PROG, (#128(3,6))
По умолчанию BCALL считает, что имя области сохранения @@@@SAVE. Если это не так, нужно указать параметр SAVE=ИМЯ.
Регистр 15 при выходе из BCALL содержит код возврата, сформированный вызываемым модулем.
Если модули ведут печать на один SYSPRINT, то нужно каждый раз перед вызовом модуля закрывать файл @SBPR (если используется PRNT), а после возврата открывать его заново. При этом нужно сохранять значение кода возврата и т.д. Всё упрощается, если указать операнд PR=Y. Тогда @SBPR автоматически закроется перед вызовом модуля и автоматически откроется после вызова, регистр 15 по-прежнему содержит код возврата.
Макрокоманда BCALL имеет вид:
[ИМЯ] BCALL ПРОГ [, (параметры)][,SAVE=ИМЯ][,PR=Y][,BLOK=N]
Имя - не более 4 символов. ПРОГ - указание имени или адреса программы, параметры - список параметров, который может отсутствовать, SAVE указывает имя области сохранения, PR=Y позволяет автоматически открыть-закрыть @SBPR. BLOK=N указывается, если BCALL должен иметь имя, но не должен оформляться блоком.
Макрокоманда BLOAD загружает модуль, вызывает его, а затем уничтожает. Фактически BLOAD эквивалентна последовательности макрокоманд: LOAD, BCALL, DELETE. По синтаксису и возможностям BLOAD полностью аналогична BCALL, за двумя исключениями:
Чтобы организовать вход в блок, достаточно написать имя BEGIN
Длина имени - не более 4 символов, организуется обход блока, сохранения регистра 14 (область сохранения регистра 14 отводится автоматически внутри BEGIN).
В макрокоманде BEGIN можно записать группу, например:
BLK BEGIN (ST, 0, SIM,*' ЗАПОМНИЛИ 0',BLK2
Если в блок передаются параметры, то они указываются после служебного слова PARAM**. Служебное слово PARAM** указывается либо первым операндом BEGIN, либо после группы, если она есть. Возможности и синтаксис приёма параметров такие же, как и у макрокоманды INITM (см. 3.1.4.). Примеры:
MIT BEGIN (ST, 0, SIM), PARAM**, *(3), ABC, (8)
BLP1 BEGIN PARAM**, POLE+4, *ABC, (11)
Иногда требуется, чтобы блок не портил содержимое общих регистров, тогда в BEGIN и ENDD соответствующего блока указывается параметр SAVE=YES, и регистры 1-15 сохраняются в области сохранения, автоматически создающейся в BEGIN.
Примеры:
A BEGIN SAVE=YES
B BEGIN (MVC, D, K), SAVE=YES
Макрокоманда BEGIN имеет вид:
ИМЯ BEGIN [ГРУППА][PARAM**, ПАРАМЕТРЫ][SAVE=YES]
Чтобы закончить блок, достаточно написать
ENDD ИМЯ
Где ИМЯ - имя блока, например:
ENDD BLO
Возвращаемые параметры, если они есть, записываются после имени закрываемого блока. Возможности и синтаксис возврата параметров полностью совпадают с возможностями и синтаксисом макрокоманды RETRN (см. 3.2.4.). Пример:
ENDD BLP, (8),,AB
Если в макрокоманде BEGIN соответствующего блока было указано SAVE=YES, обязательно нужно указать SAVE=YES и в ENDD. Нельзя указывать SAVE=YES в ENDD, если оно не было указано в BEGIN.
Макрокоманда ENDD имеет вид:
ENDD ИМЯ [,ПАРАМЕТРЫ][SAVE=YES]
Как правило, DO используется для создания конструкции DO ... WHILE ..., т.е. цикла, в котором сначала выполняется тело цикла, а затем - проверка. Если же WHILE не указано, то генерируется не цикл, а линейная последовательность (СР, с оператором DO в PL/1)
Макрокоманду DO можно использовать для генерации группы. Например, DO (L, 4, ABUF),(ST, 8, ABB),PLT,*' вызов блока PLT'
Загрузив в некоторый регистр число повторения цикла, мы можем организовать цикл по счётчику, например:
LA 5, 100
DO (L, 4, ABUF), PLT, WHILE,(BST, 5)
Здесь WHILE - служебное слово, означающее, что нужно делать. Цикл, А (ВСТ, 5) указывает, что цикл нужно организовывать по счётчику, находящемуся в регистре 5.
Между WHILE и (ВСТ, R) может быть любая группа.
Условие формируется группой, стоящей после WHILE. Используется код условия, полученный последней командой группы (или последней командой блока в группе).
Об условиях см. 2.5.
Пример:
DO (L, 4, ABUF), PLT, WHILE, (CLI, POLE, C'*'), NE
Тело цикла (группа между DO и WHILE) будет выполняться, пока условие истинно.
Бесконечный цикл организуется, если после WHILE не указаны ни группа, ни условие. Выход из такого цикла может быть организован либо EXIT - средствами, либо по прерыванию (например, по концу файла). Пример:
DO PLT, (L, 3, 0, (3)), WHILE
Если макрокоманда DO имеет имя, она автоматически оформляется блоком, если оформление блоком нежелательно, следует указать BLOK=N.
Блок не нужен в двух случаях:
Тот факт, что как до, так и после WHILE может стоять группа, открывает широкие возможности, так как и условие, и тело цикла могут быть произвольной сложности, это позволяет использовать нисходящий подход при программировании.
Макрокоманда DО имеет вид:
[ИМЯ] DO группа [,WHILE[группа], условие][BLOK=N]
Макрокоманда WHILE создаёт конструкцию WHILE... DO..., то есть конструкцию цикла, в которой проверка условия выполняется перед телом цикла, в которой проверка условия выполняется перед телом цикла, макрокоманда имеет вид:
[ИМЯ] WHILE [ГРУППА,] УСЛОВИЕ, DO, ГРУППА[,BLOK=N]
Об условии см. 2.5. Тело цикла выполняется, если условие истинно. Пример:
WHILE (CLI, POLE, C'*'), NE, DO, (L, 4, ABUF), PLT
Этот оператор отличается от оператора из 4.3.3 : там, если в POLE *, тело цикла всё же проработает один раз, а здесь - нет.
Макрокоманда IF порождает конструкцию двоичного выбора:
[ИМЯ] IF [группа,], условие, THEN, группа [ELSE, группа][,BLOK=N]
Об условии см. 2.5. Если условие истинно, срабатывает группа, стоящая после THEN, иначе - группа, стоящая после ELSE.
Макрокоманда CASE порождает конструкцию множественного выбора:
[ИМЯ] CASE [ГРУППА,], (СРАВНЕНИЕ),(КЛЮЧ1,..., КЛЮЧN[,#ELSE]),OF,ГРУППА1,#..., ГРУППАN[,#,ГРУППА ELSE][,BLOK=N]
Сравнение состоит из команды сравнения и первого сравниваемого, например (CLI,A)
Ключи - это набор вторых сравниваемых, например:
(C'1', C'2', C'3') или (B, C, D, E)
Группа с номером К срабатывает, если сравнимое совпало с ключом номер К.
Если сравниваемое не совпало ни с одним ключом, можно выполнить группу #ELSE.
CASE (CLC, A),(=C'11',=C'12',=C'13',#ELSE), OF, (MVC, DK, K),#,PPP,(LA, 5, 8), #, G,@,ERRR
Если А=С'11' то выполняется MVC DK, K
Если А=С'12' то выполнятся блок PPP и LA 5, 8
Если А=С'13' то выполняется блок G
Если А не совпало ни с одним ключом, выполняется блок ERRR.
Макрокоманды ввода-вывода на языке АС служат для того, чтобы в сжатой форме описывать наиболее часто употребляемые операции ввода-вывода.
Так, @SBCPK и @SBCPR просто порождают DCB для ввода с перфокарт и печати с наиболее часто употребляемыми параметрами;
BREAD совмещает зануление DECB, READ, CHECK; PRNT и CONS расширяют возможности системных макрокоманд PUT и WTOR.
Макрокоманда создаёт поле ввода-вывода длиной 12 байт, с именем PVV. Это поле используется по умолчанию командами VKRT, PRNT, CONS. Кроме поля PVV, создаются рабочие поля, необходимые для PRNT.
Поскольку @SBPVV не создаёт выполняемых команд, её необходимо ставить среди описаний (т.е. DS, DC, и т.д.)
Макрокоманда имеет вид:
@SBPVV
Макрокоманда создаёт DCB для печати. Имя DCB @SBPR, приняты значения DSORG=PS, MACRF=PM, BLKSIZE=128. Имя DO по умолчанию SYSPRINT, однако его можно менять параметром DD.
Макрокоманд имеет вид:
SBCPK [DD=ИМЯDD]
Макрокоманда создаёт DCB для ввода с карт с именем @SBPK. DSORG=PS, MACRF=GM, BLKSIZE=80. DDNAME и EODAD можно менять параметрами DD и END соответственно:
@SBCPK [END=метка выхода по концу файла][DD=ИМЯ DD]
Макрокоманда закрывает наборы данных QSAM. Есть два отличия от обычной команды CLOSE:
Макрокоманда имеет вид:
[ИМЯ] BCLOSE DCB1[,DCB2...][BLOK=N]
Где DCB - это имя DCB или (R), где R - номер регистра
При работе с BSAM, чтобы выполнить чтение или запись, нужно записать три команды: нуление DECB, READ или WRITE и CHECK. Если CHECK выполняется сразу за чтением или записью, удобнее объединить эти три команды. Это и делают макрокоманды BREAD и BWRITE. Более того, они автоматически порождают уникальные имена DECB.
[ИМЯ] BREAD ИМЯФАЙЛА, АДРЕСЗАПИСИ, ДЛИНА [,BLOK=N]
[ИМЯ] BWRITE ИМЯ ФАЙЛА, АДРЕСЗАПИСИ, ДЛИНА[,BLOK=N]
Правила записи имени файла, адреса запись и длины такие же, как у WRITE и READ.
Макрокоманда обеспечивает ввод карты.
[ИМЯ] VKRT [DCB=ИМЯ][P=ИМЯ][BLOK=N]
По умолчанию имя DCB - @SBPK, т.е. порождённое макрокомандой @SBCPK. Однако, если имя другое или доступен только адрес DCB, пользователь должен поместить адрес DCB в поле и имя этого поля указать в параметре DCB.
По умолчанию карта вводится в поле PVV, определяемое макрокомандой. При желании программист может задать адрес поля в символическом виде или в виде (R), где R - номер регистра, содержащего адрес поля. Для этого используется параметр Р.
Программист сам открывает и закрывает файл ввода.
Макрокоманда автоматизирует процесс формирования строки для печати. Если используется PRNT, обязательно должно быть определено поле PVV посредством макрокоманды @SBPVV.
Написав
PRNT
Мы просто распечатываем поле PVV.
PVV зачищается пробелами по команде
PRNT SKIP=0
PRNT позволяет собрать выводную строку из нескольких элементов. Элементы перечисляются через запятую и могут быть:
-символическим именем
Если длина подстроки, определяемой элементом, равна модификатору длины в DС или DS, указывается просто имя, например, ABC или RP*10, иначе пользователь сам может указать длину: (длина, имя). Например, (13, АВС).
-литералом
Литерал должен быть символьным. Способ указания длины - такой же, как и для символического имени, но, если в литерале есть модификатор кратности, длина должна указываться обязательно. Примеры:
=C'ЭТО ЛИТЕРАЛ', (15,=15C'*')
-указанием адреса: (длина, адрес), например: (28,3(4)). Длина в этом случае указывается обязательно.
Пример печати списка:
PRNT=C'X=',(3,POLE),(8,0(6)),(30,=30C'*'),POLE+9
Параметр SKIP позволяет распечатать строку требуемое количество раз. Например, PRNT SKIP=12 пропускает 12 пустых строк, а PRNT (128,=128C'*'),SKIP=3
Печатает три строки звёздочек.
Иногда требуется печатать строку не с первой позиции. Это достигается использованием параметра S. Например, чтобы напечатать 'пример' с тридцатой позиции, нужно указать:
PRNT=C'ПРИМЕР',S=30
По умолчанию PRNT считает, что работает с DCB, имеющим имя @SBPR, однако, если имя другое или доступен только адрес DCB, используется параметр DCB точно так же, как в VKRT.
Следует помнить, что PRNT со списком или SKIP, не равным нулю, перед заполнением строки зачищает PVV пробелами. Поэтому, во-первых, в PVV не следует хранить информацию, а во-вторых, зачищать PVV перед печатью не нужно.
Программист сам открывает и закрывает файл печати,
( OPEN(@SBPR, OUTPUT) BCLOSE @SBPR ).
[ИМЯ] PRNT [СПИСОК][SKIP=KRATH,][S=СМЕЩЕНИЕ][DCB=ИМЯ][BLOK=N]
Макрокоманда CONS обеспечивает дополнительные возможности по связи с оператором.
CONS может работать как WTO, но, кроме литерала, можно передать поле:
CONS=C'СООБЩЕНИЕ'
CONS POLEA
В предыдущем примере длина передаваемого поля определялась модификатором длины в DS или DС. Можно, однако, указать требуемую длину либо непосредственно в CONS, либо загрузив её в регистр:
CONS POLE,,3 выводит 3 байта из POLE
CONS POLE,,(3) выводит поле по длине в R3
Если длина находится в регистре, обязательно нужно указать операнд LMAX=N, где N - максимальная длина сообщения.
Вообще, следует помнить, что длина сообщения должна быть не более 255 символов.
Примечание. Сообщение можно передавать не только литералом или символическим именем, но и задавая адрес, например:
CONS 0(6),,(7)
В данном примере адрес сообщения в 6 регистре, длина - в 7.
Если требуется ответ оператора, то вторым операндом указывается длина ответа, она может быть числом или находиться в регистре:
CONS=C'ОТВЕТЬ',8 ответ - 8 байт
LA 8, 12
CONS=C'ОТВЕТЬ',(8) длина ответа в регистре 8
По умолчанию ответ помещается в поле PVV. Если программиста это не устраивает, он может сменить имя, используя параметр Р:
CONS=C'ОТВЕТЬ',(9),P=ANSW
Макрокоманда CONS имеет вид
[ИМЯ] CONS СООБЩЕНИЕ [ДЛИНА ОТВЕТА][Р=ИМЯ][MAX=ДЛИНА][BLOK=N]
Пересылая в поле символьный литерал, программист вынужден подсчитать количество символов в нём, чтобы указать длину пересылаемых данных. BMVC избавляет его от этого:
BMVC PVV,=C'СООБЩЕНИЕ'
Эквивалентно
MVC PVV(9),=C'СООБЩЕНИЕ'
Для того, чтобы сложить два числа, находящиеся в памяти, требуется как минимум три команды: ЗАГРУЗИТЬ, СЛОЖИТЬ, ЗАПИСАТЬ. Если же слагаемое находится в однобайтовом поле, нужно ещё предварительно очистить регистр. Если подобных операций в программе много, удобнее воспользоваться макрокомандой MDAS:
[ИМЯ] VDAS КОД, АД1, АД2[T1=ТИП1][Т2=ТИП2][BLOK=N]
КОД - код операции: А - сложение, S - вычитание, М - умножение, D - деление.
АД1 - адрес первого операнда, например KOL 0(3,8)
АД2 - адрес второго операнда или литерал
Т1 - тип первого операнда. Если не указан, первый операнд занимает слово с фиксированной точкой. Т1=Н - операнд занимает полуслово с фиксированной точкой, Т1=С - операнд занимает 1 байт.
Т2 - тип второго операнда. Значения - аналогично Т1.
Результат операции заносится в первый операнд.
Примеры:
MDAS A,KOLKS,=F'1' прибавили к слову KOLKS единицу
MDAS M, KOLKS,=F'6',T1=H умножили полуслово KOLKS на 6
MDAS D, KK, 0(3), T2=C разделили слово КК на содержимое байта, адрес которого в R3
Примечание. При делении частное заносится в первый операнд, остаток - в регистр 0.
Макрокоманда предназначена для облегчения отладки программ, написанных на языке ассемблера
Макрокоманда BSNAP DCB=YES порождает DCB с именем @@@@SNAP для макрокоманд SNAP и BSNAP и автоматически открывает его. Порождаются рабочие поля для BSNAP.
Макрокоманда BSNAP CLOSE=YES закрывает DCB @@@@SNAP, в секции или группе секций, ассемблируемых вместе, можно только один раз указать BSNAP c DCB=YES. При желании после закрытия @@@@SNAP пользователь может открыть его повторно:
OPEN (@@@@SNAP, OUTPUT)
По умолчанию имя DD в @@@@SNAP - SNAPDD, однако его можно изменить операндом DD, например:
BSNAP DCB=YES, DD=OTL
Работая в ОС MVT, программист не получает индикативного дампа. Единственное, что он имеет - код прерывания, выдача же дампа по SYSABEND или SYSUDUMP приводит к перерасходу бумаги. BSNAP позволяет автоматически получить информацию о координатах команды, вызвавшей командное прерывание. Для этого, кроме DCB=YES, следует указать INTR=YES, выдастся дамп области из 24 байтов.
Программа прекращает работу с кодом завершения USER=4095, код прерывания можно узнать из PSW.
Макрокоманда BSNAP CLOSE=YES закрывает DCB и восстанавливает предыдущий адрес программы обработки ошибок.
В процессе отладки иногда требуется выдать на печать определённые области оперативной памяти. Обычно для этого используется макрокоманда SNAP. Однако она в ряде случаев неудобна для использования. BSNAP использует команду SNAP, но имеет более гибкий механизм задания границ распечатываемой области.
Чтобы выдать дамп, обязательно нужно указать операнд А1 в макрокоманде BSNAP, который указывает на начало области. Адрес начала области может быть задан:
Например, А1=*ADDR или A1=*2(7)
Верхняя граница области может быть задана двумя способами:
Если, кроме области, нужно выдать ещё и содержимое регистров, следует указать операнд REGS=YES в макрокоманде BSNAP. Номер дампа указывается операндом ID (например, ID=5)
По умолчанию регистры не печатаются, ID=1.
Макрокоманда BSNAP имеет возможность не генерироваться, даже если она указана. Это бывает удобно, если нужно исключить режим отладки, не убирая отладочных команд. Для этого нужно первыми двумя картами программы поставить
GBLS &TEST
&TEST SETC 'HET'
[ИМЯ] BSNAP [DCB=YES][INTR=YES][DD=ИМЯ DD][CLOSE=YES][A1=АДРЕС][A2=АДРЕС][LN=ДЛИНА][REGS=YES][ID=НОМЕР][BLOK=N]
© Алексей Бабий 1980