Помощь - Поиск - Пользователи - Календарь
Полная версия: Обработка символьной информации
Форум «Всё о Паскале» > Современный Паскаль и другие языки > Ассемблер
Rocket
Вот задание: Ввести с клавиатуры две строки. Сравнить их. Вывести на экран какая из строк больше и насколько. Какие мысли есть по реализации данной программы? Как осуществить сравнение строк?
мисс_граффити
Что значит "строка больше"? По длине?
Rocket
Цитата(мисс_граффити @ 6.10.2008 20:22) *

Что значит "строка больше"? По длине?

Та по длине походу... сравнивать количество символов...как реализовать- до сих пор загадка..smile.gif
Lapp
Цитата(Rocket @ 6.10.2008 20:28) *
Та по длине походу... сравнивать количество символов...как реализовать- до сих пор загадка..smile.gif
При чем тут загадка? Не понимаю. Если по длине, то функция Length(s) решает все проблемы.
Но если требуется все-таки лексикографическое сравнение, то тогда действительно загадка. То есть само сравнение будет еще проще (типа s1<s2), но совершенно непонятно, что значит "на сколько" [орфография моя].
Rocket
Цитата(Lapp @ 7.10.2008 0:02) *

При чем тут загадка? Не понимаю. Если по длине, то функция Length(s) решает все проблемы.
Но если требуется все-таки лексикографическое сравнение, то тогда действительно загадка. То есть само сравнение будет еще проще (типа s1<s2), но совершенно непонятно, что значит "на сколько" [орфография моя].

В ассемблере есть функция length(s)?...в мои познания этого языка данная функция ещё не входит...
Lapp
Цитата(Rocket @ 6.10.2008 23:23) *
В ассемблере есть функция length(s)?...в мои познания этого языка данная функция ещё не входит...
Упс! погорячился... smile.gif)) Прошу прощения!

А как организаешь строки? Паскалевсие или нуль-терминированные?
мисс_граффити
Ввод строк сделал? Проблемы только с определением длины?
Могу попробовать вечером набросать код... но неохота тупо выкладывать готовую работу.

Lapp, что значит "паскалевские строки" применительно к асму?
Rocket
Цитата(мисс_граффити @ 7.10.2008 15:37) *

Ввод строк сделал? Проблемы только с определением длины?
Могу попробовать вечером набросать код... но неохота тупо выкладывать готовую работу.

Lapp, что значит "паскалевские строки" применительно к асму?

Не большой пример про ввод строки я видел, выглядит примерно вот так:

buffer 		db 11 		; Нулевой байт буфера
entered db (?) ; Число введенных символов
string db 11 dup (?) ; Введенные символы


Сам ввод выполняется командами:

lea dx, buffer ; Адрес буфера в dx
mov ah, 0ah ; Номер функции в аh
int 21h ; Вызов функции


Что изменится при вводе двух строк?
А набросанный код пришёлся бы очень кстати) всё равно и в нём нужно будет разобраться


мисс_граффити
Ну например...
.model small
.stack 512
.data
buf1 db 10 dup(?)
buf2 db 10 dup(?)
len1 dW (?)
mes1 db 'First is longer$'
mes2 db 'Second is longer$'
.code
;заносим адрес сегмента данных в DX
mov AX, @data
mov DS, AX

lea dx,buf1 ;куда считываем первую строку символов
mov ah,3Fh ;ввод с клавиатуры целой строки
mov bx,0
int 21h
mov len1,ax ;кол-во реально введенных символов+2 (0Ah и ODh - то есть Enter)

lea dx,buf2 ;куда считываем вторую строку символов
mov ah,3Fh ;ввод с клавиатуры целой строки
mov bx,0
int 21h

cmp ax,len1
jge m2

mov ah,9 ;выводим сообщение
lea dx,mes1
int 21h
jmp finish ;всё...

m2: mov ah,9 ;выводим сообщение
lea dx,mes2
int 21h

finish: mov ax,4c00h
int 21h
end

Длина строк маленькая (см. объявление переменных).
НА СКОЛЬКО они отличаются - не считаю (думаю, с арифм операциями как-нибудь разберешься).
Вариант равенства длин не предусмотрен.
Ну и косяки могут быть - ассемблер я не знаю практически.
Rocket
Цитата(мисс_граффити @ 7.10.2008 21:26) *
Ну например...

всё отлично, большое спасибо) вот только вывод сообщения отказывается работать...
Я вот так немного переделал:

data segment
buf1 db 10 dup(?)
buf2 db 10 dup(?)
len1 dW (?)
mes1 db 'First is longer$'
mes2 db 'Second is longer$'
data ends
code segment
assume cs:code, ds:data

start: mov AX, data
mov DS, AX

lea dx,buf1 ;куда считываем первую строку символов
mov ah,3Fh ;ввод с клавиатуры целой строки
mov bx,0
int 21h
mov len1,ax ;кол-во реально введенных символов+2 (0Ah и ODh - то есть Enter)

lea dx,buf2 ;куда считываем вторую строку символов
mov ah,3Fh ;ввод с клавиатуры целой строки
mov bx,0
int 21h

cmp ax,len1
jge m2

lea dx,mes1
mov ah,09h ;выводим сообщение
int 21h
jmp finish ;всё...

m2: lea dx,mes2
mov ah,09h ;выводим сообщение
int 21h

finish: mov ax,4c00h
int 21h
code ends
end start

мисс_граффити
У меня работает все.
Да ты по сути ничего в этой сфере вроде и не изменил. Строки местами поменял - и все?

Если assume написал - убери
mov AX, data
mov DS, AX

оно у тебя уже делается.


Rocket
Цитата(мисс_граффити @ 9.10.2008 0:54) *

У меня работает все.
Да ты по сути ничего в этой сфере вроде и не изменил. Строки местами поменял - и все?

Если assume написал - убери
mov AX, data
mov DS, AX

оно у тебя уже делается.

Без assume вообще не работает... Впрочем сообщение также отказывается выводить unsure.gif
volvo
Rocket,
Чем компилируешь, если не секрет?

Приведенный тобой в 10-м сообщении код прекрасно отрабатывает после сборки ДОСовским TASM-ом версии 3.0... Отладчиком не смотрел, на каком этапе у тебя проблема?
Rocket
Цитата(volvo @ 10.10.2008 0:43) *

Rocket,
Чем компилируешь, если не секрет?

Приведенный тобой в 10-м сообщении код прекрасно отрабатывает после сборки ДОСовским TASM-ом версии 3.0... Отладчиком не смотрел, на каком этапе у тебя проблема?

Проблема в том, что не выводит сообщение в Turbo Debugger'е (версия 3.1). Tasm у меня версии 1.0...
volvo
Цитата
Проблема в том, что не выводит сообщение в Turbo Debugger'е (версия 3.1)
А может, ты его просто не видишь? wink.gif Alt+F5 не пробовал для просмотра результатов? Ну, или View -> User Screen...
Rocket
Цитата(volvo @ 10.10.2008 22:51) *

А может, ты его просто не видишь? wink.gif Alt+F5 не пробовал для просмотра результатов? Ну, или View -> User Screen...

smile.gif так и оказалось... Теперь я буду знать столь "хитрую" комбинацию клавиш!
Rocket
Всё-таки как организовать вывод сообщеия о том насколько отличаются строки?
Вот как я делаю:

data segment
buf1 db 10 dup(?)
buf2 db 10 dup(?)
len1 dW (?)
mes1 db 'First is longer!$'
mes2 db 'Second is longer!$'
X dw ?
data ends
code segment
assume cs:code, ds:data

start: mov AX, data
mov DS, AX

lea dx,buf1 ;куда считываем первую строку символов
mov ah,3Fh ;ввод с клавиатуры целой строки
;mov bx,0
int 21h
mov len1,ax ;кол-во реально введенных символов+2 (0Ah и ODh - то есть Enter)

lea dx,buf2 ;куда считываем вторую строку символов
mov ah,3Fh ;ввод с клавиатуры целой строки
;mov bx,0
int 21h

cmp ax,len1
jge m2

sub ax,len1
mov X,ax

lea dx,X
mov ah,02h ; вот здесь что-то неправильно...
int 21h


lea dx,mes1
mov ah,09h ;выводим сообщение
int 21h

jmp finish ;всё...

m2:
sub ax,len1
mov X,ax

lea dx,X
mov ah,02h ;оно же
int 21h

lea dx,mes2
mov ah,09h ;выводим сообщение
int 21h


finish: mov ax,4c00h
int 21h
code ends
end start

volvo
Ну, и кто тебе сказал, что
lea dx, X

преобразует тебе число в его символьное представление? Функция 02H прерывания 21H ведь выводит символ, код которого хранится в DX, а у тебя в DX что хранится?

Убери из сегмента данных X, и добавь вместо него len2...
	lea dx, buf1	;куда считываем первую строку символов
