• # Avec du poil aux pattes

    Posté par . En réponse au journal Esod mumixam !. Évalué à 9.

    Une version en x86_64, pour Linux. À assembler avec FASM.

    Pour l'ASCII étendu, suit l'ISO 8859-15 (aka Latin-9), et donc pas l'UTF-8. Limites en dur pour la longueur de la ligne et des mots.

    format ELF64 executable 3
    entry _start
    TAILLE_BUF=256
    TAILLE_MOT=64
    segment readable executable
    _start:
     XOR RAX, RAX ; 0 (sys_read)
     XOR RDI, RDI ; 0 (stdin)
     MOV RSI, bufin ; adresse du tampon d'entrée
     MOV RDX, TAILLE_BUF ; taille du tampon
     SYSCALL ; lecture
     MOV [longueur], RAX ; nombre d'octets lus
     XOR RDI, RDI
    teste_nouveau_caractere:
    ; on teste le nouveau caractère
     CALL nature_caractere
     CMP AL, 0
     JNE nouveau_mot
    ; ponctuation et divers : on l'écrit tel quel
     MOV [bufout+RDI], DL
     JMP suivant
    nouveau_mot:
    ; lettre : début d'un nouveau mot
     XOR RBX, RBX ; compteur des caractères du mot
     MOV RSI, RDI ; mémorise la position (offset) du début du mot
    ; on recherche la fin de ce nouveau mot en enregistrant pour chaque lettre son type
    continue_mot:
     MOV [mot+RBX], DL
     MOV [type_car+RBX], AL
     MOV [casse_car+RBX], AH
     INC RDI
     CALL nature_caractere
     CMP AL, 0
     JE fin_mot
     INC RBX
     JMP continue_mot
    fin_mot:
     push RDX
     XOR RCX, RCX
    inverse_mot:
    ; quelle casse faut-il ?
     MOV AL, [casse_car+RCX] ; casse du caractère d'origine
     CMP AL, 0
     JNE minuscule
    ; majuscule
     MOV AL, [casse_car+RBX] ; casse du nouveau caractère
     CMP AL, 0
     JNE monter_casse
    ; déjà en majuscule, il faut juste copier
     MOV AL, [bufin+RSI+RBX]
     MOV [bufout+RSI+RCX], AL
     JMP fin_corps_boucle_mot
    monter_casse:
     MOV AL, [type_car+RBX]
     CMP AL, 1
     JNE pas_min_std
     MOV AL, [mot+RBX]
     ADD AL, "A"
     MOV [bufout+RSI+RCX], AL
     JMP fin_corps_boucle_mot
    pas_min_std:
     CMP AL, 2
     JNE pas_min_acc
     MOV AL, [mot+RBX]
     ADD AL, 0xC0 ; "À"
     MOV [bufout+RSI+RCX], AL
     JMP fin_corps_boucle_mot
    pas_min_acc: ; e dans l'o
     mov [bufout+RSI+RCX], 0xBC ; "Œ"
     JMP fin_corps_boucle_mot
    minuscule:
     MOV AL, [casse_car+RBX] ; casse du nouveau caractère
     CMP AL, 1
     JNE baisser_casse
    ; déjà en minuscule, il faut juste copier
     MOV AL, [bufin+RSI+RBX]
     MOV [bufout+RSI+RCX], AL
     JMP fin_corps_boucle_mot
    baisser_casse:
     MOV AL, [type_car+RBX]
     CMP AL, 1
     JNE pas_maj_std
     MOV AL, [mot+RBX]
     ADD AL, "a"
     MOV [bufout+RSI+RCX], AL
     JMP fin_corps_boucle_mot
    pas_maj_std:
     CMP AL, 2
     JNE pas_maj_acc
     MOV AL, [mot+RBX]
     ADD AL, 0xE0 ; "à"
     MOV [bufout+RSI+RCX], AL
     JMP fin_corps_boucle_mot
    pas_maj_acc: ; E dans l'O
     mov [bufout+RSI+RCX], 0xBD ; "œ"
    fin_corps_boucle_mot:
     INC RCX
     DEC RBX
     JNS inverse_mot
    ; on copie le dernier caractère que l'on vient de trouver
     pop RDX
     MOV [bufout+RDI], DL
    suivant:
     INC RDI
     CMP RDI, [longueur]
     JL teste_nouveau_caractere
     MOV RDI, 1 ; 1 (stdout)
     MOV RSI, bufout ; adresse du message à afficher
     MOV RDX, [longueur] ; nombre d'octets à écrire
     MOV RAX, 1 ; 1 (sys_write)
     SYSCALL ; écriture
    ; Exit
     MOV RDI, 0 ; status de sortie = SUCCESS
     MOV RAX, 60 ; 60 (sys_exit)
     SYSCALL ; exécution de la sortie
    ;; === ROUTINE nature_caractere ===
    ;; entrée :
    ;; rdi : index caractère dans le tampon bufin
    ;; sorties :
    ;; al : type du caractère :
    ;; 0 : ponctuation, divers
    ;; 1 : lettre standard
    ;; 2 : lettre accentuée
    ;; 3 : e dans l'o
    ;; ah : 0 : majuscule
    ;; 1 : minuscule
    ;; dl : rang du caractère dans le type
    ;; ===
    nature_caractere:
     MOV DL, [bufin+RDI]
    test_majuscule:
     CMP DL, "A"
     JB autres
     CMP DL, "Z"
     JA test_minuscule
    ; majuscule standard
     MOV AL, 1
     MOV AH, 0
     SUB DL, "A"
     RET
    test_minuscule: 
     CMP DL, "a"
     JB autres
     CMP DL, "z"
     JA test_edanlo
    ; minuscule standard
     MOV AL, 1
     MOV AH, 1
     SUB DL, "a"
     RET
    test_edanlo:
     CMP DL, 0xBC ; "Œ"
     JB autres
     JNE test_edanlo_min
    ; e dans l'o majuscule
     MOV AL, 3
     MOV AH, 0
     SUB DL, 0xBC ; "Œ"
     RET
    test_edanlo_min:
     CMP DL, 0xBD ; "œ"
     JA test_majuscule_accentuee
    ; e dans l'o minuscule
     MOV AL, 3
     MOV AH, 1
     SUB DL, 0xBC ; "Œ"
     RET
    test_majuscule_accentuee:
     CMP DL, 0xC0 ; "À"
     JB autres
     CMP DL, 0xDD ; "Y'"
     JA test_minuscule_accentuee
    ; majuscule accentuee
     MOV AL, 2
     MOV AH, 0
     SUB DL, 0xC0
     RET
    test_minuscule_accentuee:
     CMP DL, 0xE0 ; "à"
     JB autres
     CMP DL, 0xFD ; "y'"
     JA autres
    ; minuscule accentuee
     MOV AL, 2
     MOV AH, 1
     SUB DL, 0xE0
     RET
    autres: 
     MOV AX, 0
     RET
    ;; === FIN nature_caractere ===
    segment readable writeable
     bufin RB TAILLE_BUF
     bufout RB TAILLE_BUF
     mot RB TAILLE_MOT
     type_car RB TAILLE_MOT
     casse_car RB TAILLE_MOT
     longueur DQ 0

    Pas spécialement propre (je dois écrire en moyenne 50 lignes d'assembleur par an...), ni documenté, ni optimisé (mais vus les langages d'urbains épilés présentés dans la plupart des autres propositions, ce programme (binaire de 1364 octets) devrait avoir fini son exécution avant que les autres n'aient fini leur chargement en mémoire). Ne gère pas pas correctement les signes « multiplication » et « division » (pas envie de m'embêter pour ce cas particulier « intelligemment » placé au beau milieu des majuscules accentuées).