8088 Assembly, IBM PC DOS, 164 159 156 155 byte
Binario:
00000000: d1ee 8a0c 03f1 53fd ac3a d075 0343 e2f7 ......S..:.u.C..
00000010: 85db 741c 5f8a d043 f6c3 0174 0a57 bd64 ..t._..C...t.W.d
00000020: 0155 83eb 0374 0957 bd5d 0155 4b4b 75f7 .U...t.W.].UKKu.
00000030: 8ad0 2c2f 7213 518a f0b0 24b1 31bf 6a01 ..,/r.Q...$.1.j.
00000040: fcf2 aefe ce75 fa59 57e2 bc5a 85d2 740c .....u.YW..Z..t.
00000050: b409 cd21 b220 b402 cd21 ebef c364 6f75 ...!. ...!...dou
00000060: 626c 6524 7472 6970 6c65 246f 6824 6f6e ble$triple$oh$on
00000070: 6524 7477 6f24 7468 7265 6524 666f 7572 e$two$three$four
00000080: 2466 6976 6524 7369 7824 7365 7665 6e24 $five$six$seven$
00000090: 6569 6768 7424 6e69 6e65 24 eight$nine$
Costruisci e testa l'eseguibile usando xxd -r
dall'alto, oppure scarica PHONE.COM .
Elenco non assemblato:
D1 EE SHR SI, 1 ; point SI to DOS PSP (80H) for input string
8A 0C MOV CL, BYTE PTR[SI] ; load input string length into CX
03 F1 ADD SI, CX ; move SI to end of input
53 PUSH BX ; push a 0 to signal end of output stack
CHAR_LOOP:
FD STD ; set LODS direction to reverse
AC LODSB ; load next char from [SI] into AL, advance SI
3A D0 CMP DL, AL ; is it same as previous char?
75 03 JNZ NEW_CHAR ; if not, it's a different char
43 INC BX ; otherwise it's a run, so increment run length
E2 F7 LOOP CHAR_LOOP ; move on to next char
NEW_CHAR:
85 DB TEST BX, BX ; is there a run greater than 0?
74 1C JZ GET_WORD ; if not, look up digit name
5F POP DI ; get name for the current digit
8A D0 MOV DL, AL ; save current char in DL
43 INC BX ; adjust run count (BX=1 means run of 2, etc)
F6 C3 01 TEST BL, 1 ; is odd? if so, it's a triple
74 0A JZ IS_DBL ; is even, so is a double
57 PUSH DI ; push number string ("one", etc) to stack
BD 0164 MOV BP, OFFSET T ; load "triple" string
55 PUSH BP ; push to stack
83 EB 03 SUB BX, 3 ; decrement run count by 3
74 09 JZ GET_WORD ; if end of run, move to next input char
IS_DBL:
57 PUSH DI ; push number string to stack
BD 015D MOV BP, OFFSET D ; load "double" string
55 PUSH BP ; push to stack
4B DEC BX ; decrement by 2
4B DEC BX
75 F7 JNZ IS_DBL ; if not end of run, loop double again
GET_WORD:
8A D0 MOV DL, AL ; save current char into DL
2C 2F SUB AL, '0'-1 ; convert ASCII char to 1-based index
72 13 JB NOT_FOUND ; if not a valid char, move to next
51 PUSH CX ; save outer loop counter
8A F0 MOV DH, AL ; DH is the index to find, use as scan loop counter
B0 24 MOV AL, '$' ; word string is $ delimited
B1 31 MOV CL, 031H ; search through length of word data (49 bytes)
BF 016A MOV DI, OFFSET W ; reset word data pointer to beginning
FC CLD ; set DF to scan forward for SCAS
SCAN_LOOP:
F2/ AE REPNZ SCASB ; search until delimiter '$' is found in [DI]
FE CE DEC DH ; delimiter found, decrement counter
75 FA JNZ SCAN_LOOP ; if counter reached 0, index has been found
59 POP CX ; restore outer loop position
57 PUSH DI ; push string on stack
NOT_FOUND:
E2 BC LOOP CHAR_LOOP ; move to next char in input
OUTPUT_STACK:
5A POP DX ; get string from top of stack
85 D2 TEST DX, DX ; it is the last?
74 0C JZ EXIT ; if so, exit
B4 09 MOV AH, 09H ; DOS display string function
CD 21 INT 21H ; write string to console
B2 20 MOV DL, ' ' ; load space delimiter
B4 02 MOV AH, 02H ; DOS display char function
CD 21 INT 21H ; write char to console
EB EF JMP OUTPUT_STACK ; continue looping
EXIT:
C3 RET ; return to DOS
D DB "double$"
T DB "triple"
W DB "$oh$","one$","two$","three$","four$","five$","six$","seven$","eight$","nine$"
TL; DR:
La stringa di input viene letta da destra a sinistra per facilitare la ricerca di una tripla. L'output viene inserito nello stack x86 per semplificare l'inversione dell'ordine di visualizzazione e facilitare anche la riorganizzazione delle parole "doppia" e "tripla" per precedere il nome della cifra.
Se la cifra successiva è diversa dall'ultima, il nome viene cercato nell'elenco di parole e inserito nello stack. Poiché non esiste un concetto formale di "matrice indicizzata di stringhe a lunghezza variabile" nel codice macchina, l'elenco di parole viene scansionato i
(l'indice della parola) numero di volte in cui il delimitatore di stringa ( $
) trova la parola corrispondente. Utilmente, x86 ha un paio di brevi istruzioni ( REPNZ SCASB
che è simile a memchr()
in C), che semplifica questo (grazie CISC !).
Se la cifra è la stessa di quella precedente, il contatore per la lunghezza di una "corsa" viene incrementato e continua a scorrere verso sinistra sull'ingresso. Una volta terminata la corsa, il nome della cifra viene preso dallo stack poiché dovrà essere posizionato dopo il "doppio" o il "triplo" per ciascun raggruppamento. Se la lunghezza della corsa è dispari (e la lunghezza della corsa è > 1
), il nome della cifra seguito dalla stringa "triple" viene inserito nello stack e la lunghezza della corsa viene ridotta di 3. Poiché la lunghezza della corsa sarà ora pari, il passaggio viene ripetuto per "double" fino a quando la lunghezza della corsa è 0.
Quando la stringa di input ha raggiunto la fine, lo stack viene scaricato con ciascuna stringa salvata scritta sullo schermo in ordine inverso.
I / O:
Un eseguibile DOS per PC autonomo, input dall'output della riga di comando alla console.
Scarica e prova PHONE.COM .