mov ah, 3Fh ; ввод с клавиатуры целой строки
int 21h
mov len1, ax ; кол-во реально введенных символов+2 (0Ah и ODh - то есть Enter)

lea dx, buf2 ; куда считываем вторую строку символов
mov ah, 3Fh ; ввод с клавиатуры целой строки
int 21h
mov len2, ax

cmp ax, len1
jge m2

mov ax, len1
sub ax, len2
add ax, 48 ; переводим в CHAR
mov dx, ax ; заносим в DX
mov ah, 02h ; печатаем
int 21h

lea dx, mes1
mov ah, 09h ; выводим сообщение
int 21h

jmp finish ; всё...

m2:
mov ax, len2
sub ax, len1
add ax, 48
mov dx, ax
mov ah, 02h
int 21h

lea dx,mes2
mov ah,09h ; выводим сообщение
int 21h

finish:

Rocket
А если у нас не 10 символом максимальный размер, а 100, то как тогда вывести разность длин строк? (то есть проблема с выводом двузначного числа,к примеру)
И функция 3Fh, что она делает?
volvo
Значит, придется написать процедуру вывода десятичного числа:


; В сегменте данных:
count_of_digits dw 4 ; число будет отображаться в четырех позициях
; ...

writeDEC proc
; выводим содержимое AX
push ax
push bx
push cx
push dx

push di ; здесь будем хранить признак знака
xor cx, cx
mov bx, 10
xor di, di ; 0 = число положительное
or ax, ax ; Проверим, не отрицательное ли число в AX
jns next_digit ; Не отрицательное... Переходим дальше
inc di ; Отрицательное. Выставляем DI в 1 (число отрицательное) ...
neg ax ; ... и меняем знак числа

next_digit:
xor dx, dx ; DX обнуляется. Чтобы можно было делить DWORD на WORD
div bx ; Делмм DX:AX на BX (т.е. на 10) ...
push dx ; ... остаток забрасываем в стек ...
inc cx ; Увеличим счетчик цифр
or ax, ax
jnz next_digit ; ... и продолжаем этот цикл пока AX <> 0

mov dx, count_of_digits
sub dx, cx ; вычисляем, сколько пробелов надо вывести перед числом
or di, di
jz _zer
dec dx ; если ранее был установлен "признак отрицательности"
; то уменьшаем число пробелов еще на 1, поскульку надо еще вывести "-"
_zer:
push cx ; сохраним число цифр в стеке
mov cx, dx
mov al, ' ' ; и напечатаем необходимое число пробелов
next_space:
int 29h ; прерывание 29h - вывод на консоль
loop next_space

pop cx ; вернем число цифр
or di, di
jz next_char
mov al, '-'
int 29h ; если нужен минус - выводим его

next_char:
pop ax ; остатки от деления возвращаем в AX
add al, '0' ; преобразуем в символ (добавляя код '0')
int 29h ; и выводим на консоль
loop next_char

pop di ; восстанавливаем все регистры
pop dx
pop cx
pop bx
pop ax
ret ; и выходим из процедуры
writeDEC endp

, и вызывать вот так:
	; ...
mov ax, len1
sub ax, len2
call writeDEC ; печатаем разность

lea dx, mes1
mov ah, 09h ; выводим сообщение, что первая строка длиннее
int 21h

jmp finish ; на выход

m2:
mov ax, len2
sub ax, len1
call writeDEC ; печатаем разность

lea dx, mes2
mov ah,09h ; выводим сообщение, что длиннее вторая строка
int 21h

finish:
; ...


Цитата
И функция 3Fh, что она делает?
Ну ты даешь... smile.gif Я что-ли эту функцию придумал использовать? Ты сам в своей программе ее применял, а теперь спрашиваешь... Она вводит с клавиатуры строку (максимально возможную длину строки надо занести в CX), и помещает ее в буфер (адрес буфера - в DX).
Rocket
Цитата(volvo @ 27.11.2008 23:12) *
Значит, придется написать процедуру вывода десятичного числа:


А можно более подробно объяснить логику данной подпрограммы?...не предполагал, что реализация будет столь замысловатой smile.gif
volvo
Цитата
А можно более подробно объяснить логику данной подпрограммы?
Комментарии добавлены в предыдущее сообщение...
Rocket
Цитата(volvo @ 28.11.2008 1:10) *

Комментарии добавлены в предыдущее сообщение...

Теперь всё стало на свои места, спасибо good.gif

