Кто нибуть писал что нибуть своё ? Я написал процедуру которая устанавливает флаг нуля если символ попадает в диапазон: 2Dh,2eh,30h-39h,41h-5ah,5fh,61h-7ah. Получает байт для проверки в al, использует только ah + флаги. Нужна максимальная скорость выполнения и минимальный размер. Код (Text): vsumbol: cmp al,41h jbe .s_low cmp al,5fh jbe .s_hlow mov ah,61h @@: cmp ah,al jz .s_equ inc ah cmp ah,7ah jbe @b jmp .s_equ .s_hlow: jz .s_equ mov ah,42h @@: cmp ah,al jz .s_equ inc ah cmp ah,5ah jbe @b jmp .s_equ .s_low: jz .s_equ cmp al,2eh jz .s_equ cmp al,2dh jz .s_equ jb .s_equ mov ah,30h @@: cmp ah,al jz .s_equ inc ah cmp ah,39 jbe @b .s_equ: ret
А зачем там два цикла? Код (Text): ; ------------------------------------------------------------ ; Input: ; AL = character ; Output: ; CF=TRUE if character is in alpha-numeric range ; ------------------------------------------------------------ isalnum: cmp al, '0' jb .not_alpha_num cmp al, '9' jbe .digit cmp al, 'A' jb .not_alpha_num cmp al, 'Z' jbe .upper_case cmp al, 'a' jb .not_alpha_num cmp al, 'z' jbe .lower_case .not_alpha_num: clc ret .digit: .upper_case: .lower_case: stc ret Код не тестировался, просто из головы...
ага точно, ступил что то... вот без циклов: Код (Text): vsumbol: cmp al,41h jbe .s_low cmp al,5fh jbe .s_hlow cmp al,61h jb .s_equ cmp al,7ah ja .s_equ cmp al,al jmp .s_equ .s_hlow: jz .s_equ cmp al,42h jb .s_equ cmp al,5ah ja .s_equ cmp al,al jmp .s_equ .s_low: jz .s_equ cmp al,2eh jz .s_equ cmp al,2dh jz .s_equ jb .s_equ cmp al,30h jb .s_equ cmp al,39h ja .s_equ cmp al,al .s_equ: ret Вся идея была в том, чтобы не проверять весь диапазон если al=63h например, а начать сразу с 61h-7ah
Если нужен "эффективный" способ думаю стоит использовать таблицы Код (Text): ALPHA = 01h DIGIT = 02h XDIGIT= 04h ; 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ;00: DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,08H,00H,00H,00H,08H,00H,00H ;10: DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;20: DB 08H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;30: '0' '1' '2' '3' '4' '5' '6' '7' '8' '9' DB 06H,06H,06H,06H,06H,06H,06H,06H,06H,06H,00H,00H,00H,00H,00H,00H ;40: 'A' 'B' 'C' 'D' 'E' 'F' DB 00H,05H,05H,05H,05H,05H,05H,01H,01H,01H,01H,01H,01H,01H,01H,01H ;50: 'Z' DB 01H,01H,01H,01H,01H,01H,01H,01H,01H,01H,01H,00H,00H,00H,00H,00H ;60: 'a' 'b' 'c' 'd' 'e' 'f' DB 00H,05H,05H,05H,05H,05H,05H,01H,01H,01H,01H,01H,01H,01H,01H,01H ;70: 'z' DB 01H,01H,01H,01H,01H,01H,01H,01H,01H,01H,01H,00H,00H,00H,00H,00H ;80 DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;90 DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;A0 DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;B0 DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;C0 DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;D0 DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;E0 DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;F0 DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H
Обычно это взаимоисключающие параметры кода. Если использовать таблицу, её незачем делать размером 256 байт. Достаточно 77 байт таблицы. Будет быстрее грузиться в кэш. Код (Text): .data table db 0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1 db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 db 0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0 db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .code cmp al,7Ah jge _end sub al,2Dh js _end and eax,0FFh mov eax,[eax+offset table] test al,al _end:
Нас интересует конкретно 78 возможных значений al (от 2Dh до 7ah включительно). Если за пределами этого диапазона, то однозначно флаг ZF должен быть сброшен. Если внутри диапазона - состояние флага будет зависеть от содержимого al: либо установлен, либо сброшен. Проще всего установить или сбросить флаг сделав test al,al. Если нужно установить ZF, то содержимое al перед выполнением test должно быть ==0. Если нужно сбросить ZF - любое !=0 (например 1). Проще всего установить требуемое al путем загрузки в него того или иного значения из таблицы. Причем сам регистр al (его содержимое) будет управлять тем, какое число в al будет загружено из таблицы: 0 или 1. Таблица составлена таким образом, что первой её ячейке соответствует значение al, которое должно быть загружено в регистр перед выполнением test al,al при его исходном значении равном 2Dh, вторая ячейка содержит значение, которое должно быть загружено при исходном al==2Eh и т.д. до 7Ah. теперь так: Код (Text): cmp al,7Ah ;если al больше или равно 7ah, то cmp установит ZF (если равно 7Ah) ;или сбросит ZF, если число больше 7Ah (за пределами интересующего диапазона). ;и после этого - сразу на _end. jge _end ;если меньше, проверяем теперь на нижнюю границу: 2Dh, ;заодно меняем al на значение равное смещению от нижней границы ;путём вычитания этой границы (2Dh) sub al,2Dh ;если после вычитания число получилось меньше 0, то ZF будет сброшен (al было меньше чем 2Dh) ;если после вычитания число получилось равно 0, то ZF будет установлен (al был равен 2Dh) ;если любое из этих двух условий выполнено - значит состояние ZF соответствует входным данным ;и теперь на выход. jle _end ;тут оказываемся, если исходный al был больше 2D и меньше 7A ;после sub в al могут быть значения от 0 до (7A-2D) ;то, что содержится сейчас в al - это смещение от начала исходного диапазона ;интересующих значений (от 2Ah). Т.е. если al==5, исходный al был 32h (2D+5) ;теперь имея смещение относительно начала диапазона, будем брать из таблицы ;значения, находящиеся в ней по этому смещению. ;обнуляем старшие разряды eax(кроме al) and eax,0FFh ;значение eax+offset table теперь равно адресу ячейки в таблице, из которой ;нужно загрузить число в al. ;Грузим al из таблицы (либо 0, либо 1) mov al,byte ptr[eax+offset table] ;делаем test, чтобы установить ZF в зависимости от того что было в al: 0 или 1 test al,al _end: Вроде всё. Т.е получается, что первыми двумя условными переходами отсекаются значения за пределами диапазона 2D - 7A, а затем регистру al сопоставляется то или иное число из таблицы, которое при выполнении test даст нужное состояние флага ZF. Рассказчик правда из меня неважный
2cresta ого..., спасибо большое, всё понял, теперь буду использовать, рассказчик из тебя отличный всем спасибо.
cresta А мне нравится, не нужно ни call на подпрограму, ни макромос для проверки, и всегда легко изменить настройки таблицы например добавить символы '_','$','@','%' в диапазон идентификаторов. Если обнулить eax, а код хранить в al, символы проверять очень просто. Код (Text): xor eax,eax mov esi,string lodsb test [eax+char_table],ALNUM jxx L_ALNUM test [eax+char_table],SPACE jxx L_SPACE or [eax+char_table],0 jz L_INVALID А если еще и на граничу 256 выровнять то можно вообще для проверки использовать только eax. Код (Text): align 256 char_table: ... mov eax,char_table mov esi,string lodsb test [eax],ALNUM jxx Но это больше относится вообше к разбору символов а не к данному случаю.
h3uristic Можно еще на 1 инструкцию ( и на 1 байт) подсократить код, если не грузать в al значение из таблицы, а непосредственно ячейку таблицы проверять: Код (Text): cmp al,7Ah jge _end sub al,2Dh jle _end and eax,0FFh cmp byte ptr [eax+offset table],0 _end: Smile В общем случае конечно, используется 256 байт, но тут такой случай, что весь диапазон не нужен. Если делать таблицу 256 байт, то код вообще будет состоять из двух инструкций: Код (Text): and eax,0FFh cmp byte ptr [eax+offset table],0
2cresta круто, но таблица огромная, 77 байт - памойму это много... мне кажется, можно/нужно последовать совету n0name и использовать не байты, а биты как одну ячейку. Вот первое что пришло в голову, буду переделывать... Код (Text): ;; Только уже во флаге переноса возвращается результат ;; если CF = 1 значит число входит в заданный диапазон vsumbol: ;; ;;;;;;; ????????????????????? ;; cmp al,7ah ja @f sub al,2dh js @f ;;;;;;; ????????????????????? and eax,0ffh push eax shr eax,3 mov bl, [ table + eax ] shl eax,3 sub [esp],eax pop eax bt ebx,eax jmp .exit @@: or al,al .exit: ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;;;;;;;;;2dh-7ah table db 11111011b, 00011111b, 11110000b, 11111111b ; 2dh - 4ch db 11111111b, 01111111b, 11101000b, 11111111b ; 4dh - 6ch db 11111111b, 11111111b ; 6dh - 7ch
h3uristic Этот код работает неправильно: для 5ah и 5Bh он выдает одинаковый результат на выходе, хотя должен разный. Да и медленее он в 3 раза. И регистр ebx задействуется, необходимо его сохранять и восстанавливать (push/pop) А сэкономить места удается совсем немного: 79 байт (40 таблица+39 код) против 97 (77 таблица+20 код). Стоит 19 байт трехкратного снижения в скорости? Если код с битовой таблицей привести в рабочий вид, возможно от этих 19 байт экономии ничего не останется. ИМХО. Mikl__ Думаю, xlat будет медленее, к тому же требуется 256 байт таблица
2cresta код работает правильно, ошибка в таблице нашлась, как раз с 5bh :/... и всё таки мне кажется, что можно что нибуть придумать... Код (Text): ;это правильная таблица table db 11111011b, 00011111b, 11110000b, 11111111b ; 2dh - 4ch db 11111111b, 00111111b, 11110100b, 11111111b ; 4dh - 6ch db 11111111b, 11111111b ; 6dh - 7ch
n0name да, точно. Только битовая работа - не самы лучший вариант. h3uristic Ага ошибки нет, вот только скорость работы с битовой таблицей не впечатляет. По-прежнему в 3 раза медленее (на 10 проходах 140 тиков против 48), чем с байтовой. Впрочем я уже говорил, что это взаимоисключающие вещи: размер и скорость. Выбери что-то либо скорость либо размер. Битовая таблица вынуждает применять операции сдвига, запоминания промежуточных данных, их восстановления. и при этом теряется основное преимущество таблицы - мгновенное получение готового результата. Одни минусы. Даже тупое сканирование, например: Код (Text): _st: cmp al,2dh je _set cmp al,2eh je _set cmp al,5fh je _set cmp al,7ah jge _reset cmp al,61h jge _set cmp al,5ah jg _reset cmp al,41h jge _set cmp al,39h jg _reset cmp al,30h jge _set _reset: or al,-1 test al,al jmp _end _set: xor al,al test al,al _end: быстрее в 2 раза, чем побитовая работа. К тому же и размер при тупом сканировании меньше В общем, самый неудачный вариант. Посмотри в аттаче, как распределяется скорость работы в зависимости от размера кода.