Генерация таблиц для поиска

Последнее обновление: 03.07.2023

Одной и распространенных ситуаций применения макроконструкций представляет генерация таблиц для поиска. Например, нам нужен набор чисел типа byte от 1 до 100. В общем случае мы могли бы написать так:

.data
    nums byte 1, 2, 3, 4, 5, 6, ....., 99, 100

Писать вручную - не очень удобно, тем более всегда можно допустить ошибку на таком большом диапазоне чисел. И вместо ручного создания массива чисел можно использовать циклы:

.data

index = 1
last = 101
nums equ this byte 
while index lt last
    byte index
    index = index + 1
endm

.code
main proc       
    xor rax, rax
    mov al, nums    ; al = 1
    ret
main endp
end

Здесь чуть больше кода. Для хранения добавляемого в массив значения определена переменная index, а для хранения максимального значения - константа last. Для задания массива nums применяется следующая запись:

nums equ this byte 

Цикл while на каждой итерации определяет в массиве nums один байт, который равен index, пока index не станет равным last. То есть в итоге мы опять же получим массив nums со 100 числами.

while index lt last
    byte index
    index = index + 1
endm

И мы можем пойти чуть дальше и определить макрос, который будет генерировать определенный диапазон значений. Например, создадим таблицу для преобразования символов из нижнего регистра в верхний. Для этого определим следующий код:

; макрос генерирует последовательность чисел от start до last
createRange macro start, last
    index = start
    while index lt last
        byte index
        index = index + 1
    endm
endm

.data
character byte "y"  ; символ для преобразования в верхний регистр

; Таблица для преобразования символов из нижнего регистра в верхний
table equ this byte
    createRange 0, "a"        ; на позиции 0-96 добавляем символьные коды от 0 до "a" не включая
    createRange "A", "Z"+1   ; на позиции 97-122 добавляем символьные коды от "A" до "Z" включая
    createRange "z"+1, 128  ; на позиции 123-127 добавляем оставшиеся символьные коды таблицы ASCII

.code
main proc       
    xor rax, rax
    mov al, character   ; AL = 121 - код символа y
    lea rbx, table
    xlat
    mov character, al   ; AL = 89 (код символа Y)
    ret
main endp
end

Макрос createRange принимает два параметра - числовой код начального символа диапазона и числовой код конечного символа. Для генерации диапазона применяется цикл while. В секции .data с помощью этого макроса генерируем три поддиапазона:

createRange 0, "a"        ; на позиции 0-96 добавляем символьные коды от 0 до "a" не включая
createRange "A", "Z"+1   ; на позиции 97-122 добавляем символьные коды от "A" до "Z" включая
createRange "z"+1, 128  ; на позиции 123-127 добавляем оставшиеся символьные коды таблицы ASCII

В общем случае по каждому индексу в таблице table будет располагать равный индексу числовой код символа (например, по индексу 10 - числовой код 10) за исключением диапазаона индексов 97-122, поскольку они представляют числовые коды символов в нижнем регистре. И на эти позиции мы повторно помещаем числовые коды символов в верхнем регистре - от "A" до "Z". Таким образом, мы получаем таблицу с числовыми кодами символов.

Для замены числового кода символа применяется инструкция xlat, которая фактически аналогична инструкции

mov al, [rbx + al * 1]

Эта инструкция использует текущее значение регистра AL в качестве индекса в массиве, базовый адрес которого находится в RBX. Она выбирает байт по этому индексу в массиве и копирует этот байт в регистр AL.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850