А вот как организовать подпрограмму поиска одной введённой строки в другой строке? И ещё: вывод позиции, с которой подстрока содержится в строке...
volvo
Цитата
А вот как организовать подпрограмму поиска одной введённой строки в другой строке? И ещё: вывод позиции, с которой подстрока содержится в строке...
Вот тебе программа, которая это делает... В виде подпрограммы оформляй сам:

MODEL small

stack 100
.286

DATASEG
entrStr db 13, 10, 'string:$'
entrSStr db 13, 10, 'substring:$'
sNotFound db 13, 10, 'substring was not found$'
sResult db 13, 10, 'pos = $'

inpStr db 200
inpStrLen db ?
inpStrDat db 200 dup(?)

inpSStr db 200
inpSStrLen db ?
inpSStrDat db 200 dup(?)

count_of_digits dw 6

CODESEG

writeDEC proc

; ...

writeDEC endp

show_ax proc
mov cx, 10
xor di, di
@@conv:
xor dx, dx
div cx
add dl, '0'
inc di
push dx ; складываем в стэк
or ax, ax
jnz @@conv
; выводим из стэка на экран
@@show:
pop dx ; dl = очередной символ
mov ah, 2 ; ah - функция вывода символа на экран
int 21h
dec di ; повторяем пока di<>0
jnz @@show
ret
show_ax endp

start:
mov ax,@DATA
mov ds, ax
mov es, ax

; вводим строку
mov ah, 09h
mov dx, offset entrStr
int 21h
mov ah, 0ah
mov dx, offset inpStr
int 21h

; записываем '$' в конец строки
mov di, offset inpStrDat
xor ch, ch
mov cl, inpStrLen
add di, cx
mov byte ptr[di], '$'

; вводим подстроку
mov ah, 09h
mov dx, offset entrSStr
int 21h
mov ah, 0ah
mov dx, offset inpSStr
int 21h

; Подготовка
xor cx, cx
mov di, offset inpStrDat
mov si, offset inpSStrDat
mov cl, inpStrLen

; Ищем первый символ подстроки
FindFirstCh:
mov al, [di] ;
inc di
cmp al, [si]
jz beginCompare ; Нашли

nextCompare:
loop FindFirstCh

; Если цикл FindFirstCh закончился - значит подстроки нет
mov ah, 09h
mov dx, offset sNotFound
int 21h
jmp exit_prog

beginCompare:
; Проверяем следующие за первым в подстроке символы
push cx
push si
push di
dec di
mov cl, inpSStrLen

; Проверка
yesCompare:
mov al, [di]
inc di
cmp al, [si]
jnz noCompare ; Очередной символ не совпал
inc si
loop yesCompare

; Если здесь - значит все совпало
jmp found

; Не совпало - восстанавливаем данные и ищем дальше
; первый символ подстроки в строке
noCompare:
pop di
pop si
pop cx
jmp short nextCompare

found:
; Есть совпадение, выводим сообщение
mov ah, 09h
mov dx, offset sResult
int 21h

; вытягиваем из стека адрес первого символа
pop di

; и вычисляем его позицию
mov dx, offset inpStrDat
mov ax, di
sub ax, dx
call writeDEC ; Эту процедуру я показывал раньше

exit_prog:
mov ah, 4ch
int 21h
end start

(процедуру writeDEC возьми из предыдущих постов, я не стал ее опять копировать...)
Rocket
Цитата(volvo @ 7.12.2008 12:24) *
Вот тебе программа, которая это делает...

У меня возник ряд вопросов по реализации...
1) Использование "offset". Я так полагаю, что это полный аналог команды "lea" ?
2) inpStrDat что это за переменная, для чего она нужна?
3)
mov di, offset inpStrDat
что делает конструкция такого вида?
4) Как определяется размер строки? т.е.
mov cl, inpStrLen
почему в cl сразу помещается размер строки?
5) При переходе на метку
beginCompare:
, где мы должны проверять последующие за первой буквы, мы снова проверяем совпадение первых букв, так ли это?
6) Когда мы из стека вытаскиваем di, разве он сразу не указывает на позицию, с которой начинается подстрока в строке? Как вообще происходит тогда вычисление позиции?
volvo
Цитата(Rocket @ 8.12.2008 23:36) *
1) Использование "offset". Я так полагаю, что это полный аналог команды "lea" ?
Правильно полагаешь...

; можно вот так получить смещение inpStrDat
; в сегменте данных
mov di, offset inpStrDat

; а можно - вот так:
lea di, inpStrDat
В обоих случаях смещение этого массива от начала сегмента будет занесено в регистр DI...

Цитата(Rocket @ 8.12.2008 23:36) *
2) inpStrDat что это за переменная, для чего она нужна?
Как это "для чего"? А строку ты что, в воздухе хранить будешь? Вообще-то для нее надо место выделять. Вот я и выделил 200 байт.

Вообще обрати внимание, для ввода строки используется функция 0AH прерывания 21H... А она требует для работы вот чего:
Цитата(Абель)
LABEL представляет собой директиву с атрибутом BYTE. Первый байт содержит максимальную длину вводимых данных. Так как это однобайтовое поле, то возможное максимальное значение его - FFh или 255. Второй байт необходим DOS для занесения в него действительного числа введенных символов. Третьим байтом начинается поле, которое будет содержать введенные символы.
 	NAMEPAR	LABEL BYTE	; Список параметров:
MAXLEN DB 20 ; Максимальная длина
ACTLEN DB ? ; Реальная длина
NAMEFLD DB 20 DUP (' ') ; Введенные символы

Так как в списке параметров директива LABEL не занимает места, то NAMEPAR и MAXLEN указывают на один и тот же aдрес памяти. В трансляторе MASM для определения списка параметров в виде структуры может использоваться также директива STRUC. Однако, в связи с тем, что ссылки на имена, определенные внутри, требуют специальной адресации, воздержимся cейчас от рассмотрения данной темы до гл. 24 "Директивы ассемблера".
Для запроса на ввод необходимо поместить в регистр AH номер функции - 10 (шест. 0Ah), загрузить адрес списка параметров (NAMEPAR в нашем примере) в регистр DX и выполнить INT 21H
Вот так... А поскольку я не описывал LABEL (ленивый я, не люблю набирать лишние символы smile.gif ), то в DX загружал смещение inpStr, то есть, первого из необходимых параметров...

Я надеюсь, вопрос
Цитата(Rocket @ 8.12.2008 23:36) *
4) Как определяется размер строки? т.е.
mov cl, inpStrLen
почему в cl сразу помещается размер строки?
исчерпан? Я там, в цитате, выделил ответ на него...

Цитата(Rocket @ 8.12.2008 23:36) *
5) При переходе на метку
beginCompare:
, где мы должны проверять последующие за первой буквы, мы снова проверяем совпадение первых букв, так ли это?
Так, но почему тебя это пугает? Я же уменьшаю DI перед проверкой, то есть, DI указывает именно на первый, совпавший символ в строке...

Цитата(Rocket @ 8.12.2008 23:36) *
6) Когда мы из стека вытаскиваем di, разве он сразу не указывает на позицию, с которой начинается подстрока в строке? Как вообще происходит тогда вычисление позиции?
Нет, он указывает на смещение относительно начала сегмента... А для того, чтобы вычислить позицию, надо из этого самого смещения, которое хранится в DI, вычесть смещение первого символа строки, которое я и заношу в DX... После вычитания в AX имеем позицию подстроки в строке...
Rocket
Всё стало на свои места! Спасибоsmile.gif
Так, вот ещё несколько вопросов вопросов :
1) процедура show_ax для чего предназначена? мы вроде её не используем нигде...
2) Зачем записывать $ конец введённой строки? Я знаю, что это признак конца строки...
3) Как это в виде процедуры оформить? Я полагаю, что после ввода строки и подстроки и после соответствующих подготовок. Нужно что-нибудь передавать в процедуру или прятать в стек?
volvo
Цитата(Rocket @ 9.12.2008 23:24) *
1) процедура show_ax для чего предназначена? мы вроде её не используем нигде...
Это я забыл удалить, она не нужна тут...

Цитата(Rocket @ 9.12.2008 23:24) *
2) Зачем записывать $ конец введённой строки? Я знаю, что это признак конца строки...
Ну, раз знаешь - чего спрашиваешь? smile.gif Допустим, ты ввел 20 символов, места выделено под 200, и тебе понадобилось распечатать введенную строку. Что делать будешь? Правило хорошего тона требует заполнить строку как положено (если этого не делает функция DOS - то это должен сделать программист, чтоб потом не отлавливать глюки). Раз строка должна заканчиваться символом "$", значит его надо добавить...

