TITLE Рубежный контроль - пробный вариант - Объединение строк -  7 ошибок - решение
COMMENT +
 Мы оставим только те переводы строк, которые следуют за точкой.
 Это тренировочный вариант контрольной работы. В файле Ex.asm находится программа с ошибками. 
 В ней восклицательными знаками отмечены места, в которых необходимо вставить какие-либо ассемблерные команды.
 Учтите, что в рубежном контроле не будет намёков на то, где находятся ошибки, а будет лишь дано их количество
 Попробуйте сделать этот вариант самостоятельно, при необходимости обращайтесь в файл Ex-sol.asm, где указаны ошибки и их объяснение

 Результат выполнения программы должен выглядеть так:


I've
hurt
myself
today.
to
see
if
I
still
feel.
I've hurt myself today.
to see if I still feel.


Разумеется, нужно уметь объяснить суть каждой ошибки.
Повторите темы:
- Команды работы со строками
- Прерывания
Необходимую теоретическую информацию вы можете найти в условии к пятой лабораторной работе.

+

.model small, stdcall
.stack 128




.data
Input BYTE "I've",0Ah, 0Dh,"hurt",
0Ah, 0Dh,"myself",0Ah, 0Dh,"today.",
0Ah, 0Dh,"to",0Ah, 0Dh,"see",
0Ah, 0Dh,"if",0Ah, 0Dh,"I",
0Ah, 0Dh,"still",0Ah, 0Dh,
"feel.$",0h

Output BYTE (LENGTHOF Input) DUP(?)
.code

main PROC
mov ax, @data
mov ds, ax
mov es, ax		;! Все команды типа lodsb, stosb работают со смещениями относительно ES, а не DS.
			;! они не будут работать так, как вы ожидаете, если вы не зададите в ES необходимое вам значение. 
			;! В данном случае оно совпадает со значением DS

cld	 		;! Очищаем флаг направления, так как мы должны проходить по адресам от меньших к большим

mov si, OFFSET Input 
mov cx, -1

cycle:			; Подсчёт длины строки
inc cx			; Увеличиваем счётчик
lodsb 			; Загружаем символ
test al, al		; Выполняем логическое И символа с самим собой и 
			; устанавливаем флаги соответственно результату, не записывая его в память
			; ZF будет установлен только если al =0	
jnz cycle		; 


mov si, OFFSET Input	
mov di, OFFSET Output

mov dl, 00h		; dl=1 означает, что текущий символ следует за точкой
copy:			; Копируем с необходимыми заменами
	lodsb		; Загружаем символ
	cmp al, '.'	; Это пробел?
	je SetFlag	; Да - переходим на SetFlag
	cmp al, 0Ah	; Нет - это символ 0Ah?
			;!je Store	; Нет, просто запишем его в выходную строку
					; Команда cmp выполняет вычитание одного операнда из другого, 
					; а затем устанавливает флаги в зависимости от результата. При этом результат не записывается в память
					; Соответственно, если операнды равны, то установится флаг ZF. Команды JE и JZ эквивалентны

	jne Store	; Нет, просто запишем его в выходную строку
	test dl, 01h	; Да - это символ 0Ah. Была ли точка перед ним? (установлен ли признак - регистр dl)
	jz DeleteNl	; Нет - точки не было. Пропустим 0Ah и символ, следующий за ним
	or dl,dl	;! Да - точка была. Сбросим признак того, что предыдущий символ - точка
	xor dl, dl	;! Да - точка была. Сбросим признак того, что предыдущий символ - точка. Or не сбросит его, а оставит неизменным
	jmp Store	; Запишем символ в выходную строку
 
DeleteNl:		; здесь мы пропускаем перевод строки
	lodsb		; Очевидно, мы уже загрузили один символ из пары символов,переводящих строку (0Ah и 0Dh) - загрузим и второй
			; Указатель (si) автоматически переместится на одну позицию дальше по строке
	mov al, 20h	; Запишем в al пробел (мы заменим перевод строки пробелом, иначе слова сольются)
	dec cx		;! Уменьшим на 1 cx - оставшееся количество символов  в строке
			;! Если мы не уменьшим на 1 значение CX, то мы захватим лишние символы после конца строчки
	jmp Store	; Запишем пробел

  SetFlag:		; Здесь мы установим признак того, что сейчас мы прочитали точку
	or dl, 01h	; младший бит устанавливается в 1
  Store:
			;!stosb dl - никакие команды со строками не нуждаются в явно заданных операндах. 
			;!Если же они будут заданы, то в любом случае будут использоваться регистры si/di и al/ax, или же ассемблер выдаст ошибку компиляции.
	stosb		; Запись символа из al в строку

loop copy		;

call newline		; Переведём строку

mov ah, 09h		; Вывод исходной строки с помощью прерывания DOS - до символа доллара
mov dx, OFFSET Input	; 
int 21h

call newline

mov dx, OFFSET Output	;Вывод модифицированной строки 
int 21h			

call newline

mov ax, 4c00h 		;! Корректное завершение программы с кодом 0.
int 21h			;! Без этого прерывания программа не будет завершена и/или корректно выполнена.

main ENDP



newline PROC USES ax dx
mov ah, 02h
mov dl, 0Ah
int 21h
mov dl, 0Dh
int 21h

ret
newline ENDP

END main