Команды перекодировки

При программировании достаточно часто встает задача перевода строки символов из одного кода в другой. При организации систем телеобработки, например, приходится пользоваться терминалами типа телетайпа, которые передают и принимают информацию, имеющую вид строк символов в коде ASCII. Однако вся работа с символьными данными в машинах фирмы IBM производится на основе кода EBCDIC. Таким образом, очевидно, что при организации связи с удаленными терминалами необходим перевод информации из кодов EBCDIC в коды ASCII и обратно. (Операционная система сделает эту работу за нас, если мы используем телекоммуникационные методы доступа, однако посмотрим, как же конкретно это делается.) Аналогичные проблемы возникают при преобразованиях форм представления чисел, кодировании, а также при подготовке двоичной информации к выводу на перфокарты. Другими часто встречающимися задачами являются задача реорганизации данных и задача поиска во всем массиве данных символов, имеющих специальное значение. Для облегчения решения этих задач служат команды TR и TRT.

Команда TR

Первым операндом команды TR является адрес области памяти, содержащей информацию, которую нужно перекодировать байт за байтом в соответствии со словарем (иногда называемым байт-функцией), адрес начала которого задается с помощью второго операнда. Содержимое поля длины указывает длину перекодируемой строки.

TR D1(L1,B1),D2(B2)

TRanslate

Перекодировать(D1 +(B2))L1, используя словарь по адресу D2 + (B2)

При выполнении команды предполагается, что словарь состоит из 256 байтов, т. е. содержит по одному байту на каждую возможную 8-битовую комбинацию. Содержимое каждого байта исходной области, области аргументов, используется в качестве индекса для поиска в словаре. Найденные таким способом байты словаря помещаются в область аргументов на место соответствующих им байтов. Например, если первые 4 байта словаря выглядят так:

TRTAB:

Байт 0: С6

Байт 1: С7

Байт 2: С8

Байт 3: С9 (еще 252 байта)

а область аргументов содержит

03010200

то в результате перекодировки получится

С9С7С8С6

Рассмотрим процесс выполнения команды более детально. Первый байт поля аргументов содержит 03. Это значение используется в качестве индекса для поиска в словаре. Содержимым байта TRTAB+ +03 является С9. Этот байт и записывается на место первого байта поля аргументов. При этом получается

С9010200

Второй байт-аргумент содержит 01. 01 замещается в поле аргументов содержимым байта 01 области TRTAB. Этот процесс продолжается (слева направо) до тех пор, пока все байты исходной области не будут перекодированы.

Возможно, рассматривая информацию дампа, вы задумывались о тем, как же происходит замена шестнадцатеричных чисел соответствующими кодами EBCDIC. Рассмотрим задачу преобразования шестнадцатеричного числа, имеющего вид полного слова, в тот вид, который оно бы имело, будучи распечатанным в качестве части дампа. На рис. 20.3 изображен фрагмент программы, предназначенный для выполнения поставленной задачи в предположении, что исходное число находится по адресу NUM.

Сначала число необходимо распаковать. Однако будьте внимательны здесь, поскольку команда UNPK меняет местами половины последнего байта, меняя тем самым преобразуемое число. Возникшее затруднение будет преодолено, если мы распакуем один дополнительный байт. Содержимое этого байта, в нашем примере девятого байта области HEX, никакой роли не играет.

Предположим, что сначала мы имели

NUM: 6АС3408050

После распаковки получим

Статья 429 - Картинка 1

Рис. 20.3. Преобразование содержимого полного слова NUM в коды EBCDIC для составляющих его шестнадцатеричных цифр.

Заметим, что цифры от 0 до 9 уже имеют вид кодов EBCDIC, пригодных для печати. Однако цифры отА до F должны быть переведены в коды EBCDIC из той формы, которую они имеют, FA—FF. Это можно сделать с помощью следующих перекодировок:

FA?С1

FB?С2

FC?СЗ