Цитата(Rocket @ 9.12.2008 23:24) *
3) Как это в виде процедуры оформить? Я полагаю, что после ввода строки и подстроки и после соответствующих подготовок. Нужно что-нибудь передавать в процедуру или прятать в стек?
Да, скорее всего надо в процедуре получать через DI адрес строки, через SI - адрес подстроки, и через CX - длину строки... А возвращать значение она должна через AX, как обычно, если AX = 0, то совпадений нет, иначе в AX содержится индекс первого элемента строки... Сохранять надо все регистры, которые изменяются внутри процедуры, опять же правило хорошего тона: не делай сам себе проблем, после возврата из процедуры содержимое регистров (кроме тех, через которые возвращаются результаты) должно быть точно таким же, как и до ее вызова...
Rocket
Цитата(volvo @ 10.12.2008 0:46) *

Да, скорее всего надо в процедуре получать через DI адрес строки, через SI - адрес подстроки, и через CX - длину строки... А возвращать значение она должна через AX, как обычно, если AX = 0, то совпадений нет, иначе в AX содержится индекс первого элемента строки... Сохранять надо все регистры, которые изменяются внутри процедуры, опять же правило хорошего тона: не делай сам себе проблем, после возврата из процедуры содержимое регистров (кроме тех, через которые возвращаются результаты) должно быть точно таким же, как и до ее вызова...


Я переделал следующим образом:

data segment
entrStr db 13, 10, 'string:$'
entrSStr db 13, 10, 'substring:$'
sNotFound db 13, 10, 'substring was not found$'
sResult db 13, 10, 'pos = $'

inpStr db 100
inpStrLen db ?
inpStrDat db 100 dup(?)

inpSStr db 100
inpSStrLen db ?
inpSStrDat db 100 dup(?)

count_of_digits dw 2
data ends


code segment
assume cs:code, ds:data

writeDEC proc

push ax
push bx
push cx
push dx

xor cx, cx
mov bx, 10

next_digit:
xor dx, dx
div bx
push dx
inc cx
or ax, ax
jnz next_digit

next_char:
pop ax
add al, '0'
int 29h
loop next_char

pop dx
pop cx
pop bx
pop ax
ret

writeDEC endp


findSStr proc

push di
push si
push cx

; Ищем первый символ подстроки
FindFirstCh:
mov al, [di] ;
inc di
cmp al, [si]
jz beginCompare ; Нашли

nextCompare:
loop FindFirstCh

; Если цикл FindFirstCh закончился - значит подстроки нет
mov ah, 09h
lea dx, sNotFound
int 21h
jmp finish

beginCompare:
; Проверяем следующие за первым в подстроке символы
push cx
push si
push di
dec di
mov cl, inpSStrLen

; Проверка
yesCompare:
mov al, [di]
inc di
cmp al, [si]
jnz noCompare ; Очередной символ не совпал
inc si
loop yesCompare

; Если здесь - значит все совпало
jmp found

; Не совпало - восстанавливаем данные и ищем дальше
; первый символ подстроки в строке
noCompare:
pop di
pop si
pop cx
jmp short nextCompare

found:
; Есть совпадение, выводим сообщение
mov ah, 09h
lea dx, sResult
int 21h

; вытягиваем из стека адрес первого символа
pop di

; и вычисляем его позицию
lea dx, inpStrDat
mov ax, di
sub ax, dx
call writeDEC ; Эту процедуру я показывал раньше


ret
findSStr endp


start:
mov ax,data
mov ds, ax


; вводим строку
mov ah, 09h
lea dx, entrStr
int 21h
mov ah, 0ah
lea dx, inpStr
int 21h

; записываем '$' в конец строки
lea di, inpStrDat
xor ch, ch
mov cl, inpStrLen
add di, cx
mov byte ptr[di], '$'

; вводим подстроку
mov ah, 09h
lea dx, entrSStr
int 21h
mov ah, 0ah
lea dx, inpSStr
int 21h

; Подготовка
xor cx, cx
lea di, inpStrDat
lea si, inpSStrDat
mov cl, inpStrLen

call findSStr

finish: mov ax,4c00h
int 21h

code ends
end start


и всё-таки походу криво процедуру оформил... ?
volvo
А я переделал вот так:
findSStr proc
; Ищем первый символ подстроки
FindFirstCh:
mov al, [di] ;
inc di
cmp al, [si]
jz beginCompare ; Нашли

nextCompare:
loop FindFirstCh

xor ax, ax ; не найдено, вернем 0

; Если цикл FindFirstCh закончился - значит подстроки нет
jmp exit_proc

beginCompare:
; Проверяем следующие за первым в подстроке символы
push cx
push si
push di
dec di
mov cl, inpSStrLen

