Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

RFpro.ru: Ассемблер? Это просто! Учимся программировать


РАССЫЛКИ ПОРТАЛА RFPRO.RU

Лучшие эксперты по данной тематике

Асмик Гаряка
Статус: Советник
Рейтинг: 11125
∙ повысить рейтинг »
Коцюрбенко Алексей aka Жерар
Статус: Советник
Рейтинг: 5020
∙ повысить рейтинг »
Куликов Роман Евгеньевич
Статус: 1-й класс
Рейтинг: 0
∙ повысить рейтинг »

/ КОМПЬЮТЕРЫ И СОФТ / Программирование / Assembler (Ассемблер)

Номер выпуска:1574
Дата выхода:18.12.2015, 01:21
Администратор рассылки:Лысков Игорь Витальевич (Старший модератор)
Подписчиков / экспертов:17 / 7
Вопросов / ответов:1 / 1

Консультация # 188411: Здравствуйте, уважаемые эксперты! Прошу вас ответить на следующий вопрос: По запросу программы пользователь вводит с клавиатуры два целых четырехзначных положительных десятичных числа, разделённых знаком операции + или - Программа выводит на экран результат операции в двух системах счисления : в десятичной и бинарной (в дополнительном коде).<...


Консультация # 188411:

Здравствуйте, уважаемые эксперты! Прошу вас ответить на следующий вопрос:
По запросу программы пользователь вводит с клавиатуры два целых четырехзначных положительных десятичных числа, разделённых знаком операции + или -
Программа выводит на экран результат операции в двух системах счисления : в десятичной и бинарной (в дополнительном коде).

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


Ассемблер: Nasm

Спасибо.

Дата отправки: 13.12.2015, 00:45
Вопрос задал: surikalex007456 (Посетитель)
Всего ответов: 1
Страница онлайн-консультации »


Консультирует Лысков Игорь Витальевич (Старший модератор):

Здравствуйте, surikalex007456!
Вот и программа. Работает как с положительными, так и с отрицательными числами
Комментариев более, чем достаточно. Вникайте...

Код (Assembler):
format PE console

include 'win32ax.inc'

code

;функция преобразует строку в число
;первые пробелы пропускаются
;ввод заканчивается любой нецифрой
;параметры:
;esi - адрес строки
;ecx - длина строки
;число возвращается в eax
proc	atoi uses edi ebx
	mov		ebx, 1			;знак числа, считаем, что положительное
	mov		edi, 10 		;будем умножать на 10
	xor		edx, edx		;здесь накапливаем число
first_spaces:				;цикл пропуска первых пробелов
	lodsb					;читаем символ из [esi], esi++
	dec		ecx				;уменьшаем счетчик
	jl		.atoi_ret		;строка кончилась
	cmp		al, ' ' 		;первые пробелы
	je		.first_spaces	; пропускаем

	cmp		al, '-' 		;встретили минус?
	jne		.atoi_next
	neg		ebx		 		;ebx = -1, отрицательное число
	lodsb					;читаем следующий символ
	dec		ecx				;уменьшаем счетчик
	jl		.atoi_ret		;строка кончилась

atoi_next:					;цикл обработки цифр
	cmp		al, '0' 		;проверяем на цифру
	jl		.atoi_ret
	cmp		al, '9'
	jg		.atoi_ret

	imul	edx, edi		;умножаем старшие разряды на 10
	and		eax, 0x0f		;и добавим
	add		edx, eax		; новый разряд
	lodsb					;читаем следующий символ
	dec		ecx				;счетчик
	jge    .atoi_next		;и на повтор

atoi_ret:
	dec		esi				;сдвинем указатель на предыдущий символ 
							; для дальнейшего анализа
	inc		ecx				;подправим и счетчик
	mov		eax, edx		;вернем число
	imul	eax, ebx		;учтем знак числа
	ret
endp

;функция анализирует символ операции
;параметры:
;esi - адрес строки
;ecx - длина строки
;код операции возвращается в eax и C=0
;если символ операции неверный, то вернет C=1
proc	GetOp
	lodsb					;читаем символ
	dec		ecx				;счетчик
	jl		.error
	cmp		al, ' ' 		;пробелы игнорируем
	je		GetOp
	cmp		al, '-' 		;есть минус
	je		.minus
	cmp		al, '+' 		;плюс
	jne		.error
	xor		eax, eax		;для плюса возвращаем 0
	clc
	ret
minus:
	mov		eax, 1			;для минуса - 1
	clc
	ret
 .error:
	stc
	ret
endp

;функция парсит введенную строку и вычисляет операцию
;параметры:
;esi - адрес строки
;ecx - длина строки
;результат возвращается в eax и в С
proc	CalcCommand
	call	atoi			;получаем первое число
	mov		edi, eax		;сохраним в edi

	call	GetOp			;вводим код операции
	jc		.return 		;ошибка?
	mov		ebx, eax		;сохраняем в ebx

	call	atoi			;вводим второе число
							;проверим на корректность данных
	cmp		byte [esi], 0dh ;мы должны выйти из анализа либо по 0dh
	je		.test_op
	cmp		byte [esi], ' ' ;либо по пробелу
	stc						;вдруг ошибка!
	jne		.return 		;все остальное - ошибка формата!
							;все ок!
test_op:					;проверяем код операции
	xchg	eax, edi		;поменяем местами операнды
	test	ebx, ebx		;0 - плюс
	jz		.op_add
							;1 - минус
op_sub:
	sub		eax, edi
	jmp		.ret_ok