FD?С4

FE?С5

FF? С6

F0?F9 не должны при этом меняться. Существует много различных способов выполнения этого преобразования, однако простейший и наиболее эффективный, безусловно, заключается в использовании команды TR. Поскольку нас интересуют только преобразования строк FA—FF, то достаточно заполнить лишь последние 16 байтов словаря. Устанавливая адрес начала словаря на X'FO' меньше, чем адрес начала фактически отведенной под словарь области, мы представляем дело так, как будто бы действительно имеем полный 256-байтовый словарь. Словарь можно было также задать с помощью команды

TRTAB DC С'0123456789ABCDEF'

Содержимое каждого байта-аргумента используется в качестве индекса для поиска в словаре. Фактически содержимое поля аргументов используется для выбора определенных байтов из словаря и записи их в исходную область на места, определяемые байтами-аргументами. Этот факт можно успешно использовать при решении задач реорганизации данных. Для этого в поле аргументов необходимо записать значения индексов, соответствующих определенным байтам из словаря. Однако в качестве словаря здесь можно использовать область, в которой хранится информация, подлежащая реорганизации.

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

Статья 429 - Картинка 2

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

297-46-3792 10365

Очевидно, для этого необходимо сделать следующие преобразования:

Байт

Порядковый номер в выводимой строке

5

6

7

Дефис

8

9

Дефис

A

B

С

D

Пробел

Пробел

0

1

2

3

4

0

1

2

3

4

5

6

7

8

9

A

B

C

D

E

F

10

11

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

TABENTRY DS CL14

BLANK DC С' '

HYPHEN DC С'-'

Мы записываем номер служащего и его номер карточки системы социального обеспечения в том порядке, в котором они находятся в таблице, по адресу TABENTRY, и используем полученную 16-байтовую строку в качестве словаря. В качестве аргументов в данном случае выступает просто последовательность индексов, определяющая порядок выборки отдельных байтов из словаря и размещения их в поле аргументов. Поле аргументов может быть определено, например, так:

ARG DC X'0506070F08090FOAOBOCODOEOE0001020304'

Если мы хотим поместить уже отсортированную строку по адресу OUTLINE, то это можно сделать с помощью пары команд:

MVCOUTLINE(18),ARG

TR OUTLINE(18),TABENTRY

Попробуйте сами вручную выполнить команду TR, чтобы посмотреть, как она работает. Заметим, что при перекодировке, которую мы производили, содержимое поля аргументов уничтожается. Именно поэтому мы использовали команду MVC для пересылки содержимого поля аргументов в область OUTLINE.

В качестве последнего примера мы рассмотрим простейший способ использования команды TR для шифрования. Одним из способов (но, наверняка, не лучшим) кодирования сообщений является использование кода Цезаря. Для получения кода Цезаря некоторой строки к каждому символу в ней «добавляется» некоторый ключевой символ. Пусть, например, в качестве ключевого выбран символ С. Строка

MEET ME AT THE CASBAH. I HAVE SMUGGLED SOME TOOTHPASTE.

в коде Цезаря будет выглядеть так:

OGGV OG CV VJG ECUDCJ.КJCXG UOWIINGF UQOG VQQVJRCUVG.

Поняли ли вы, что произошло? Каждой букве алфавита ставится в соответствие определенное число, А=0, В=1, С=2, ..., Z=25. Кодирование производится с помощью сложения чисел, соответствующих каждой букве кодируемого сообщения с числом, соответствующим ключевому символу по модулю 26. М+С= 12+2= 14=0, Е+С=4+2= =6=G и т. д. Декодирование может быть значительно затруднено, например, с помощью устранения знаков пунктуации и разбиения сообщения на пятибуквенные «слова». После выполнения описанных действий наше сообщение примет вид

Статья 429 - Картинка 3

Рис. 20.4. Преобразование 30-бантового сообщения в код Цезаря и помещение результата по адресу OUTPUT.

На рис. 20.4 приведен фрагмент программы, использующей команду TR для описанной кодировки сообщений. Строка, которая должна быть закодирована, с устраненными знаками пунктуации и без пробелов находится в памяти по адресу MESS. Первая команда TR заменяет каждый символ на соответствующее ему числовое значение. При этом считается, что число, соответствующее ключевому символу, находится в регистре 3. С помощью второй команды TR полученная строка чисел снова приводится к виду строки символов. Содержимое регистра 3 используется для сдвига адреса начала поля, содержимое которого используется в качестве словаря. С помощью последней команды TR полученное сообщение разбивается на пятибуквенные слова.

Отметим использование псевдокоманды ORG для построения словаря LETDIG, служащего для перевода строки символов в соответствующую ей строку числовых значений. ORG устанавливает значение счетчика размещения равным значению, заданному в поле операндов. Предложение

ORGLETDIG +X'D1'

служит для помещения в счетчик размещения значения, на Dli6 превышающего значение этого счетчика для имени LETDIG. Константа следующего DC предложения записывается в память по адресу LETDIG+D116.

Перекодировать и проверить

Команда TRT используется для поиска в произвольной строке байтов с заранее заданным содержимым. Подобные задачи часто возникают при обработке символьной информации. Нам может понадобиться, например, отыскать десятичную точку в числе, представленном в форме с плавающей точкой, найти пробелы в некотором тексте или произвести проверку числовой информации на наличие незаконных символов.

Порядок работы с TRT очень похож на порядок работы с TR.

TRTD1(L1,B1),D2(B2)

TranslateandTest

Поиск в (D1+(B1))L1 символов, определяемых с помощью (D2 + (B2))256

Снова мы имеем словарь и область аргументов. Однако в отличие от TR команда TRT не меняет содержимого памяти. Вместо этого среди содержимого области аргументов производится поиск символов, определяемых заданной в словаре информацией.

Конкретно, при выполнении команды TRT содержимое поля аргументов просматривается слева направо, и при этом по индексу, определяемому содержимым каждого байта аргумента, отыскивается соответствующий ему байт в словаре. Как только находится байт-аргумент, содержимое соответствующего байта словаря для которого не равно нулю, процесс прекращается, адрес найденного байта помещается в регистр 1, его содержимое — в регистр 2 (разряды 24—31) и устанавливается новое значение признака результата:

Признакрезультата

Описание ситуации

0

Содержимое всех байтов словаря, соответствующих байтам аргумента, равно 0.

1

Был найден байт в области аргументов (не последний),

для которого содержимое соответствующего ему байта словаря не равно 0.

2

Последний байт области аргументов был первым, которому соответствовал байт словаря с ненулевым содержимым.

Таким образом, перед использованием TRT строится 256-байтовый словарь. Все байты словаря содержат 0, кроме тех, которые соответствуют интересующим нас индексам. Пусть, например, нам известно, что в некотором 10-байтовом поле могут быть записаны коды чисел от 0 до 9, а также коды пробелов. Мы хотим использовать команду TRT для проверки наличия в этой области каких-либо других символов. Таким образом, байты 40„ и F0 — F9 словаря должны содержать 0, остальные же должны быть ненулевыми. Такой словарь может быть построен, например, так:

DIGTEST DC 256X'FF'

ORG DIGTEST+ Х'40*

DC X'00'

ORG DIGTEST+X`F0`

DC 10X`00`

ORG

С помощью предложения ORG с пробелами в поле операндов значение счетчика результата устанавливается равным наибольшему его предшествующему значению, в данном случае DIGTEST+256. Предположим, что первоначально мы имеем

(1) = 00000000 (2) = FFFFFFFF

и что исследуемое число находится по адресу 2000, в поле NUM. В зависимости от содержимого поля NUM выполнение команды

TRT NUM(10), DIGTEST

даст следующие результаты:

Статья 429 - Картинка 4