; Проверка
yesCompare:
mov al, [di]
inc di
cmp al, [si]
;не совпало переход
jnz noCompare ; Очередной символ не совпал
inc si
loop yesCompare

; Если здесь - значит все совпало
jmp found

; Не совпало - восстанавливаем данные и ищем дальше
; первый символ подстроки в строке
noCompare:
pop di
pop si
pop cx
jmp short nextCompare

found:
; вытягиваем из стека адрес первого символа
pop di

; и вычисляем его позицию
mov dx, offset inpStrDat
mov ax, di
sub ax, dx
;call writeDEC ; Эту процедуру я показывал раньше

pop si
pop cx

exit_proc:
ret
findSStr endp

; вызов:
; Подготовка
xor cx, cx
mov di, offset inpStrDat
mov si, offset inpSStrDat
mov cl, inpStrLen

call findSStr

test ax, 0
jnz not_found

; Есть совпадение, выводим сообщение
push ax
mov ah, 09h
mov dx, offset sResult
int 21h
pop ax
call writeDEC
jmp exit_prog

not_found:
mov ah, 09h
mov dx, offset sNotFound
int 21h

exit_prog:
mov ah, 4ch
int 21h

, что я сделал не так? smile.gif

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

data segment
entrStr db 13, 10, 'string:$'
entrSStr db 13, 10, 'substring:$'
sNotFound db 13, 10, 'substring was not found$'
sResult db 13, 10, 'pos = $'

inpStr db 100
inpStrLen db ?
inpStrDat db 100 dup(?)

inpSStr db 100
inpSStrLen db ?
inpSStrDat db 100 dup(?)

count_of_digits dw 2
data ends


code segment
assume cs:code, ds:data

writeDEC proc

push ax
push bx
push cx
push dx

xor cx, cx
mov bx, 10

next_digit:
xor dx, dx
div bx
push dx
inc cx
or ax, ax
jnz next_digit

next_char:
pop ax
add al, '0'
int 29h
loop next_char

pop dx
pop cx
pop bx
pop ax
ret

writeDEC endp


findSStr proc

; Ищем первый символ подстроки
FindFirstCh:
mov al, [di] ;
inc di
cmp al, [si]
jz beginCompare ; Нашли

nextCompare:
loop FindFirstCh
xor ax, ax ; не найдено, вернем 0

; Если цикл FindFirstCh закончился - значит подстроки нет
jmp exit_proc

beginCompare:
; Проверяем следующие за первым в подстроке символы
push cx
push si
push di
dec di
mov cl, inpSStrLen

; Проверка
yesCompare:
mov al, [di]
inc di
cmp al, [si]
;не совпало переход
jnz noCompare ; Очередной символ не совпал
inc si
loop yesCompare

; Если здесь - значит все совпало
jmp found

; Не совпало - восстанавливаем данные и ищем дальше
; первый символ подстроки в строке
noCompare:
pop di
pop si
pop cx
jmp short nextCompare

found:
; вытягиваем из стека адрес первого символа
pop di

; и вычисляем его позицию
mov dx, offset inpStrDat
mov ax, di
sub ax, dx

pop si
pop cx

exit_proc:
ret

findSStr endp


start:
mov ax,data
mov ds, ax


; вводим строку
mov ah, 09h
lea dx, entrStr
int 21h
mov ah, 0ah
lea dx, inpStr
int 21h

; записываем '$' в конец строки
lea di, inpStrDat
xor ch, ch
mov cl, inpStrLen
add di, cx
mov byte ptr[di], '$'

; вводим подстроку
mov ah, 09h
lea dx, entrSStr
int 21h
mov ah, 0ah
lea dx, inpSStr
int 21h

; Подготовка
xor cx, cx
mov di, offset inpStrDat
mov si, offset inpSStrDat
mov cl, inpStrLen

call findSStr

test ax, 0
jnz not_found

; Есть совпадение, выводим сообщение
push ax
mov ah, 09h
mov dx, offset sResult
int 21h
pop ax
call writeDEC
jmp exit_prog

not_found:
mov ah, 09h
mov dx, offset sNotFound
int 21h

exit_prog:
mov ax, 4c00h
int 21h
code ends
end start


и в ней присутствует косяк... Вобщем, когда подстроки нет в строке, то программа всё равно выводит сообщение с номером позиции...выводит 0. Мне кажется, что не происходит вот это:

xor ax, ax; не найдено, вернем 0
; Если цикл FindFirstCh закончился - значит подстроки нет
jmp exit_proc




volvo
Цитата
Мне кажется, что не происходит вот это:

xor ax, ax; не найдено, вернем 0
; Если цикл FindFirstCh закончился - значит подстроки нет
jmp exit_proc
Нет... Проблема не тут. Замени вот эти 2 строки:
	test ax, 0
jnz not_found

на
	or ax, ax
jz not_found
и проверь...
Rocket
Цитата(volvo @ 10.12.2008 23:56) *

Нет... Проблема не тут. Замени вот эти 2 строки:
	test ax, 0
jnz not_found

на
	or ax, ax
jz not_found
и проверь...

Идельно! Всё работает! Недеюсь больше по этой программе вопросов не возникнет)

Я решил в первой программе, которая определяла какая из двух строк больше и насколько, решил изменить функцию ввода с 3Fh на 0ah, я же теперь знаю особенности этой функции в отличии от функции 3Fh...
Всё бы ничего, только вот вывод цифры отказывается работать...
Вот собственно сама переделанная программа:

data segment
inpStr1 db 100
inpStrLen1 db ?
inpStrDat1 db 100 dup(?)
inpStr2 db 100
inpStrLen2 db ?
inpStrDat2 db 100 dup(?)

mes1 db 13, 10, 'First is longer!$'
mes2 db 13, 10, 'Second is longer!$'
mes3 db 13, 10, 'Enter the first string: $'
mes4 db 13, 10, 'Enter the second string: $'
outstr db 13, 10, '$'
count_of_digits dw 2
data ends

code segment
assume cs:code, ds:data

start: mov AX, data
mov DS, AX

lea dx,mes3
mov ah,09h
int 21h
lea dx,inpStr1
mov ah,0ah
int 21h


lea dx,mes4
mov ah,09h
int 21h
lea dx,inpStr2
mov ah,0ah
int 21h

xor cx,cx
mov cl,inpStrLen2

cmp cl, inpStrLen1
jge m2

xor cx,cx
mov cl,inpStrLen1
sub cl,inpStrLen2
mov al, cl

call writeDEC

lea dx,mes1
mov ah,09h
int 21h

jmp finish

m2:

xor cx,cx
mov cl,inpStrLen1
sub cl,inpStrLen2
mov al,cl

call writeDEC



lea dx,mes2
mov ah,09h
int 21h


finish: mov ax,4c00h
int 21h

writeDEC proc

push ax
push bx
push cx
push dx

xor cx, cx
mov bx, 10

next_digit:
xor dx, dx
div bx
push dx
inc cx
or ax, ax
jnz next_digit

next_char:
pop ax
add al, '0'
int 29h
loop next_char

pop dx
pop cx
pop bx
pop ax
ret
writeDEC endp

code ends
end start


по-видимому, что-то с регистрами напутал...или стек?
volvo
Ты просто забыл кое что (например, очистить AX перед занесением в AL разности длин... Ну, младший байт занесется,а то, что было в старшем - останется... И чего ты напечатаешь тогда?), и ошибся при вычислении разности длин в нижнем фрагменте, там надо из второй длины вычитать первую, а ты 2 раза сделал одно и то же... Читай комментарии...


; ТУТ был ввод двух строк, с ним все правильно...


; сначала делаешь перевод строки, иначе число напечатается
; в начале той же строки, где был курсор
lea dx, outstr
mov ah, 09h
int 21h

xor ax, ax ; вот ЭТОГО у тебя вообще не было !!!
xor cx, cx

mov cl, inpStrLen2
cmp cl, inpStrLen1
jge m2 ; вторая строка длиннее

xor cx, cx
mov cl, inpStrLen1 ; от первой
sub cl, inpStrLen2 ; отнимаем вторую
mov al, cl
call writeDEC

lea dx,mes1
mov ah, 09h
int 21h

jmp finish

m2:
xor cx, cx
mov cl, inpStrLen2 ; от второй
sub cl, inpStrLen1 ; отнимаем первую !!!
mov al, cl
call writeDEC

lea dx,mes2
mov ah, 09h
int 21h

finish:
mov ax,4c00h
int 21h
Rocket
Цитата(volvo @ 11.12.2008 1:39) *
Ты просто забыл кое что (например, очистить AX перед занесением в AL разности длин... Ну, младший байт занесется,а то, что было в старшем - останется... И чего ты напечатаешь тогда?), и ошибся при вычислении разности длин в нижнем фрагменте, там надо из второй длины вычитать первую, а ты 2 раза сделал одно и то же... Читай комментарии...

Большое человеческое спасибо! good.gif
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.