Search code examples
stringassemblyx86masm32

Assembly x86 Date to Number - Breaking a string into smaller sections


I'm actually looking to be pointed in the right direction on an issue.

I'm looking to convert a date in x86 Assembly from the format "DD-MMM-YYYY" to a unique number so that it can be bubble sorted later and eventually converted back.

So, when I have a string input ie: .data inDate dw "08-SEP-1993"

And I want to split it up to

day = "08"
month = "SEP"
year = "1993"

So that I can process it further (I'll be converting SEP to "7", ect.)

So my question is what is a simple, efficient way to break the date down (code-wise)? I know I'll need to convert the date format to allow for sorting, but I'm new to Assembly so I'm not positive how to break the string up so I can convert it.

Also, as a second question, how would you convert a number from the string to an actual numerical value?

Thanks!

NOTE: I suppose it should be noted I'm using masm32


Solution

  • Next little program was made with EMU8086 (16 bits), it captures numbers from keyboard as strings, convert them to numeric to compare, and finally it converts a number to string to display. Notice the numbers are captured with 0AH, which requieres a 3-level variable "str". The conversion procedures that you need are at the bottom of the code (string2number and number2string).

    .model small
    
    .stack 100h
    
    .data
    
    counter dw ?
    
    msj1    db 'Enter a number: $'
    msj2    db 'The highest number is: $'
    break   db 13,10,'$'
    
    str     db 6                ;MAX NUMBER OF CHARACTERS ALLOWED (4).
            db ?                ;NUMBER OF CHARACTERS ENTERED BY USER.
            db 6 dup (?)        ;CHARACTERS ENTERED BY USER. 
    
    highest dw 0        
    
    buffer  db 6 dup(?)
    
    .code
    
    ;INITIALIZE DATA SEGMENT.
      mov  ax, @data
      mov  ds, ax
    
    ;-----------------------------------------
    ;CAPTURE 5 NUMBERS AND DETERMINE THE HIGHEST.
    
      mov  counter, 5           ;HOW MANY NUMBERS TO CAPTURE.
    enter_numbers:                          
    
    ;DISPLAY MESSAGE.
      mov  dx, offset msj1
      call printf
    
    ;CAPTURE NUMBER AS STRING.
      mov  dx, offset str
      call scanf
    
    ;DISPLAY LINE BREAK.
      mov  dx, offset break
      call printf
    
    ;CONVERT CAPTURED NUMBER FROM STRING TO NUMERIC.
      mov  si, offset str       ;PARAMETER (STRING TO CONVERT).
      call string2number        ;NUMBER RETURNS IN BX.
    
    ;CHECK IF CAPTURED NUMBER IS THE HIGHEST.
      cmp  highest, bx  
      jae  ignore               ;IF (HIGHEST >= BX) IGNORE NUMBER.
    ;IF NO JUMP TO "IGNORE", CURRENT NUMBER IS HIGHER THAN "HIGHEST".  
      mov  highest, bx          ;CURRENT NUMBER IS THE HIGHEST.
    
    ignore:  
    ;CHECK IF WE HAVE CAPTURED 5 NUMBERS ALREADY.
      dec  counter
      jnz  enter_numbers
    
    ;-----------------------------------------
    ;DISPLAY HIGHEST NUMBER.
    
    ;FIRST, FILL BUFFER WITH '$' (NECESSARY TO DISPLAY).
      mov  si, offset buffer
      call dollars
    
    ;SECOND, CONVERT HIGHEST NUMBER TO STRING.              
      mov  ax, highest
      mov  si, offset buffer
      call number2string
    
    ;THIRD, DISPLAY STRING.
      mov  dx, offset msj2
      call printf
      mov  dx, offset buffer
      call printf    
    
    ;FINISH PROGRAM.
      mov  ax, 4c00h
      int  21h
    
    ;-----------------------------------------
    ;PARAMETER : DX POINTING TO '$' FINISHED STRING.
    proc printf
      mov  ah, 9
      int  21h
      ret
    endp    
    
    ;-----------------------------------------
    ;PARAMETER : DX POINTING TO BUFFER TO STORE STRING.
    proc scanf
      mov  ah, 0Ah
      int  21h
      ret
    endp    
    
    ;------------------------------------------
    ;CONVERT STRING TO NUMBER.
    ;PARAMETER : SI POINTING TO CAPTURED STRING.
    ;RETURN    : NUMBER IN BX.
    
    proc string2number
    ;MAKE SI TO POINT TO THE LEAST SIGNIFICANT DIGIT.
      inc  si ;POINTS TO THE NUMBER OF CHARACTERS ENTERED.
      mov  cl, [ si ] ;NUMBER OF CHARACTERS ENTERED.                                         
      mov  ch, 0 ;CLEAR CH, NOW CX==CL.
      add  si, cx ;NOW SI POINTS TO LEAST SIGNIFICANT DIGIT.
    ;CONVERT STRING.
      mov  bx, 0
      mov  bp, 1 ;MULTIPLE OF 10 TO MULTIPLY EVERY DIGIT.
    repeat:         
    ;CONVERT CHARACTER.                    
      mov  al, [ si ] ;CHARACTER TO PROCESS.
      sub  al, 48 ;CONVERT ASCII CHARACTER TO DIGIT.
      mov  ah, 0 ;CLEAR AH, NOW AX==AL.
      mul  bp ;AX*BP = DX:AX.
      add  bx, ax ;ADD RESULT TO BX. 
    ;INCREASE MULTIPLE OF 10 (1, 10, 100...).
      mov  ax, bp
      mov  bp, 10
      mul  bp ;AX*10 = DX:AX.
      mov  bp, ax ;NEW MULTIPLE OF 10.  
    ;CHECK IF WE HAVE FINISHED.
      dec  si ;NEXT DIGIT TO PROCESS.
      loop repeat ;COUNTER CX-1, IF NOT ZERO, REPEAT.
    
      ret 
    endp    
    
    ;------------------------------------------
    ;FILLS VARIABLE WITH '$'.
    ;USED BEFORE CONVERT NUMBERS TO STRING, BECAUSE
    ;THE STRING WILL BE DISPLAYED.
    ;PARAMETER : SI = POINTING TO STRING TO FILL.
    
    proc dollars                 
      mov  cx, 6
    six_dollars:      
      mov  bl, '$'
      mov  [ si ], bl
      inc  si
      loop six_dollars
    
      ret
    endp  
    
    ;------------------------------------------
    ;CONVERT A NUMBER IN STRING.
    ;ALGORITHM : EXTRACT DIGITS ONE BY ONE, STORE
    ;THEM IN STACK, THEN EXTRACT THEM IN REVERSE
    ;ORDER TO CONSTRUCT STRING (STR).
    ;PARAMETERS : AX = NUMBER TO CONVERT.
    ;             SI = POINTING WHERE TO STORE STRING.
    
    proc number2string
      mov  bx, 10 ;DIGITS ARE EXTRACTED DIVIDING BY 10.
      mov  cx, 0 ;COUNTER FOR EXTRACTED DIGITS.
    cycle1:       
      mov  dx, 0 ;NECESSARY TO DIVIDE BY BX.
      div  bx ;DX:AX / 10 = AX:QUOTIENT DX:REMAINDER.
      push dx ;PRESERVE DIGIT EXTRACTED FOR LATER.
      inc  cx ;INCREASE COUNTER FOR EVERY DIGIT EXTRACTED.
      cmp  ax, 0  ;IF NUMBER IS
      jne  cycle1 ;NOT ZERO, LOOP. 
    ;NOW RETRIEVE PUSHED DIGITS.
    cycle2:  
      pop  dx        
      add  dl, 48 ;CONVERT DIGIT TO CHARACTER.
      mov  [ si ], dl
      inc  si
      loop cycle2  
    
      ret
    endp  
    

    Now the 32 bits version. Next is a little program that assigns to EAX a big number, convert it to string and convert it back to numeric, here it is:

    .model small
    
    .586
    
    .stack 100h
    
    .data
    
    msj1   db 13,10,'Original EAX = $'
    msj2   db 13,10,'Flipped  EAX = $'
    msj3   db 13,10,'New      EAX = $'
    
    buf    db 11
           db ?
           db 11 dup (?)
    
    .code          
    start:
    ;INITIALIZE DATA SEGMENT.
      mov  ax, @data
      mov  ds, ax
    
    ;CONVERT EAX TO STRING TO DISPLAY IT.
      call dollars  ;NECESSARY TO DISPLAY.
      mov  eax, 1234567890
      call number2string  ;PARAMETER:AX. RETURN:VARIABLE BUF.
    
    ;DISPLAY 'ORIGINAL EAX'.
      mov  ah, 9
      mov  dx, offset msj1
      int  21h  
    
    ;DISPLAY BUF (EAX CONVERTED TO STRING).
      mov  ah, 9
      mov  dx, offset buf
      int  21h  
    
    ;FLIP EAX.
      call dollars  ;NECESSARY TO DISPLAY.
      mov  eax, 1234567890
      call flip_eax  ;PARAMETER:AX. RETURN:VARIABLE BUF.
    
    ;DISPLAY 'FLIPPED EAX'.
      mov  ah, 9
      mov  dx, offset msj2
      int  21h  
    
    ;DISPLAY BUF (EAX FLIPPED CONVERTED TO STRING).
      mov  ah, 9
      mov  dx, offset buf
      int  21h  
    
    ;CONVERT STRING TO NUMBER (FLIPPED EAX TO EAX).
      mov  si, offset buf  ;STRING TO REVERSE.
      call string2number   ;RETURN IN EBX.
      mov  eax, ebx        ;THIS IS THE NEW EAX FLIPPED.
    
    ;CONVERT EAX TO STRING TO DISPLAY IT.
      call dollars  ;NECESSARY TO DISPLAY.
      call number2string  ;PARAMETER:EAX. RETURN:VARIABLE BUF.
    
    ;DISPLAY 'NEW EAX'.
      mov  ah, 9
      mov  dx, offset msj3
      int  21h  
    
    ;DISPLAY BUF (EAX CONVERTED TO STRING).
      mov  ah, 9
      mov  dx, offset buf
      int  21h  
    
    ;WAIT UNTIL USER PRESS ANY KEY.
      mov  ah, 7
      int  21h
    
    ;FINISH PROGRAM.
      mov  ax, 4c00h
      int  21h           
    
    ;------------------------------------------
    
    flip_eax proc
      mov  si, offset buf  ;DIGITS WILL BE STORED IN BUF.
      mov  bx, 10 ;DIGITS ARE EXTRACTED DIVIDING BY 10.
      mov  cx, 0  ;COUNTER FOR EXTRACTED DIGITS.
    extracting:       
    ;EXTRACT ONE DIGIT.
      mov  edx, 0 ;NECESSARY TO DIVIDE BY EBX.
      div  ebx ;EDX:EAX / 10 = EAX:QUOTIENT EDX:REMAINDER.
    ;INSERT DIGIT IN STRING.
      add  dl, 48 ;CONVERT DIGIT TO CHARACTER.
      mov  [ si ], dl
      inc  si
    ;NEXT DIGIT.
      cmp  eax, 0     ;IF NUMBER IS
      jne  extracting ;NOT ZERO, REPEAT.
    
      ret
    flip_eax endp  
    
    ;------------------------------------------
    ;CONVERT STRING TO NUMBER IN EBX.
    ;SI MUST ENTER POINTING TO THE STRING.
    
    string2number proc
    
    ;COUNT DIGITS IN STRING.
      mov  cx, 0
    find_dollar:                                          
      inc  cx  ;DIGIT COUNTER.
      inc  si  ;NEXT CHARACTER.
      mov  bl, [ si ]
      cmp  bl, '$'
      jne  find_dollar  ;IF BL != '$' JUMP.
      dec  si  ;BECAUSE IT WAS OVER '$', NOT OVER THE LAST DIGIT.
    
    ;CONVERT STRING.
      mov  ebx, 0
      mov  ebp, 1 ;MULTIPLE OF 10 TO MULTIPLY EVERY DIGIT.
    repeat:         
    ;CONVERT CHARACTER.                    
      mov  eax, 0 ;NOW EAX==AL.
      mov  al, [ si ] ;CHARACTER TO PROCESS.
      sub  al, 48 ;CONVERT ASCII CHARACTER TO DIGIT.
      mul  ebp ;EAX*EBP = EDX:EAX.
      add  ebx, eax ;ADD RESULT TO BX. 
    ;INCREASE MULTIPLE OF 10 (1, 10, 100...).
      mov  eax, ebp
      mov  ebp, 10
      mul  ebp ;AX*10 = EDX:EAX.
      mov  ebp, eax ;NEW MULTIPLE OF 10.  
    ;CHECK IF WE HAVE FINISHED.
      dec  si ;NEXT DIGIT TO PROCESS.
      loop repeat ;CX-1, IF NOT ZERO, REPEAT.
    
      ret 
    string2number endp
    
    ;------------------------------------------
    ;FILLS VARIABLE STR WITH '$'.
    ;USED BEFORE CONVERT NUMBERS TO STRING, BECAUSE
    ;THE STRING WILL BE DISPLAYED.
    
    dollars proc
      mov  si, offset buf
      mov  cx, 11
    six_dollars:      
      mov  bl, '$'
      mov  [ si ], bl
      inc  si
      loop six_dollars
    
      ret
    dollars endp  
    
    ;------------------------------------------
    ;NUMBER TO CONVERT MUST ENTER IN EAX.
    ;ALGORITHM : EXTRACT DIGITS ONE BY ONE, STORE
    ;THEM IN STACK, THEN EXTRACT THEM IN REVERSE
    ;ORDER TO CONSTRUCT STRING (BUF).
    
    number2string proc
      mov  ebx, 10 ;DIGITS ARE EXTRACTED DIVIDING BY 10.
      mov  cx, 0 ;COUNTER FOR EXTRACTED DIGITS.
    cycle1:       
      mov  edx, 0 ;NECESSARY TO DIVIDE BY EBX.
      div  ebx ;EDX:EAX / 10 = EAX:QUOTIENT EDX:REMAINDER.
      push dx ;PRESERVE DIGIT EXTRACTED (DL) FOR LATER.
      inc  cx  ;INCREASE COUNTER FOR EVERY DIGIT EXTRACTED.
      cmp  eax, 0  ;IF NUMBER IS
      jne  cycle1  ;NOT ZERO, LOOP. 
    ;NOW RETRIEVE PUSHED DIGITS.
      mov  si, offset buf
    cycle2:  
      pop  dx        
      add  dl, 48 ;CONVERT DIGIT TO CHARACTER.
      mov  [ si ], dl
      inc  si
      loop cycle2  
    
      ret
    number2string endp  
    
    end start