Дан текст не более 255 символов. Слова отделяются друг от друга пробелами. Определить слова, содержащее максимальное количество различных букв.
Оптимизация кода не производилась.
ASM-модуль содержит основную подпрограмму procasm, которая и вызывается из Паскаля и две вспомогательные подпрограммы sort (Сортировка массива методом пузырька) и calc (подсчет количества букв в слове).
Исходный код модуля Asmproc.asm
stk segment STACK
db 256 dup(?)
stk ends
data segment
extrn s :byte ;исходная строка из паскаля
extrn rezs :byte ;результирующая строка, для удобства тоже объявлена внешней
extrn p :word ;передаю в паскаль кол-во букв результирующей строки
Index dw 255 dup(?);массив, содержащий начало слов в исходной строке
maxCount dw 255 dup(?);массив, содержащий кол-во разных символов в каждом слове
cword dw 255 dup(?);массив, содержащий кол-во всех символов в каждом слове
max dw ?;переменная в которой хранится кол-во разных символов в текущем слове
allmax dw ?;переменная в которой содержится max кол-во неповторяющихся символов
count dw ?;будем здесь хранить номер последнего слова
countw dw ?;кол-во всех символов в текущем слове, наверное можно было обойтись без нее, но я ее использую
cw dw 0;кол-во слов в исходной строке
myrezs db 255 dup(?); вспомогательный массив символов, использую для сортировки символов в текущем слове
flag db 0 ;вспомогательная переменная, используется при сортировке, указывает требуется ли сортировать
mainoff dw ? ; вспомогательная переменная для определения смещения конца строки
data ends
code segment
assume cs:code, ds:data, ss:stk
public procasm
mov ax,data
mov ds,ax
mov es,ax; es тоже указывает на наш сегмент данных
procasm proc near ; если у вас более 64К то конечно far
extrn myprint:near ; тоже --- объявляем внешнюю процедуру (Паскалевскую)
lea di,s ;в di смещение исходной строки
mov mainoff,di ; в mainoff тоже, потребуется в дальнейшем
mov bl,s[0] ;длина строки из паскаля хранится в 0 байте строки
inc bl ;с учетом этого нулевого байта
xor bh,bh ; обнуляем старшую часть bx
mov cx,bx ; в сх длину исходной строки
mov count,cx
xor si,si; обнуляем регистр si
inc di ; увеличиваем на 1 di, чтобы исключить 0 элемент исходной строки
mov index[si],di ; индекс 1 слова
mov al,' ' ;будем искать пробел
cld ;обрабатываем строку слева направо
my1:
repne scasb ; сканируем строку пока не встретим первый пробел, либо пока не закончится строка
jcxz endstr ; а вдруг уже конец строки
add si,2 ; увеличим si на два, так как массив индексов состоит из слов
mov index[si],di ;занесем в массив найденный индекс следующего слова
inc cw ;количество пробелов
jmp my1
endstr:
inc cw ;количество слов на 1 больше чем пробелов, проверки на смежные пробелы нет
mov bx,cw
push bx ; сохраним в стеке кол-во слов, пригодится далее
xor si,si
m6: mov bx,index[si+2] ; в bx индекс следующего слова
sub bx,index[si] ; вычтем из bx индекс текущего слова, получим длину слова с пробелом
dec bx ; учтем пробел
mov countw,bx ; занесем в эту переменную длину текущего слова, знает зачем здесь наверное опять только всевышний
mov cword[si],bx ;сохраним в массив длину текущего слова
add si,2 ; увеличим индекс для массива
dec cw ; одно слово обработали, учтем это
cmp cw,1 ; уже последнее слово ?
jne m6 ;нет, берем следующее слово
mov bx,count
add bx,mainoff ;получим смещение конечного символа
sub bx,index[si] ;найдем длину последнего слова
mov cword[si],bx ; занесем его в массив
xor si,si ;наверное понятно что здесь делается, если не понятно КОРОТКИЙ ПЕРЕХОД НА -30 то есть на сроку на 35, там описано
pop bx ;извлекем из стека длину текущей строки
push bx ; сохраним опять далее тоже понадобится
mov cx,bx
mov allmax,0 ;для начала скажем, что у нас максимальная строка равна 0
m15:
push cx ; сохраним сх в стеке для внешнего цикла, так как будем работать со строковыми командами, которые тоже используют этот регистр
mov cx,cword[si] ;в сх длину текущего слова
mov countw,cx ; для подпрограмм
lea di,myrezs ; в di смещение вспомогательного массива
push si ; сохраним si в стеке, будем менять для подпрограмм
mov si,index[si] ; в si индекс текущего символа
rep movsb ; пересылаем текущее слово (хм не машинное) в вспомогательный массив
lea si,myrezs ; опять загружаем в si смещение полученной строки (т.е.(ягни) вспомогательного массива)
call sort ; вызываем процедуру сортировки по возрастанию вспомогательного массива
call calc ; вызываем процедуру подсчета кол-ва уникальных символов в вспомогательном массиве
mov bx,max ; в bx заносим, полученную из подпрограммы переменную max (кол-во уник.символов)
cmp bx,allmax ; сравним с allmax
jg m18 ; если больше, то занесем в allmax
m19: pop si ; восстановим из стека исходный индекс
mov maxCount[si],bx ;занесем в массив макс.кол-во уник.символов текущего слова
add si,2 ; увеличим индекс, почему на 2 смотри выше
pop cx ; восстановим из стека сх
loop m15 ; собственно сам цикл (уменьшает сх на 1, если сх=0 выход из цикла, иначе на метку m15)
jmp ex1 ;безусловный переход на метку ex1, чтобы не задеть следующие строки за циклом,
m18: mov allmax,bx ;чтоб случайно не перейти на обработку метки m18
jmp m19 ;прыгаем назад
ex1: pop bx ;УФФ вышли из цикла, восстановим из стека длину исходной строки
mov cx,bx
xor si,si
m16: push cx ; опять сохраним сх в стеке, зачем? опять будем работать со строками
mov bx,maxcount[si] ;в bx макс.кол-во уник.символов текущего слова
cmp allmax,bx ;сравним вообще с найденным максимумом
je print ;если равен то на распечатку
myret: add si,2 ;увеличим индекс
pop cx ;восстановим для цикла сх
loop m16 ;ну и зациклимся
ret ;возврат из подпрограммы, как вы думаете КУДА? (в главную программу на паскале)
print: push si ;восстановим исходный индекс
mov cx,cword[si] ; в сх длину нашего слова с макс.кол-вом уникальных символов
mov bx,allmax ; для вывода в паскале
mov p,bx ; запишем сюда
mov si,index[si] ; в si индекс этого слова
lea di,rezs ; в di смещение результирующей строки
inc di ;учтем нулевой элемент массива, где хранится длина строки
mov rezs[0],cl ;занесем в этот элемент длину строки
rep movsb ;перешлем эту строку
call myprint ;вызываем паскалевскую процедуру печати
pop si ;восстанавливаем исходный индекс
jmp myret ;прыгаем назад в цикл
procasm endp
sort proc ;сортировка методом пузырька
push ax ;на всякий случай сохраним в стеке используемые регистры
push cx
push di
push si
push bx
xor bx,bx ;что мы делаем? правильно обнуляем bx
cld
m13:
mov flag,0 ;говорим что у нас массив отсортирован
mov cx,countw ; в сх длину текущего слова
dec cx ; это чтоб не выйти за границы массива (N-1)
jcxz exit ; а вдруг слово состоит из одного символа (здесь дурак не пройдет (есть защита))
push si ; сохраним на всякий случай, а вдруг массив не отсортирован
lodsb ;загрузим в al первый символ из текущего слова
mov bl,al ;занесем его в bl
m12:
lodsb ;загрузим следующий символ
cmp al,bl ;сравним
jg m11 ;если правее, то на обмен
mov bl,al ; если нет, то в bl занесем al
m10:
loop m12 ;зацикливаемся
cmp flag,0 ; на выходе проверяем наш флаг
pop si ;на всякий случай восстановим из стека
je exit ;УРА! отсортировали и на выход
jmp m13 ;иначе все же идем досортировывать
m11: push si ; в стек
pop di ; из стека
sub di,2 ;вернем указатель приемника назад на 2
stosb ;занесем в строку из al, при этом di указывает на следующий символ
mov al,bl ;теперь вернем на свое законное место и bl
stosb ;этой командой
mov flag,1 ;здесь говорим что все же массив не отсортирован
jmp m10 ;прыгаем назад в цикл
exit: pop bx ;подтираем за собой, восстанавливаем из стека
pop si
pop di
pop cx
pop ax
ret
sort endp
calc proc near ;подсчет количества букв в слове
push ax
push cx
push di
push si
push bx
mov max,1 ;хотя бы один уникальный символ будет
mov cx,countw
dec cx
jcxz exit1 ;а все таки вдруг был один символ в слове
cld
lodsb ;загружаем в al первый символ из текущего слова (строки) по адресу ds:si
mov bl,al ; наверное понятно (если нет, то вам ничем нельзя помочь (это не лечится))
m5: lodsb ;загружаем следующий символ
cmp al,bl ;сравниваем
jne m4 ;если уникальный то увеличение счетчика
m7: mov bl,al ;иначе идем дальше по циклу
loop m5
jmp exit1 ;безусловный переход на метку exit1, ЗАЧЕМ? а чтобы случайно не выполнить обработку метки m4
m4: inc max ;увеличиваем счетчик уникальных символов
jmp m7 ;назад в цикл
exit1: pop bx ;неужели выход
pop si
pop di
pop cx
pop ax
ret
calc endp
code ends
end
Исходный код модуля VAR28.pas
program main;
{$L asmproc.obj}
var
s,rezs:string;
p:word;
procedure procasm; external;
procedure myprint;
begin
writeln(rezs);
writeln(p);
end;
begin
write('Enter string:');
readln(s);
procasm;
readln;
end.
|