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

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


Ассемблер: Nasm

Спасибо.

Обсуждение

давно
Посетитель
7438
7205
13.12.2015, 01:09
общий
Адресаты:
Здравствуйте!
А Вы сами как-то пробовали написать программу?
Давайте будем вместе писать. Покажите, что у Вас есть. А мы подправим, добавим.
Будем огромная польза именно для Вас. Поверьте, писать на языке Ассемблера легко и просто.
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
399279
5
13.12.2015, 01:22
общий
Код:
section .data
str1 db 'Here is string 1', 0xA

global _start

_start:
mov ah,8
int 21h ;принимаем строку


Компилирую nasm'ом, выполняю .com в Debug

Только начал и уже застыл, при выполнении программы возвращается сообщение "Переполнение деления".
Я только за совместное решение!

Писать на любом языке легко и просто, трудно начать!
давно
Посетитель
7438
7205
13.12.2015, 01:50
общий
Адресаты:
Пока в том, что приведено, я не вижу программы...
1) текст исходника досовского com-а под nasm должен начинать со строк

use16
org 100h

2) Зачем в начале строка?
3) функция 8 вводит всего один символ, для ввода строки нужна функция 0ah,
для которой в регистре dx надо передать адрес параметра, первый байт - максимальный размер,
второй байт - 0, в нем будет длина принятой строки, и дальше - буфер для принятой строки
Например,
buf db 128,0,128 dup(?)
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
13.12.2015, 01:56
общий
Адресаты:
Могу дать немного другую программку, которая вводит два числа
умножает их сложением и выводит результат
Думаю, можете взять для себя многое.
Потом покажете, что получилось
[code lang=asm h=200]
;макро ввода строки с консоли
;параметры:
;str - адрес буфера, куда введем строку
;два байта перед адресом str указывают на максимальный размер буфера
;и на длину реально считанной строки, в конце буфера будет код 0dh
;второй параметр - имя строки приглашения
macro GETSTR str, sTitle
{
lea dx, [sTitle] ;пригласим ввести строку
PRINT ;выводим на экран
lea dx, [str-2] ;адрес параметра для функции 0ah
mov ah, 0ah ;вводим строку
int 21h
}
;макро преобразования строки в число
;параметр str - адрес строки
;результат в AX
macro GETNUM str
{
local .loop
local .end
lea si, [str] ;адрес строки
xor cx, cx ;здесь будем накапливать число
mov bx, 10 ;будем умножать на 10
.loop: ;цикл преобразования
lodsb ;читаем в AL байт по адресу ds:[si] с автоинкриментом SI
cmp al, 0x0d ;строка заканчивается кодом 0dh
je .end ;если встретили - строка закончилась
cmp al, '0' ;проверим на цифру
jl .loop ;нецифры игнорируем
cmp al, '9'
jg .loop
and ax, 000fh ;превратим символ цифры 30h-39h в число 0-9
xchg ax, cx ;ax = старшим разрядам, cx=очередному разряду
mul bx ;dx:ax = предыдущим разрядам числа, умноженному на 10
add cx, ax ;добавляем чередной разряд
jmp .loop ;и на повтор
.end: ;число преобразовано
mov ax, cx ;результат в AX
}
;макро собственно умножения, которое заменяется сложением
;умножается два числа в регистрах AX и DI
;будем складывать число AX DI раз
;результат в AX
macro CALCSUM
{
local .loop
local .result_0
local .end
cmp di, 0 ;проверим счетчик цикла на 0
je .result_0 ;в этом случае результат будет = 0
mov bx, ax ;запомним первое число
.loop:
dec di ;один раз число у нас уже сложено!
je .end ;поэтому начинаем с вычитания 1
add ax, bx ;складываем, пока второе число не 0
jmp .loop
.result_0:
mov ax, 0 ;второе число 0 - результат = 0
.end:
}
;макро формирования числовой строки
;параметр - адрес буфера
;число в регистре AX
macro FORMSTRING str
{
local .div_loop
local .form_loop
mov bx, 10 ;будем делить на 10
mov cx, 0 ;счетчик цифр
.div_loop: ;цикл получения десятичных разрядов
mov dx, 0 ;подготавливаемся к делению
div bx ;делим DX:AX/BX
push dx ;сохраняем остаток от деления (очередную цифру!) в стеке
inc cx ;и считаем!
test ax, ax ;дошли до нуля?
jne .div_loop ;нет - продолжаем
lea di, [str] ;адрес, куда запишем строку цифр
.form_loop: ;цикл формирования числовой строки
pop ax ;разряды извлекаем из стека в обратном порядке!
or al, '0' ;делаем из числа символ цифры
stosb ;сохраняем в буфере es:[di] с автоинкриментом di
loop .form_loop ;по всем разрядом из стека
mov al, '$' ;закрываем строку символом доллара для функции 9h
stosb
}
;макро вывода строки, адрес в dx
macro PRINT
{
mov ah, 9 ;выводим
int 21h
}
;макро ожидания нажатия на клавишу
macro WAITKEY
{
mov ah, 0 ;ждем нажатие на клавишу
int 16h
}
use16
org 100h
GETSTR string, sEnterX ;вводим число Х с консоли
GETNUM string ;преобразуем в число
mov di, ax ;сохраним число в DI
GETSTR string, sEnterY ;вводим число Y с консоли
GETNUM string ;преобразуем в число
CALCSUM ;умножаем AX=AX*DI
FORMSTRING sNum ;преобразуем число AX в строку
lea dx, [sResult] ;адрес строки результата, начиная с заголовка
PRINT ;выводим сообщение на экран
WAITKEY ;ожидаем нажатие на клавишу
mov ax, 4c00h
int 21h ;выход из программы
sEnterX db "Enter number X: $"
sEnterY db 0dh,0ah,"Enter number Y: $"
db 128
db 0
string db 128 dup(?)
sResult db 0dh,0ah,"Summa = "
sNum db 8 dup (?)
[/code]
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
13.12.2015, 17:13
общий
Адресаты:
Ну что там, получается?
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
399279
5
13.12.2015, 20:41
общий
Пытаюсь переделать под себя экземпл WinAsm'а но не выходит
Видать c типами данных надо разбираться
Код:

; This is a sample Console program, author unknown.
; This program will request input for a string and print out the string reversed in upper case.

Include Console.Inc


.CODE

Start:

Invoke Main
Invoke ExitProcess,0

Main Proc
XOR EAX,EAX
Get_Input Msg1, inbuf1
Get_Input Msg1, znak
Get_Input Msg1, inbuf2

Invoke ReverseText,Offset inbuf1,Offset inbuf2
;Invoke Ucase,Offset textbuf2
;Invoke ClearScreen
;Print_Text Msg2
;Print_Text inbuf1
Print_Text Msg3
Print_Text inbuf2
Print_Text CRLF
Get_Input Msg4,inbuf1
RET
Main EndP

; Reverses source string to destination string
ReverseText Proc Uses EBX,_src:PTR,_dst:PTR
MOV ECX,_src ; Move source string pointer into ECX (cannot do memory indirection fromm emory operand)
MOV EDX,_dst ; Move destination string pointer into EDX(cannot do memory indirection fromm emory operand)
;MOV BYTE PTR[EDX+EAX],NULL ; Set the end of the string
ADD EDX,ECX ; When index is zero exit
RET
ReverseText EndP

; Gets the length of a string(not including the NULL terminator)
GetStrLen Proc ,_str:PTR
MOV ECX,_str ; Move source pointer to ECX
MOV EAX,-1 ; Start of at -1 so we can build a faster loop
next_char:
INC EAX ; EAX==NULL
CMP BYTE PTR[ECX+EAX],NULL
JNE next_char ; If BYTE is not equal to NULL process next .
RET ; Returns string length in EAX
GetStrLen EndP

End Start
давно
Посетитель
7438
7205
13.12.2015, 23:13
общий
Адресаты:
Для начала надо определиться, под ДОС или Windows (консоль) пишем программу?
Фраза "выполняю .com в Debug" означает, что под ДОС
А последний фрагмент - под Windows
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
399279
5
14.12.2015, 13:17
общий
Под Win переиграли всё таки.
давно
Посетитель
7438
7205
14.12.2015, 15:11
общий
Адресаты:
Лады, нарисую, только чуток позже. Занят несколько...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
15.12.2015, 13:45
общий
это ответ
Здравствуйте, surikalex007456!
Вот и программа. Работает как с положительными, так и с отрицательными числами
Комментариев более, чем достаточно. Вникайте...
[code lang=asm h=200]
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
[/code]
5
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
15.12.2015, 13:49
общий
15.12.2015, 13:52
Адресаты:
Отправил ответ и увидел, что надо было под nasm.
Программа написана под fasm
Что будем делать?
Предлагаю оставить на самостоятельную работу
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
15.12.2015, 14:26
общий
Адресаты:
Хм, WinAsm, насколько я знаю, писан на Masm32...
Так каким ассемблером Вы пользуетесь?
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
399279
5
15.12.2015, 21:35
общий
15.12.2015, 21:35
Многие перепробовал, остановился на WinAsm
А Вы какой ассемблер посоветовали? Или среду
Спасибо за Ваш ответ и помощь!
давно
Посетитель
7438
7205
16.12.2015, 10:26
общий
Адресаты:
Честно говоря, это дело предпочтения каждого, "на вкус и цвет товарища нет"
Лично я пишу, под ДОС - на TASM-е, под Windows - в основном - на MASM-е (плюс - много информации),
иногда - на FASM-е (попадаются специфические задачи, для которых FASM - самое то)
Сами тексты - в любом простом текстовом редакторе.
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Форма ответа