Advertisement
VladimirKostovsky

Assembler_lab2_sub

Dec 2nd, 2023
1,184
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. .386
  2. .MODEL  FLAT, STDCALL
  3. EXTERN  GetStdHandle@4    : PROC ; Получение дескриптора.
  4. EXTERN  WriteConsoleA@20  : PROC ; Вывод в консоль.
  5. EXTERN  CharToOemA@8      : PROC ; Строку в OEM кодировку.
  6. EXTERN  ReadConsoleA@20   : PROC ; Ввод с консоли.
  7. EXTERN  ExitProcess@4     : PROC ; Функция выхода из программы.
  8. EXTERN  lstrlenA@4        :   PROC ; Функция определения длины строки.
  9.  
  10. .DATA  
  11.     STR1 DB "Введите первое число, а затем второе в шестнадцатеричной системе: ", 10, 0     
  12.     STR2 DB "Результат разности в десятичной системе: ", 0
  13.     STR_ERR DB "Ошибка. Нужно не менее 3-х знаков и не слишком большие числа.", 0   
  14.     STR3 DQ " "
  15.  
  16.     DIN     DD ?              ; Дескриптор ввода, 4 байта.
  17.     DOUT    DD ?                 ; Дескриптор вывода, 4 байта.
  18.     BUF     DB 200 dup (?) ; Буфер для строк длиной 200 байт.
  19.     LENS    DD ?                 ; Для количества выведенных символов.
  20.     FIRST   DD 0
  21.     SECOND  DD 0
  22.     S_16    DD 16
  23.     F_SIGN  DB 0
  24.     S_SIGN  DB 0
  25.  
  26. .CODE
  27.     START proc
  28.  
  29.     ; Перекодировка STR1.
  30.     MOV EAX, OFFSET STR1
  31.     PUSH EAX                       
  32.     PUSH EAX
  33.     CALL CharToOemA@8 ;
  34.  
  35.     ; Перекодировка STR2.
  36.     MOV EAX, OFFSET STR2
  37.     PUSH EAX
  38.     PUSH EAX
  39.     CALL CharToOemA@8
  40.  
  41.     ; Перекодировка STR_ERR.
  42.     MOV EAX, OFFSET STR_ERR
  43.     PUSH EAX
  44.     PUSH EAX
  45.     CALL CharToOemA@8
  46.  
  47.     ; Помещаем декриптор ввода в DIN.
  48.     PUSH -10                       
  49.     CALL GetStdHandle@4
  50.     MOV DIN, EAX
  51.  
  52.     ; Помещаем декриптор вывода в DOUT.
  53.     PUSH -11
  54.     CALL GetStdHandle@4
  55.     MOV DOUT, EAX
  56.  
  57.     ; Выводим приглашение для ввода на экран консоли.
  58.     PUSH OFFSET STR1
  59.     CALL lstrlenA@4         ; Помещаем в EAX количество символов в строке STR1.
  60.     PUSH 0                  ; Резервный параметр
  61.     PUSH OFFSET LENS        ; Берет адрес строки для вывода действительно выведенных символов (для длины)
  62.     PUSH EAX                ; Объявление временного буфера (сколько символов)
  63.     PUSH OFFSET STR1        ; Берет адрес строки
  64.     PUSH DOUT               ; Указывает на стандартную библиотеку вывода
  65.     CALL WriteConsoleA@20   ; Вызов функции
  66.  
  67.     ; Ввод первого числа.
  68.     PUSH 0                  ; Помещаем 5-й аргумент в стек (резерв).
  69.     PUSH OFFSET LENS        ; Помещаем 4-й аргумент в стек (адрес переменной для количества символов).
  70.     PUSH 200                   ; Помещаем 3-й аргумент в стек (максимальное количество символов).
  71.     PUSH OFFSET BUF         ; Помещаем 2-й аргумент в стек (адрес начала строки для ввода).
  72.     PUSH DIN                ; Помещаем 1-й аргумент в стек (дескриптор ввода).
  73.     CALL ReadConsoleA@20           
  74.  
  75.     ; Перевод из строки в первое число, а также проверка.
  76.     SUB LENS, 2  ; Определяем длину строки без управляющих символов.
  77.     CMP LENS, 3 ; Число должно содержать не меньше 3 знаков.
  78.     JB ERROR
  79.     CMP LENS, 8  ; Число должно содержать не больше 8 знаков.
  80.     JA ERROR
  81.     MOV ECX, LENS
  82.     MOV ESI, OFFSET BUF
  83.     XOR EBX, EBX
  84.     XOR EAX, EAX
  85.  
  86.     ; Проверяем, отрицательно ли первое число.
  87.     MOV BL, [ESI]                      
  88.     CMP BL, '-'
  89.     JNE CONVERT_FIRST    ; Если не минус, то переход сразу к конвертированию.
  90.     SUB LENS, 1         ; Если минус, то уменьшить длину строки на 1.
  91.     MOV ECX, LENS
  92.     MOV F_SIGN, 1       ; Установить флаг отрицательности на 1 (true).
  93.     INC ESI              ; Переход на следующий символ строки (цифру).
  94.  
  95.     CONVERT_FIRST:
  96.         MOV BL, [ESI]
  97.         SUB BL, '0'  ; 0 в ASCII коде = 48
  98.         CMP BL, 10   ;
  99.         JA CHECK_16_1   ; Если цифра больше 9, нужно проверить на принадлежность [A , ... , E]
  100.         SHL EAX, 4         
  101.         ADD EAX, EBX
  102.         INC ESI
  103.         JMP CONTINUE_1
  104.  
  105.         CHECK_16_1:
  106.             SUB BL, 7
  107.             CMP BL, 16  ; если цифра больше 15 (больше F).
  108.             JAE ERROR
  109.             CMP BL, 10  ; если цифра меньше 10 (служебные символы).
  110.             JB ERROR
  111.             SHL EAX, 4
  112.             ADD EAX, EBX
  113.             INC ESI
  114.  
  115.         CONTINUE_1:
  116.     LOOP CONVERT_FIRST
  117.  
  118.     ADD FIRST, EAX
  119.     JC ERROR
  120.  
  121.     CMP F_SIGN, 1 ; Если изначально число отрицательное,
  122.     JNE SIGN_NEG_1                     
  123.     NEG FIRST     ; то умножаем его на -1.
  124.    
  125.     SIGN_NEG_1:
  126.  
  127.     ; Ввод второго числа.
  128.     PUSH 0         
  129.     PUSH OFFSET LENS               
  130.     PUSH 200                       
  131.     PUSH OFFSET BUF                
  132.     PUSH DIN                       
  133.     CALL ReadConsoleA@20       
  134.  
  135.     ; Перевод из строки второго числа и проверки.
  136.     SUB LENS, 2                    
  137.     CMP LENS, 3
  138.     JB ERROR
  139.     CMP LENS, 8
  140.     JA ERROR
  141.     MOV ECX, LENS
  142.     MOV ESI, OFFSET BUF
  143.     XOR EBX, EBX
  144.     XOR EAX, EAX
  145.  
  146.     ; Проверяем отрицательно ли второе число.
  147.     MOV BL, [ESI]                      
  148.     CMP BL, '-'
  149.     JNE CONVERT_SECOND ; Если не минус, то переход к конвертации.
  150.     SUB LENS, 1        ; Если минус, то уменьшить длину строки на 1.
  151.     MOV ECX, LENS
  152.     MOV S_SIGN, 1      ; Установить флаг отрицательности на 1 (true).
  153.     INC ESI            ; Переход на следующий символ строки (цифру).
  154.  
  155.     CONVERT_SECOND:
  156.         MOV BL, [ESI]
  157.         SUB BL, '0'
  158.         CMP BL, 10
  159.         JA CHECK_16_2    ; Если цифра больше 9, нужно проверить на принадлежность [A , ... , E]
  160.         SHL EAX, 4
  161.         ADD EAX, EBX
  162.         INC ESI
  163.         JMP CONTINUE_2
  164.  
  165.         CHECK_16_2:
  166.             SUB BL, 7
  167.             CMP BL, 16   ; Если цифра больше 15 (больше F).
  168.             JAE ERROR
  169.             CMP BL, 10   ; Если цифра меньше 10 (служебный символ).
  170.             JB ERROR
  171.             SHL EAX, 4
  172.             ADD EAX, EBX
  173.             INC ESI
  174.  
  175.         CONTINUE_2:
  176.     LOOP CONVERT_SECOND
  177.  
  178.     ADD SECOND, EAX
  179.     JC ERROR
  180.  
  181.     ; Проверяем необходимость смены знака.
  182.     CMP S_SIGN, 1                      
  183.     JNE SIGN_NEG_2
  184.     NEG SECOND
  185.  
  186.     SIGN_NEG_2:
  187.  
  188.    
  189. ; Вычитание чисел
  190.     MOV S_SIGN, 0    ; Предположение, что число положительное.
  191.     MOV EAX, SECOND
  192.     SUB FIRST, EAX  ; Вычитание.
  193.     CMP FIRST, 0     ; Сверка с нулем.
  194.     JGE SUM_0
  195.     MOV S_SIGN, 1   ; Если отрицательное, поменять знак.
  196.     NEG FIRST
  197.  
  198.     SUM_0:
  199.     ; Перевод десятичного числа в строку.
  200.     XOR EBX, EBX
  201.     XOR EAX, EAX
  202.     MOV ESI, OFFSET STR3
  203.  
  204.     CMP S_SIGN, 0           ; Если результат отрицательный,
  205.     JE SIGN_POS             ; то добавить в строку знак '-'.
  206.     MOV AX, 45              ; 45 - код знака '-'.
  207.     MOV [ESI], AX
  208.     INC ESI
  209.  
  210.     SIGN_POS:
  211.         XOR CX,CX           ; Количество символов, обнуляется.
  212.         MOV EBX, 10         ; Делитель в 16битовый регистр.
  213.         MOV EAX, FIRST      ; EDX:EAX <- FIRST.
  214.         XOR EDX, EDX
  215.  
  216.  
  217.     JMP TO_STRING
  218.  
  219.     ; Выводим результат.
  220.     OUTPUT:
  221.         PUSH OFFSET STR2   
  222.         CALL lstrlenA@4      
  223.         PUSH 0               
  224.         PUSH OFFSET LENS     
  225.         PUSH EAX             
  226.         PUSH OFFSET STR2     
  227.         PUSH DOUT            
  228.         CALL WriteConsoleA@20
  229.  
  230.         PUSH OFFSET STR3   
  231.         CALL lstrlenA@4
  232.         PUSH 0
  233.         PUSH OFFSET LENS
  234.         PUSH EAX  
  235.         PUSH OFFSET STR3
  236.         PUSH DOUT
  237.         CALL WriteConsoleA@20
  238.  
  239.         PUSH 0
  240.         CALL ExitProcess@4 ; Выход
  241.  
  242.     ; В случае ошибки.
  243.     ERROR:
  244.         PUSH OFFSET STR_ERR
  245.         CALL lstrlenA@4
  246.         PUSH 0
  247.         PUSH OFFSET LENS
  248.         PUSH EAX
  249.         PUSH OFFSET STR_ERR
  250.         PUSH DOUT
  251.         CALL WriteConsoleA@20
  252.  
  253.         PUSH 0
  254.         CALL ExitProcess@4 ; выход
  255.  
  256.     START ENDP
  257.     END START
  258.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement