8088 Асамблея, IBM PC DOS, 164 159 156 155 байт
Двійковий:
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$
Створіть і випробуйте виконуваний файл xxd -r
зверху або завантажте PHONE.COM .
Нерозбірний список:
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:
Вхідний рядок читається праворуч зліва, щоб полегшити пошук трійки. Вихід натискається на стек x86 для спрощення змінити порядок відображення, а також полегшити перестановку слів "подвійний" і "потрійний", щоб передувати імені цифри.
Якщо наступна цифра відрізняється від останньої, назву шукають у списку слів і натискають на стек. Оскільки в машинному коді немає офіційного поняття "індексований масив рядків змінної довжини", список слів сканується i
(індекс слова) кількість разів для роздільника рядка ( $
), щоб знайти відповідне слово. Корисно, що x86 має пару коротких інструкцій ( REPNZ SCASB
що схоже на memchr()
C), що спрощує це (спасибі CISC !).
Якщо цифра така ж, як і попередня, лічильник на довжину "пробігу" збільшується і продовжує циклічно ліворуч на вході. Після закінчення запуску ім'я цифри береться з стека, оскільки його потрібно буде розміщувати після "подвійного" або "потрійного" для кожної групи. Якщо довжина пробігу непарна (а довжина запуску - це > 1
), ім'я цифри з наступним рядком "потрійний" висувається до стека, а довжина виконання зменшується на 3. Оскільки довжина запуску тепер буде парною, крок повторюється для "подвійного", поки довжина пробігу не дорівнює 0.
Коли рядок введення доходить до кінця, стек викидається з кожною збереженою рядком, записаною на екран у зворотному порядку.
I / O:
Автономний виконуваний комп'ютер DOS, вхід з виводу командного рядка на консоль.
Завантажте та протестуйте PHONE.COM .