kode mesin x86-64, 44 byte
(Kode mesin yang sama juga berfungsi dalam mode 32-bit.)
Jawaban @Daniel Schepler adalah titik awal untuk ini, tetapi ini memiliki setidaknya satu ide algoritmik baru (bukan hanya bermain golf dengan ide yang sama): Kode ASCII untuk 'B'
( 1000010
) dan 'X'
(1011000
) memberi 16 dan 2 setelah masking dengan0b0010010
.
Jadi setelah mengecualikan desimal (digit angka tidak nol) dan oktal (angka char '0'
kurang dari'B'
), kita bisa mengatur base = c & 0b0010010
dan melompat ke loop digit.
Callable dengan x86-64 System V sebagai unsigned __int128 parse_cxx14_int(int dummy, const char*rsi);
Ekstrak nilai pengembalian EDX dari setengah unsigned __int128
hasil dengan tmp>>64
.
.globl parse_cxx14_int
## Input: pointer to 0-terminated string in RSI
## output: integer in EDX
## clobbers: RAX, RCX (base), RSI (points to terminator on return)
parse_cxx14_int:
xor %eax,%eax # initialize high bits of digit reader
cdq # also initialize result accumulator edx to 0
lea 10(%rax), %ecx # base 10 default
lodsb # fetch first character
cmp $'0', %al
jne .Lentry2
# leading zero. Legal 2nd characters are b/B (base 2), x/X (base 16)
# Or NUL terminator = 0 in base 10
# or any digit or ' separator (octal). These have ASCII codes below the alphabetic ranges
lodsb
mov $8, %cl # after '0' have either digit, apostrophe, or terminator,
cmp $'B', %al # or 'b'/'B' or 'x'/'X' (set a new base)
jb .Lentry2 # enter the parse loop with base=8 and an already-loaded character
# else hex or binary. The bit patterns for those letters are very convenient
and $0b0010010, %al # b/B -> 2, x/X -> 16
xchg %eax, %ecx
jmp .Lentry
.Lprocessdigit:
sub $'0' & (~32), %al
jb .Lentry # chars below '0' are treated as a separator, including '
cmp $10, %al
jb .Lnum
add $('0'&~32) - 'A' + 10, %al # digit value = c-'A' + 10. we have al = c - '0'&~32.
# c = al + '0'&~32. val = m+'0'&~32 - 'A' + 10
.Lnum:
imul %ecx, %edx
add %eax, %edx # accum = accum * base + newdigit
.Lentry:
lodsb # fetch next character
.Lentry2:
and $~32, %al # uppercase letters (and as side effect,
# digits are translated to N+16)
jnz .Lprocessdigit # space also counts as a terminator
.Lend:
ret
Blok yang diubah vs versi Daniel (sebagian besar) indentasi kurang dari instruksi lainnya. Juga loop utama memiliki cabang kondisional di bagian bawah. Ini ternyata menjadi perubahan netral karena tidak ada jalan yang bisa jatuh ke atasnya, dandec ecx / loop .Lentry
ide untuk memasuki loop ternyata bukan kemenangan setelah menangani oktal secara berbeda. Tetapi memiliki lebih sedikit instruksi di dalam loop dengan loop dalam bentuk idiomatis do {} while structure, jadi saya menyimpannya.
Alat uji C ++ Daniel bekerja tidak berubah dalam mode 64-bit dengan kode ini, yang menggunakan konvensi panggilan yang sama dengan jawaban 32-bitnya.
g++ -Og parse-cxx14.cpp parse-cxx14.s &&
./a.out < tests | diff -u -w - tests.good
Disassembly, termasuk byte kode mesin yang merupakan jawaban sebenarnya
0000000000000000 <parse_cxx14_int>:
0: 31 c0 xor %eax,%eax
2: 99 cltd
3: 8d 48 0a lea 0xa(%rax),%ecx
6: ac lods %ds:(%rsi),%al
7: 3c 30 cmp $0x30,%al
9: 75 1c jne 27 <parse_cxx14_int+0x27>
b: ac lods %ds:(%rsi),%al
c: b1 08 mov $0x8,%cl
e: 3c 42 cmp $0x42,%al
10: 72 15 jb 27 <parse_cxx14_int+0x27>
12: 24 12 and $0x12,%al
14: 91 xchg %eax,%ecx
15: eb 0f jmp 26 <parse_cxx14_int+0x26>
17: 2c 10 sub $0x10,%al
19: 72 0b jb 26 <parse_cxx14_int+0x26>
1b: 3c 0a cmp $0xa,%al
1d: 72 02 jb 21 <parse_cxx14_int+0x21>
1f: 04 d9 add $0xd9,%al
21: 0f af d1 imul %ecx,%edx
24: 01 c2 add %eax,%edx
26: ac lods %ds:(%rsi),%al
27: 24 df and $0xdf,%al
29: 75 ec jne 17 <parse_cxx14_int+0x17>
2b: c3 retq
Perubahan lain dari versi Daniel termasuk menyimpan sub $16, %al
dari dalam digit-loop, dengan menggunakan lebih banyaksub
daripadatest
sebagai bagian dari mendeteksi pemisah, dan digit vs karakter alfabet.
Berbeda dengan Daniel, setiap karakter di bawah '0'
ini diperlakukan sebagai pemisah, bukan hanya '\''
. (Kecuali' '
: and $~32, %al
/jnz
di kedua loop kami memperlakukan ruang sebagai terminator, yang mungkin nyaman untuk pengujian dengan integer pada awal baris.)
Setiap operasi yang memodifikasi %al
di dalam loop memiliki flag mengkonsumsi cabang ditetapkan oleh hasilnya, dan setiap cabang pergi (atau jatuh melalui) ke lokasi yang berbeda.