Conversion chaine de caractère (hexa,dec,oct,bin) -> nombre (16bits,mode réel, tasm)

Contenu du snippet

Ce code est 16bits mode réel.

Il permet de convertir une chaine de caractères de DS:SI en un nombre dans AX pour plusieurs bases :
-> Décimale
-> Hexadécimale
-> Binaire
-> Octale

Le code a été dévellopé avec TASM.

Ce code est l'inverse de mon code http://www.asmfr.com/code.aspx?ID=30896

Source / Exemple :


MODEL SMALL
STACK 100h

DATA SEGMENT
  ChaineMax DB 25
  ChaineLen DB ?
  Chaine DB 25 DUP('$')
  CRLF DB 13,10,'$'
DATA ENDS

CODE SEGMENT
  ASSUME CS:CODE,DS:DATA

Scanf MACRO Buff
  MOV AH,0Ah
  LEA DX,Buff
  INT 21h
ENDM

Printf MACRO BuffC
  MOV AH,09h
  LEA DX,BuffC
  INT 21h
ENDM

TerminalChar EQU '$'

;inverse une chaine
;==================
;DS:SI : adresse du début de la chaine
;DS:DI : adresse de fin de la chaine (avant le caractère de terminaison de chaine)
InverseChaine PROC
  ;on inverse la chaine puisque l'on a calculé la représentation à l'envers (méthode des divisions successives)
  boucleInv:
    ;on échange [DI] <-> [SI]
    MOV AL,byte ptr [DI]
	MOV AH,byte ptr [SI]
	MOV byte ptr [SI],AL
	MOV byte ptr [DI],AH
	;octets suivants
	DEC DI
	INC SI
	;tant que l'on n'a pas tout inversé (SI < DI)
	CMP SI,DI
	JL boucleInv
  RET
InverseChaine ENDP

;convertit un nombre en sa représentation décimale (chaine)
;==========================================================
;DS:SI : adresse où stocker la chaine
;AX : nombre à convertir
;CX=1 : nombre signé, CX=0 : non signé
ChaineDec PROC
  ;sauvegarde des registres
  PUSH DX
  PUSH DI
  PUSH CX
  PUSH SI
  PUSH AX

  ;si le nombre est non signé
  CMP CX,0
  ;on passe à la conversion
  JE PasSigne
  ;sinon, on calcule la valeur absolue
  ;si AX est >= 0
  CMP AX,0
  JGE PasSigne
  ;valeur absolue de AX
  NEG AX
  ;on ajoute le signe
  MOV byte ptr [SI],'-'
  ;on passe au caractère suivant
  INC SI

  PasSigne:
  ;sauvegarde de l'offset de départ de la chaine
  MOV DI,SI

  ;mot de poids fort dans le dividende
  XOR DX,DX

  ;tant qu'il y a des chiffres à ajouter
  boucleDec:
    ;CX=AX pour le calcule du reste de division
    MOV CX,AX

    ;division par 10 : algo de Terje Mathisen
	;========================================
    MOV DX,0CCCDh
    ;on divise AX par 10 : résultat dans DX
    MUL DX
	SHR DX,3
	;========================================

	;on sauvegarde de résultat dans AX
	MOV AX,DX

	;on calcule le reste de la division de CX(=AX avant division)
	SHL DX,1  ;DX = quotient * 2
	SUB CX,DX ;CX = divende - quotient * 2
	SHL DX,2  ;DX = quotient * 2 * 4 = quotient * 8
	SUB CX,DX ;CX = dividende - quotient * 2 - quotient * 8 = dividende - quotient * 10 = reste

    ;on ajoute '0'=48 pour convertir le chiffre en code ascii correspondant
	ADD CX,'0'

    ;on le copie dans la chaine
    MOV byte ptr [DI],CL

    ;on passe au caractère suivant
	INC DI
	;si le quotient est nul, on a fini la conversion
	CMP AX,0
	JA boucleDec

  ;on met un caractère de fin de chaine
  MOV byte ptr [DI],TerminalChar

  ;on se place avant le caractère de la fin de chaine
  DEC DI

  ;on inverse la chaine puisque l'on a calculé la représentation à l'envers (méthode des divisions successives)
  CALL InverseChaine

  ;récupération des registres
  POP AX
  POP SI
  POP CX
  POP DI
  POP DX
  RET
ChaineDec ENDP

;convertit une chaine de caractère (décimale) en nombre
;======================================================
;DS:SI : chaine représentant le nombre décimal
;renvoie le nombre dans AX
DecChaine PROC
  ;sauvegarde des registres utilisés
  PUSH BX
  PUSH CX
  PUSH SI
  
  ;init du nombre à 0
  XOR AX,AX
  ;init de BH (et BL) à 0
  XOR BX,BX

  boucleDecC:
    ;on lit un caractrère ascii de la chaine
    MOV BL,byte ptr [SI]
	;on lui retranche le code ascii de '0' pour se placer dans la plage décimale 0-9
    SUB BL,'0'
	;si le caractère est en dessous de '0', erreur ou fin de chaine
	JL FinDecC
	;si le caractère est en dessus de '9', erreur ou fin de chaine
	CMP BL,9
	JA FinDecC
    
	;on multiplie AX par 10 pour donner leur "poids" aux chiffres précédents
	;=======================================================================
	MOV CX,AX ;CX=AX
	SHL CX,3  ;CX = CX * 2 ^ 3 = AX * 8
	ADD AX,AX ;AX = AX + AX = AX * 2
	ADD AX,CX ;AX = AX + CX = AX * 2 + AX * 8 = AX * 10
    ;=======================================================================

	;on ajoute le valeur du chiffre courant à AX
	ADD AX,BX
	
	;caractère suivant
	INC SI

    ;on boucle tant que l'on ne sort pas avec les conditions d'erreur ou de fin de chaine
	JMP boucleDecC

  FinDecC:

  ;on restaure les registres
  POP SI
  POP CX
  POP BX
  RET
DecChaine ENDP

;convertit une chaine de caractère (hexadécimale) en nombre
;==========================================================
;DS:SI : chaine représentant le nomre hexadécimal
;renvoie le nombre dans AX
HexChaine PROC
  ;sauvegarde des registres utilisés
  PUSH BX
  PUSH SI
  
  ;init du nombre à 0
  XOR AX,AX
  ;init de BH (et BL) à 0
  XOR BX,BX

  boucleHexC:
    ;on lit un caractrère ascii de la chaine
    MOV BL,byte ptr [SI]
	;on lui retranche le code ascii de '0' pour se placer dans la plage décimale 0-9
    SUB BL,'0' ;BL = caractère - '0'
	;si le caractère est en dessous de '0', erreur ou fin de chaine
	JL FinHexC
	;si le caractère est entre '0' et '9', on convertit
	CMP BL,9
	JBE SuiteHexC

    ;BL = caractère - '0'
	;on lui retranche le code ascii de 'A'(-'0'-10) pour se placer dans la plage décimale 10-15
    SUB BL,'A'-'0'-10 ;BL = caractère - '0' - ('A' - '0' - 10) = caractère - 'A' + 10
	;si le caractère est en dessous de 'A', erreur ou fin de chaine
	JL FinHexC
	;si le caractère est entre 'A' et 'F', on convertit
	CMP BL,15
	JBE SuiteHexC

    ;BL = caractère - 'A' + 10
	;on lui retranche le code ascii de 'a'(-'A') pour se placer dans la plage décimale 10-15
    SUB BL,'a'-'A' ;BL = caractère - 'A' + 10 - ('a' - 'A') = caractère - 'a' + 10
	;si le caractère est en dessous de 'a', erreur ou fin de chaine
	JL FinHexC
	;si le caractère est au dessus de 'f', erreur ou fin de chaine
	CMP BL,15
	JA FinHexC

	SuiteHexC:
	;on multiplie AX par 16 pour donner leur "poids" aux chiffres précédents
	;=======================================================================
	SHL AX,4  ;AX = AX * 2 ^ 4 = AX * 16
    ;=======================================================================

	;on ajoute le valeur du chiffre courant à AX
	ADD AX,BX
	
	;caractère suivant
	INC SI

    ;on boucle tant que l'on ne sort pas avec les conditions d'erreur ou de fin de chaine
	JMP boucleHexC

  FinHexC:

  ;on restaure les registres
  POP SI
  POP BX
  RET
HexChaine ENDP

;convertit une chaine de caractère (binaire) en nombre
;=====================================================
;DS:SI : chaine représentant le nombre binaire
;renvoie le nombre dans AX
BinChaine PROC
  ;sauvegarde des registres utilisés
  PUSH BX
  PUSH SI
  
  ;init du nombre à 0
  XOR AX,AX
  ;init de BH (et BL) à 0
  XOR BX,BX

  boucleBinC:
    ;on lit un caractrère ascii de la chaine
    MOV BL,byte ptr [SI]
	;on lui retranche le code ascii de '0' pour se placer dans la plage décimale 0-1
    SUB BL,'0'
	;si le caractère est en dessous de '0', erreur ou fin de chaine
	JL FinBinC
	;si le caractère est en dessus de '1', erreur ou fin de chaine
	CMP BL,1
	JA FinBinC
    
	;on multiplie AX par 2 pour donner leur "poids" aux chiffres précédents
	;======================================================================
	ADD AX,AX ;AX = AX + AX = AX * 2
    ;======================================================================

	;on ajoute le valeur du chiffre courant à AX
	ADD AX,BX
	
	;caractère suivant
	INC SI

    ;on boucle tant que l'on ne sort pas avec les conditions d'erreur ou de fin de chaine
	JMP boucleBinC

  FinBinC:

  ;on restaure les registres
  POP SI
  POP BX
  RET
BinChaine ENDP

;convertit une chaine de caractère (octal) en nombre
;===================================================
;DS:SI : chaine représentant le nomre octal
;renvoie le nombre dans AX
OctChaine PROC
  ;sauvegarde des registres utilisés
  PUSH BX
  PUSH SI
  
  ;init du nombre à 0
  XOR AX,AX
  ;init de BH (et BL) à 0
  XOR BX,BX

  boucleOctC:
    ;on lit un caractrère ascii de la chaine
    MOV BL,byte ptr [SI]
	;on lui retranche le code ascii de '0' pour se placer dans la plage décimale 0-7
    SUB BL,'0'
	;si le caractère est en dessous de '0', erreur ou fin de chaine
	JL FinOctC
	;si le caractère est en dessus de '7', erreur ou fin de chaine
	CMP BL,7
	JA FinOctC
    
	;on multiplie AX par 8 pour donner leur "poids" aux chiffres précédents
	;=======================================================================
	SHL AX,3  ;AX = AX * 2 ^ 3 = AX * 8
    ;=======================================================================

	;on ajoute le valeur du chiffre courant à AX
	ADD AX,BX
	
	;caractère suivant
	INC SI

    ;on boucle tant que l'on ne sort pas avec les conditions d'erreur ou de fin de chaine
	JMP boucleOctC

  FinOctC:

  ;on restaure les registres
  POP SI
  POP BX
  RET
OctChaine ENDP

  Deb:
  ;init de DS
  MOV AX,DATA
  MOV DS,AX

  ;saisie chaine de caractères
  Scanf ChaineMax
  
  ;conversion
  LEA SI,Chaine
  CALL HexChaine

  ;conversion en décimal non signé
  XOR CX,CX
  CALL ChaineDec

  ;affichage
  Printf CRLF
  Printf Chaine

  ;exit 0
  MOV AL,0
  MOV AH,4Ch
  INT 21h
CODE ENDS
END Deb

Conclusion :


N'hésitez pas à commenter et à noter...

Le code est commenté et optimisé (principalement les multiplications) dans les limites de mes connaissances...

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.