op_add:
	add		eax, edi
ret_ok:
	clc
return:
	ret
endp

;функция преобразования числа в строку
;параметры:
;edi - адрес строки
;eax - число
proc itoa
   test 	eax, eax			;отрицательное?
   jge		.positive
   neg		eax					;модуль числа
   mov		byte [edi], '-' 	;выводим знак минуса
   inc		edi
positive:						;собственно преобразование
   xor		ecx, ecx			;счетчик цифр
	mov		esi, 10 			;будем делить на 10
div_loop:						;цикл формирования десятичных разрядов
	xor		edx, edx			;подготавливаемся к делению
	div		esi					;eax - частное edx:eax/esi, edx - остаток
	push	edx					;остаток - очередной разряд - сохраняем в стеке
	inc		ecx					;считаем
	test	eax, eax			;все разряды?
	jne		.div_loop			;нет - на повтор
digits_loop:					;цикл вывода цифр, извлекаем из стека в обратном порядке
	pop		eax					;очередной разряд
   or		al, '0' 			;делаем символ-цифру
	stosb						;выводдим
	loop	.digits_loop		;по всем
	ret
endp

;функция формирования двоичной строки
;параметры:
;eвi - адрес строки
;eax - число
proc	form_bin
	mov		edx, eax			;перенесем число для удовства в edx
	mov		ecx, 32 			;32 бита
shift_loop:					;цикл по битам
	mov		al, '0' 			;al = '0'
	shl		edx, 1				;C - очередной бит
	adc		al, 0				;al = '0' + 0 + C ('0' или '1')
	stosb
	loop	.shift_loop			;по всем
	mov		ax, 'b' 			;строку закончим 'b' с нулем! (ah=0)
	stosw
	ret
endp

;---------------------------------------------------
;Начало
start:
;получим handle консоли для вывода
	invoke	GetStdHandle, STD_OUTPUT_HANDLE
	cmp		eax,-1
	je		.console_error_exit
	mov		[hStdOut], eax		;сохраним

;получим handle консоли для ввода
	invoke	GetStdHandle, STD_INPUT_HANDLE
	cmp		eax,-1
	je		.console_error_exit
	mov		[hStdIn], eax		;сохраним

;выводим приглашение для ввода строки
	invoke	WriteConsole, [hStdOut], szMessage, MsgLen, dwWritten, 0
;вводим строку в буфер sCommand, длина введенной строки будет в dwReaded
	invoke	ReadFile, [hStdIn], sCommand, 64, dwReaded, 0

;обрабатываем строку
	lea		esi, [sCommand]
	mov		ecx, [dwReaded]
	call	CalcCommand
	jc		.error_exit			;ошибка?

;формируем результат, число в eax
	lea		edi, [sCommand] 	;сюда запишем строку результат
	push	eax					;сохраним число для вывода двоичной стоки
	call	itoa				;преобразуем в строку-знаковое десятичное число
	mov		ax, ', '			;отделим запятой с пробелом
	stosw
	pop		eax					;восстановим полученное число
	call	form_bin			;формируем двоичную строку

;выведем полученнфй результат, начиная с пояснительной строки
;третьим параметром передается результат вызова подсчета длины строки
;invoke lstrlen, sResult
	invoke	WriteConsole, [hStdOut], sResult, invoke lstrlen, sResult, dwWritten, 0
	jmp	short .wait_enter

error_exit:
	invoke	WriteConsole, [hStdOut], szError, ErrLen, dwWritten, 0
	
wait_enter:
;ждем нажатие на enter, чтобы не убежало с экрана
	invoke	ReadFile, [hStdIn], sCommand, 1, dwReaded, 0
	jmp	short .exit
	
console_error_exit:
;При ошибке получения handle консоли выведем MessageBox, в заголовке путь и имя программы
	invoke	MessageBox,HWND_DESKTOP,"Error occured",invoke GetCommandLine,MB_OK

exit:
	invoke	ExitProcess,0

data

hStdOut 	dd	-1
hStdIn		dd	-1

szMessage	db "Enter operation: "
MsgLen = $-szMessage

szError 	db	"Incorrect command!"
ErrLen = $-szError

dwWritten	dd	0
dwReaded	dd	0

sResult 	db	"Result: "
sCommand	db	64 dup(?)

end start

Консультировал: Лысков Игорь Витальевич (Старший модератор)
Дата отправки: 15.12.2015, 13:45

5
нет комментария
-----
Дата оценки: 15.12.2015, 21:36

Рейтинг ответа:

НЕ одобряю +1 одобряю!


Оценить выпуск | Задать вопрос экспертам

главная страница  |  стать участником  |  получить консультацию
техническая поддержка  |  восстановить логин/пароль

Дорогой читатель!
Команда портала RFPRO.RU благодарит Вас за то, что Вы пользуетесь нашими услугами. Вы только что прочли очередной выпуск рассылки. Мы старались. Пожалуйста, оцените его. Если совет помог Вам, если Вам понравился ответ, Вы можете поблагодарить автора - для этого в каждом ответе есть специальные ссылки. Вы можете оставить отзыв о работе портале. Нам очень важно знать Ваше мнение. Вы можете поближе познакомиться с жизнью портала, посетив наш форум, почитав журнал, который издают наши эксперты. Если у Вас есть желание помочь людям, поделиться своими знаниями, Вы можете зарегистрироваться экспертом. Заходите - у нас интересно!
МЫ РАБОТАЕМ ДЛЯ ВАС!


В избранное