Ludzie pragną czasami się rozstawać, żeby móc tęsknić, czekać i cieszyć się z powrotem.
Sortowanie zbioru łańcuchów (z uwzględnieniem i bez uwzględnienia wielkości liter).
Sprawdzanie, czy dany znak jest znakiem alfanumerycznym.
Sprawdzanie, czy dany znak może występować w identyfikatorach.
Sprawdzanie, czy dany znak jest operatorem arytmetycznym lub logicznym.
Sprawdzanie, czy znak jest nawiasem (czyli jednym ze znaków (, ), [, ], {, },
< lub > ).
Sprawdzanie, czy znak jest znakiem przestankowym.
Sprawdzanie, czy znak jest białym znakiem (czyli spacją, tabulatorem lub znakiem nowego wiersza).
Sprawdzanie, czy znak jest znakiem sterującym kursorem.
Sprawdzanie, czy znak jest znakiem kontrolującym ekran
(na przykład PageUp, PageDown, Home czy End).
Sprawdzanie, czy znak odpowiada klawiszowi funkcyjnemu.
Nasz zestaw HyCode zdefiniujemy tak, aby opisane działania były tak szybkie i tak proste, jak tylko jest to możliwe. Znaczną przewagę nad kodem ASCII możemy uzyskać, jeśli wszystkie znaki wchodzące w skład jakiejś grupy zestawimy razem — na przykład wszystkie litery lub wszystkie znaki sterujące. Dzięki temu będziemy mogli robić dowolne z powyższych sprawdzeń za pomocą tylko dwóch porównań. Na przykład wygodnie byłoby sprawdzać, czy dany znak jest znakiem przestankowym, po-równując go z wartościami ograniczającymi znaki przestankowe z góry i z dołu. Nie można w ten sposób obsłużyć wszystkich możliwych zakresów porównań, ale warto uwzględnić zakresy występujące najczęściej. Wprawdzie w ASCII pewne ciągi znaków są ułożone bardzo sensownie, ale można je jeszcze poprawić. Na przykład nie można tam sprawdzić, czy znak jest przestankowy, przy ograniczeniu się do dwóch porównań, gdyż znaki te są porozrzucane po całym zestawie.
120
Profesjonalne programowanie. Część 1. Zrozumieć komputer
5.4.2. Grupowanie znaków odpowiadających cyfrom
Weźmy pod uwagę pierwsze trzy funkcje z powyższej listy — najłatwiej będzie nam je realizować, jeśli znakom o kodach od 0 do 9 przypiszemy kolejne cyfry. Korzystając z pojedynczego porównania wartości bez znaku, sprawdzamy, czy dany znak jest cyfrą. Konwersja między cyfrą a jej wartością jest banalna, gdyż kod i wartość znaku są identyczne.
5.4.3. Grupowanie liter
Kolejnym typowym problemem związanym z obsługą znaków i łańcuchów znakowych jest obsługa liter. Zestaw ASCII, choć jest o niebo lepszy od EBCDIC, po prostu nie nadaje się do sprawdzania i przetwarzania liter. Oto problemy z literami ASCII, które rozwiążemy w HyCode:
Litery zostały umieszczone w dwóch osobnych częściach. Sprawdzanie, czy znak jest literą, wymaga zrobienia czterech porównań.
Małe litery mają kody ASCII większe od wielkich liter. Jeśli chodzi o porównania, bardziej intuicyjne jest traktowanie małych liter jako znajdujących się wcześniej niż wielkie.
Wszystkie małe litery mają wartości większe od poszczególnych wielkich liter. Prowadzi to do niezgodnych z intuicją efektów, kiedy a jest większe od B, choć każde dziecko wie, że jest inaczej.
Kodowanie HyCode rozwiązuje te problemy na kilka ciekawych sposobów. Po pierwsze, do zapisu 52 liter używane są kody od $4C do $7F. HyCode wykorzystuje tylko 128 znaków ($00..$7F), z czego 52 to litery. Wobec tego, jeśli będziemy sprawdzać, czy dany znak jest literą, wystarczy porównać, czy jego kod jest większy lub równy $4C.
W językach wysokiego poziomu wystarczy porównanie typu:
if( c >= 76) ...
Jeśli kompilator będzie obsługiwał HyCode, wystarczy zapis:
if( c >= 'a') ...
W asemblerze wystarczy wykorzystać dwie instrukcje:
cmp( al, 76 );
jnae NotAlphabetic;
// Instrukcje wykonywane dla liter.
NotAlphabetic:
Kolejna zaleta HyCode (istotnie różniąca to kodowanie od innych) to przeplatanie wielkich i małych liter (czyli kolejno zapisywane są znaki a, A, b, B, c, C i tak dalej).
Dzięki temu sortowanie i porównywanie łańcuchów jest bardzo łatwe, niezależnie od tego, czy uwzględniamy wielkość liter, czy nie. Przeplatanie powoduje, że najmłodszy
Rozdział 5. ♦ Dane znakowe
121
bit znaku wskazuje, czy znak jest małą literą (najmłodszy bit jest zerem), czy wielką (najmłodszy bit jest jedynką). HyCode wykorzystuje następujące kodowanie liter: a:76, A:77, b:78, B:79, c:80, C:81, ..., y:124, Y:125, z:126, Z:127