0

I'm trying to write a program that converts a string which represents in hex to string in trenary(base 3) representation. so far I've succeed to convert to input string to decimal but now I need to convert it to trenary and I don't really know how to write it in assembly(nasm). All I know is that I need to divide the decimal number in 3 and add the reminder to the final answer.

this is the code so far:

section .rodata
LC0:
DB  "The result is: %d", 10, 0  ; Format string

section .bss
LC1:
RESB    32

section .text
align 16
global my_func
extern printf

my_func:
push    ebp
mov ebp, esp    ; Entry code - set up ebp and esp
pusha   ; Save registers

mov ecx, dword [ebp+8]  ; Get argument (pointer to string)

; Your code should be here...
mov dword [LC1], 0  ; initialize answer

loop:
mov al, byte [ecx]

; if al == \n, skip it
cmp al, 10
    je next

shl dword[LC1], 4 ; multiply by 16 each digit we add

; if al >= 'a'
cmp al, 'a'
    jge ge_a

; if al >= 'A'
cmp al, 'A'
    jge ge_A

; if al >= '0'
cmp al, '0'
    jge ge_0

; default
; do nothing
jmp next

ge_a: ; a <= al
    ; if al <= 'f'
    cmp al, 'f'
        jle a_f
    ; else
        jmp next

ge_A: ; A <= al
    ; if al <= 'F'
    cmp al, 'F'
        jle A_F
    ; else
        jmp next

ge_0: ; 0 <= al
    ; if al <= '9'
    cmp al, '9'
        jle n0_9
    ; else
        jmp next

a_f: ; [a, f]
    sub al, 'a'
    add al, 10
    add byte[LC1], al
    jmp next

A_F: ; [A, F]
    sub al, 'A'
    add al, 10
    add byte[LC1], al
    jmp next

n0_9: ; [0, 9]
    sub al, '0'
    add byte[LC1], al
    jmp next

next:
 inc    ecx ; increment pointer
 cmp    byte [ecx], 0 ; check if byte pointed to is zero
 jnz    loop ; keep looping until it is null terminated


 push   dword[LC1]  ; Call printf with 2 arguments: pointer to str
 push   LC0 ; and pointer to format string.
 call   printf
 add esp, 8 ; Clean up stack after call

 popa   ; Restore registers
 mov    esp, ebp    ; Function exit code
 pop    ebp
 ret
Cœur
  • 37,241
  • 25
  • 195
  • 267
kitsuneFox
  • 1,243
  • 3
  • 18
  • 31
  • same way you convert to decimal: repeated division/modulo by the base to get digits in order. https://stackoverflow.com/questions/13166064/how-do-i-print-an-integer-in-assembly-level-programming-without-printf-from-the/46301894#46301894 – Peter Cordes Mar 14 '18 at 10:57
  • Also, if you're going to use `printf` for output, why not use `sscanf` or `strtol` for input? `strtol` is probably much more efficient than all that crazy branching separately for lower and upper case. (And it would accumulate the result in a register, and definitely wouldn't cause a store-forwarding stall by doing a byte add and then a dword shift.) – Peter Cordes Mar 14 '18 at 11:00

1 Answers1

1

Well... "decimal", "hex", "ternary" etc. are ways of representing a number in text. You've converted a string with a hex representation of a number to a number - there's nothing really "decimal" about it at this point. You want to divide your number by 3, but you don't really "add" the remainder to anything, you convert the digit to a character representing that digit (add '0') and put it in a buffer. As usual, we get the remainders in the "wrong" order - work "backwards" in the buffer or otherwise reverse 'em. Don't forget you want to end up with a zero-terminated string! Your format string for printf will need to expect a string, not an integer. If you've got a routine to convert a number to a decimal representation, just changing the 10 to 3 should work.

Frank Kotler
  • 3,079
  • 2
  • 14
  • 9