Převod římských čísel na arabská a naopak - Saturn@HP-50g


Předmluva

  

Tento zápis je smutným pokračováním tématického odklonu od výchozí mánie - RPN. O této hanebnosti jsou zmínky v kapitolách předchozích témat, leč snaha po nápravě žádná. Patrně došlo k situaci, kterou lze komentovat slavným citátem „Můžeme o tom diskutovat, můžeme o tom vést spory, můžeme s tím i nesouhlasit, ale to je tak všechno, co se proti tomu dá dělat...“ A k jaké to vlastně došlo nepřístojnosti? Že nepůjde o RPN už víme. Nepůjde však ani o RPL, ba ani na jazyk C nebude zaostřeno. Předmětem zájmu je zde poklesek na nízkou, ale opravdu velmi, velmi nízkou úroveň. No učiněná Sodoma Gomora, radši o tom, paní, nikde nemluvte, taková hanba... (Scénická poznámka: Odcházející sousedka za neustálého bědování lomí rukama.)

Zde prezentovaný program je v assembleru pro procesor Saturn. Aby bylo možno jeho stavbu porovnat s řešením v jiných programovacích jazycích, jde opět o osvědčený Převod římských čísel na arabská a naopak. (Že výběr "osvědčeného" tématu je zde pouze zástupným pojmenováním pro nedostatečnou tvůrčí invenci, je více než patrné. Chlapské přiznání však laskavý čtenář očekává marně.)


Zdrojový text

  

Zde je zdrojový text programu pro Saturn - soubor roman.a. Komentáře k němu až později.

   1 %%HP: T(3)A(R)F(.);
   2 "CODE
   3 NB4BT   EQU     2               nibbles per 1 byte
   4 MAXRO   EQU     15              nejdelsi je MMMDCCCLXXXVIII
   5 
   6 *===============================*
   7 *          VSTUPNI BOD          *
   8 *===============================*
   9         C=DAT1  A               C(A): adresa objektu na RPL-stacku
  10         ?C#0    A               je platna?
  11         GOYES   RO_ARG          - ano, pokracovat
  12         LA(5)   #201            - ne, chybove hlaseni *Too Few Arguments*
  13 RO_ERROR
  14         GOVLNG  =Errjmp
  15 RO_ERROR_VAL
  16         GOSBVL  =GETPTR
  17         LA(5)   =argvalerr      chybove hlaseni *Bad Argument Value*
  18         GOTO    RO_ERROR
  19 
  20 *===============================*
  21 *     NA STACKU JE ARGUMENT     *
  22 *===============================*
  23 RO_ARG
  24         CD1EX                   D1:   adresa objektu
  25         A=DAT1  A               A(A): prolog
  26         D1=C                    D1:   adresa objektu vracena
  27         LC(5)   =DOINT
  28         ?A=C    A               je to ZINT?
  29         GOYES   RO_A2R          - ano
  30         LC(5)   =DOCSTR
  31         ?A#C    A               je to STRING?
  32         GOYES   +               - ne
  33         GOTO    RO_R2A          - ano
  34 +
  35         LA(5)   =argtypeerr     chybove hlaseni *Bad Argument Type*
  36         GOTO    RO_ERROR
  37 
  38 *===============================*
  39 *          JE TO CISLO          *
  40 *===============================*
  41 * R0(A): docasna pamet pro vysledek
  42 * R1(A): pointer na cifry (vychozi D1)
  43 * R2(A): index aktualni cifry (dekadicky rad)
  44 * R3(A): pointer na tabulku rimskych cislic sromt[]
  45 * B(A):  index do tabulky sromt[]
  46 *
  47 D1SROMT MACRO
  48         C=R3.F  A               C(A): sromt[]
  49         C=C+B   A               B(A): index podle dekadickeho radu
  50         D1=C                    D1:   sromt[] + index
  51 D1SROMT ENDM
  52 *
  53 RO_A2R
  54         GOSUB   RO_START
  55 * D1:   pointer na cifry
  56 * C(A): pocet cifer
  57         C=C-1   A               pouze nula ma jen jeden nibble
  58         ?C=0    A               je to nula?
  59         GOYES   RO_ERROR_VAL    - ano
  60         AD1EX                   A(A): adresa hodnoty
  61         A=A+C   A               A(A): adresa posledniho nibble...
  62         D1=A                    D1:   ...tam kam patri
  63         A=DAT1  P               A(0): znamenko
  64         ?A#0    P               je to minus?
  65         GOYES   RO_ERROR_VAL    - ano
  66         C=C-CON A,5             moc velky pocet znaku?
  67         GONC    RO_ERROR_VAL    - ano
  68         D1=D1-  1               D1:   pointer na prvni cifru (MSD)
  69         C=C+1   A               ctyrmistne cislo? (C=C-5+1 -> C=C-1)
  70         GONC    +               - ne, bez kontroly
  71         A=DAT1  P               A(0): prvni cifra
  72         A=A-CON P,4             hodnota > 3999?
  73         GONC    RO_ERROR_VAL    - ano
  74 +
  75         C=C+CON A,3             C(A):  pocet cifer - 1
  76         R2=C.F  A               R2(A): index prvni cifry (MSD)
  77         LC(5)   (MAXRO)*(NB4BT)
  78         GOSUB   RO_A2R_MEM
  79         AD0EX                   A(A):  docasna pamet pro vysledek
  80         R0=A.F  A
  81         AD0EX
  82         C=R2.F  A               C(A):  index prvni cifry (MSD)
  83         C=C+C   A               viz. NB4BT
  84         C=C+C   A               2 rimske cislice na kazdy dekadicky rad
  85         B=C     A               B(A):  index do tabulky sromt[]
  86         GOSUB   RO_SROMT        R3(A): sromt[]
  87 *-------------------------------*
  88 *    ZPRACOVANI JEDNE CIFRY     *
  89 *-------------------------------*
  90 RO_A2R_LOOP
  91         A=DAT1  P               A(0):  cifra
  92         AD1EX
  93         R1=A.F  A               R1(A): pointer na cifry
  94         AD1EX                   A(0):  cifra
  95         LC(1)   4
  96         ?A=C    P               je to 4?
  97         GOYES   RO_A2R_4_9      - ano
  98         LC(1)   9
  99         ?A#C    P               je to 9?
 100         GOYES   RO_A2R_REST0    - ne
 101 RO_A2R_4_9
 102         D1SROMT
 103         C=DAT1  B               z sromt[]...
 104         DAT0=C  B               ...do vysledku
 105         D0=D0+  NB4BT           dalsi znak ve vysledku
 106         D1=D1+  NB4BT           dalsi znak v sromt[]
 107         A=A+A   P               byla to 9?
 108         GONC    +               - ne
 109         D1=D1+  NB4BT           - ano, dalsi znak v sromt[]
 110 +
 111         C=DAT1  B               z sromt[]...
 112         DAT0=C  B               ...do vysledku
 113         D0=D0+  NB4BT           dalsi znaku ve vysledku
 114         GOTO    RO_A2R_CONT
 115 RO_A2R_REST1
 116         D1SROMT
 117         LC(1)   5
 118         ?A<C    P               cifra < 5?
 119         GOYES   +               - ano
 120         D1=D1+  NB4BT           - ne, dalsi znak v sromt[]
 121         A=A-CON P,5-1           cifra -= 5 - 1;
 122 +
 123         C=DAT1  B               z sromt[]...
 124         DAT0=C  B               ...do vysledku
 125         D0=D0+  NB4BT           dalsi znak ve vysledku
 126         A=A-1   P               v cele iteraci odecteno 5
 127 RO_A2R_REST0
 128         ?A#0    P               nenulova cifra na dekadickem radu?
 129         GOYES   RO_A2R_REST1    - ano
 130 RO_A2R_CONT
 131         A=R1.F  A               A(A): pointer na cifry...
 132         A=A-1   A               ...aktualizovat...
 133         D1=A                    ...a dat tam, kam patri
 134         B=B-CON A,2*NB4BT       index -= 2;
 135         C=R2.F  P               C(A): index aktualni cifry
 136         C=C-1   P               hotovo?
 137         R2=C.F  P
 138         GOC     +               - ano
 139         GOTO    RO_A2R_LOOP     - jeste ne
 140 +
 141 *-------------------------------*
 142 * ULOZIT RETEZEC DO NOVEHO OBJ. *
 143 *-------------------------------*
 144         A=R0.F  A               A(A): adresa vysledku
 145         CD0EX                   C(A): konec ukladani vysledku
 146         C=C-A   A               delka retezce vysledku (nibble)
 147         D1=A                    D1:   pointer na vysledek
 148         GOSUB   RO_A2R_MEM      D0:   pointer na data noveho objektu
 149         CD0EX                   C(A): pointer na pridelenou pamet
 150         R0=C.F  A               uschovano v R0
 151         CD0EX
 152         C=C-1   A               bude se testovat CARRY, ne ZERO
 153 RO_A2R_MOVE
 154         A=DAT1  B               byte z vysledku...
 155         DAT0=A  B               ...do noveho objektu
 156         D0=D0+  NB4BT
 157         D1=D1+  NB4BT
 158         C=C-1   A               hotovo?
 159         GONC    RO_A2R_MOVE     - jeste ne
 160         C=R0.F  A               C(A): pointer na pridelenou pamet
 161         C=C-CON A,5+5           zpet pred prolog a delku
 162         R0=C.F  A
 163 *===============================*
 164 *            HOTOVO             *
 165 *===============================*
 166 RO_DONE
 167         GOSBVL  =GETPTR
 168         C=R0.F  A
 169         DAT1=C  A               vysledny novy objekt
 170 * LOOP
 171         A=DAT0  A
 172         D0=D0+  5
 173         PC=(A)
 174 
 175 *===============================*
 176 * NOVY RETEZEC - ALOKACE PAMETI *
 177 *===============================*
 178 * VSTUP:  C(A):  mnoztvi pameti [nibble]
 179 * VYSTUP: D0:    pointer na pridelenou pamet
 180 *         C(A):  delka retezce [byte]
 181 * ZMENY:  A,R0,R1
 182 RO_A2R_MEM
 183         AD1EX                   uschovat D1...
 184         R1=A.F  A               ...do R1
 185         R0=C.F  A               R0(A): delka retezce [nibble]
 186         C=C+CON A,5+5           mnozstvi pameti vcetne prologu a delky
 187         GOSBVL  =GETTEMP
 188         LC(5)   =DOCSTR
 189         DAT0=C  A               prolog
 190         D0=D0+  5               preskocit prolog
 191         C=R0.F  A               C(A): delka retezce [nibble]
 192         C=C+CON A,5             hodnota je vcetne pole delky
 193         DAT0=C  A               delka
 194         D0=D0+  5               preskocit delku na zacatek objektu
 195         C=R0.F  A
 196         CSRB.F  A               # nibble -> byte
 197         A=R1.F  A               z R1...
 198         D1=A                    ...obnovit D1
 199         RTN
 200 
 201 *===============================*
 202 *         JE TO RETEZEC         *
 203 *===============================*
 204 * R0(A): _IDX
 205 * R1(0): _INC (1 nebo 5)
 206 * R2(A): delka zadani (uschova C)
 207 * R3(A): pointer na tabulku rimskych cislic sromt[]
 208 * R4(A): pocet stejnych nebo mensich predchozich rimskych cislic
 209 * D(0):  prechozi _IDX
 210 * D0:    pointer na addt[] + subt[]
 211 * D1:    pointer na znaky (zadani)
 212 *
 213 C2ORD   MICRO   CSRB.F P        C(A): _ORD
 214 *
 215 RO_R2A
 216         GOSUB   RO_START
 217         CSRB.F  A               # nibble -> byte
 218 * D1:   pointer na znaky
 219 * C(A): pocet znaku
 220         C=C-1   A
 221         LA(5)   MAXRO
 222         ?C>=A   A               prilis dlouhe nebo kratke zadani?
 223         GOYES   RO_R2A_ERROR
 224         R2=C.F  A               R2(A): pocet znaku
 225         GOSUB   RO_SROMT        R3(A): sromt[]
 226         LC(5)   2*5             C(A):  delka addt[] + subt[]
 227         GOSUB   RO_A2R_MEM      D0:    pointer na addt[] + subt[]
 228 *
 229         C=0     A               Vynulovat:
 230         R4=C    A               - pocet stejnych nebo mensich
 231         DAT0=C  A               - addt[]
 232         D0=D0+  5
 233         DAT0=C  A               - subt[]
 234         D0=D0-  5               D0:   pointer na addt[] + subt[]
 235 *
 236         C=C-1   A               C(A): 0xFFFFF
 237         D=C     A               D(0): prechozi _IDX
 238 *-------------------------------*
 239 *   ZPRACOVANI JEDNOHO ZNAKU    *
 240 *-------------------------------*
 241 RO_R2A_LOOP
 242         AD0EX                   A(A): pointer na addt[] + subt[]
 243         C=R3.F  A
 244         D0=C                    D0:   sromt[]
 245         C=DAT1  B
 246         B=C     B               B(B): znak ze zadani
 247         D0=D0-  NB4BT
 248 -
 249         D0=D0+  NB4BT           dalsi znak v sromt[]
 250         C=DAT0  B               C(B): znak z tabulky sromt[]
 251         ?C#0    B               tabulka pokracuje?
 252         GOYES   +               - ano
 253 RO_R2A_ERROR
 254         GOTO    RO_ERROR_VAL
 255 +
 256         ?C#B    B               znaky zadani:tabulka jsou ruzne?
 257         GOYES   -               - ano
 258         AD0EX                   D0:   pointer na addt[] + subt[]
 259 *                               A(A): adresa nalezu v sromt[]
 260         C=R3.F  A               C(A): sromt[]
 261         A=A-C   A               A(A): rozdil pointeru
 262         ASRB.F  A               # nibble -> byte == _IDX
 263         R0=A.F  A               R0(A): _IDX
 264         LC(1)   #1              maska
 265         A=A&C   P               A(0):  _WHT
 266         A=A+A   P
 267         A=A+A   P               A(0):  _WHT << 2
 268         A=A+1   P
 269         R1=A.F  P               R1(0): _INC
 270 *
 271         A=0     A               A(A):  smask
 272         C=R0.F  A               C(A):  _IDX
 273         ?C<D    A               aktualni _IDX  >=  prechozi _IDX?
 274         GOYES   +               - ne,  smask: 0
 275         A=A-1   A               - ano, smask: -1
 276 +
 277         C=R4    A               C(A):  less
 278         C=C-A   A               C(A):  less - smask
 279         C=C&A   A               C(A):  less - smask  &  smask
 280         R4=C    A               R4(A): nova hodnota less
 281         C=C-CON A,3             less > 3?
 282         GONC    RO_R2A_ERROR    - ano
 283 *
 284         C=R0.F  A               C(A): _IDX
 285         ?C<=D   A               aktualni _IDX  <=  prechozi _IDX
 286         GOYES   RO_R2A_SUMM     - ano
 287 *-------------------------------*
 288 *     AKTUALNI > PREDCHOZI      *
 289 *-------------------------------*
 290         C=R4    A               C(A):  less
 291         C=C-CON A,2             less >= 2?
 292         GONC    RO_R2A_ERROR    - ano
 293 *
 294         C=D     A               C(A): prechozi _IDX
 295         C2ORD                   C(A): _ORD
 296         AD0EX
 297         D0=A                    A(A): addt[]
 298         A=A+C   A               A(A): addt[] + _ORD
 299         AD0EX                   A(A): addt[]
 300         C=DAT0  P               D0:   addt[] + _ORD
 301         B=C     P               B(0): addt[_ORD]
 302         C=0     P
 303         DAT0=C  P               addt[_ORD] = 0
 304         D0=D0+  5               D0:   subt[] + _ORD
 305         C=B     P               C(0): addt[_ORD]
 306         DAT0=C  P               subt[_ORD] = addt[_ORD]
 307         AD0EX                   D0:   addt[]
 308         C=R0.F  A               C(A): _IDX
 309 *-------------------------------*
 310 *   PRICTENI AKTUALNI HODNOTY   *
 311 *-------------------------------*
 312 RO_R2A_SUMM
 313         D=C     A               D(A): nove prechozi _IDX
 314         C2ORD                   C(A): _ORD
 315         AD0EX
 316         D0=A                    A(A): addt[]
 317         A=A+C   A               A(A): addt[] + _ORD
 318         AD0EX                   D0:   addt[] + _ORD
 319         C=DAT0  P
 320         B=C     P               C(0): addt[_ORD]
 321         C=R1.F  P
 322         C=C+B   P               C(0): addt[_ORD] + _INC
 323         DAT0=C  P
 324         AD0EX                   D0:   pointer na addt[] + subt[]
 325         C=C+CON P,6             prirustek stejneho radu v norme?
 326         GONC    +               - ano
 327         GOTO    RO_R2A_ERROR
 328 +
 329         C=R2.F  A               C(A): zbyvajici pocet znaku
 330         C=C-1   A               jeste nejake znaky ze zadani?
 331         GOC     +               - ne, hotovo
 332         R2=C.F  A
 333         D1=D1+  NB4BT           dalsi znak ze zadani
 334         GOTO    RO_R2A_LOOP     - ano, pokracovat
 335 +
 336 *-------------------------------*
 337 *     VYSLEDEK A JEHO DELKA     *
 338 *-------------------------------*
 339         A=DAT0  A               cely obsah addt[]
 340         D0=D0+  5
 341         C=DAT0  A               cely obsah subt[]
 342         SETDEC
 343         A=A-C   A               A(A): vysledek!
 344         SETHEX
 345         LC(5)   #10000
 346         B=C     A
 347         LC(5)   5
 348 -
 349         BSR     A
 350         C=C-1   P
 351         ?A<B    A               je cislo mensi?
 352         GOYES   -               - ano
 353         R2=C.F  A               R2(A): delka - 1
 354         R3=A.F  A               R3(A): hodnota
 355 *-------------------------------*
 356 * ULOZIT RETEZEC DO NOVEHO OBJ. *
 357 *-------------------------------*
 358         C=C+CON A,5+5+1         mnozstvi pameti vcetne prologu a delky
 359         GOSBVL  =GETTEMP
 360         CD0EX
 361         D0=C
 362         R0=C.F  A               R0(A): pointer na novy objekt
 363         LC(5)   =DOINT
 364         DAT0=C  A               prolog
 365         D0=D0+  5               preskocit prolog
 366         C=R2.F  A               C(A): delka - 1
 367         C=C+CON A,5+1           hodnota je vcetne pole delky
 368         DAT0=C  A               delka
 369         D0=D0+  5               preskocit delku na zacatek objektu
 370         C=R2.F  A               C(A): delka - 1
 371         A=R3.F  A               A(A): hodnota
 372 -
 373         DAT0=A  P               cifra ulozena
 374         D0=D0+  1               pointer na dalsi cifru
 375         ASR     A               A(P): dalsi cifra
 376         C=C-1   P               hotovo?
 377         GONC    -               - ne, dalsi
 378         GOTO    RO_DONE
 379 
 380 *===============================*
 381 *  START: ADRESA+DELKA OBJEKTU  *
 382 *===============================*
 383 * VSTUP:  D1:   pointer na prvni uroven RPL-stacku
 384 * VYSTUP: D1:   zacatek objektu (za prologem a delkou)
 385 *         C(A): delka objektu [nibble]
 386 * ZMENY:  N/A
 387 RO_START
 388         GOSBVL  =SAVPTR
 389         C=DAT1  A
 390         D1=C                    D1: adresa objektu na RPL-stacku
 391         D1=D1+  5               preskocit prolog
 392         C=DAT1  A               C:  delka...
 393         C=C-CON A,5             ...bez velikosti pole delky
 394         D1=D1+  5               preskocit delku na zacatek objektu
 395         RTN
 396 
 397 *===============================*
 398 *    TABULKA RIMSKYCH CISLIC    *
 399 *===============================*
 400 * VSTUP:  N/A
 401 * VYSTUP: R3(A): pointer na tabulku
 402 * ZMENY:  C(A)
 403 RO_SROMT
 404         GOSUB   +
 405         CON(2)  'I'
 406         CON(2)  'V'
 407         CON(2)  'X'
 408         CON(2)  'L'
 409         CON(2)  'C'
 410         CON(2)  'D'
 411         CON(2)  'M'
 412         CON(2)  0               konec tabulky
 413 +
 414         C=RSTK
 415         R3=C.F  A
 416         RTN
 417 ENDCODE"

Každému je hned na první pohled jasné, že zdrojový text roman.a není pouhou transkripcí modulu roman.c do jazyka symbolických adres procesoru Saturn. Pro ty, kterým to na první pohled jasné není, je tu nápověda: v celém programu se ani v nejmenším nevyskytuje násobení dvou proměnných, natož dělení! Těmto operacím se díky vlastnostem Saturnovým dalo vtipně vyhnout.

Dalším zcela zřejmým rozdílem je jiný přístup v řešení převodu římských čísel na arabská. Je to sice okaté, ale kdyby náhodou někdo tápal, budiž mu pomůckou obsah následující kapitoly. V té je zobrazen modul r2a2.c (pozor, neplést s R2-D2 :-), který nový postup ukazuje. Související indicií je absence tabulky svalt[]. Prostě, dělá se to jinak, tak to jde i bez ní.

Pozn.: Operandy, které program zpracovává, mají různou bitovou šíři. BCD cifra zabere 4 bity (tj. 1 nibble), znak textového řetězce "měří" 1 bajt (2 nibbles), ... Největší šířka operandu nepřekročí 20 bitů (tedy 5 nibbles).


Převod R→A trochu jinak

  

Modul r2a2.c, jehož výpis následuje, není určen pro samostatný překlad. Obě obsažené funkce (r2a2() i r2a2_value()) mají třídu uložení static. Při potřebě vyzkoušet kód modulu r2a2.c je třeba vložit jeho obsah do zdrojového textu roman.c a v jeho funkci operate() změnit volání funkce r2a() na r2a2(). To ale nikdo dělat nebude, pročež následující výpis má poslání toliko ilustrativní.

   1 /*============================================================================*\
   2                                 RIMSKE --> ARABSKE
   3 \*============================================================================*/
   4 
   5 
   6 #define  R2A2_ORDER     4       // nejvyse 4 dekadicke rady
   7 #define  R2A2_MAXORD    1000    // 10 ^ R2A2_ORDER
   8 
   9 
  10 
  11 /*
  12  * SESTAVENI HODNOTY Z POLE CIFER
  13  */
  14 
  15 static int r2a2_value(int const valt[])
  16 {
  17     int     order,
  18             value;
  19 
  20     for(order = 1, value = 0;  order <= R2A2_MAXORD;  order *= 10, ++valt)
  21         value += valt[0] * order;
  22     return(value);
  23 }
  24 
  25 
  26 
  27 /*
  28  * VSTUPNI BOD
  29  */
  30 
  31 static void r2a2(char const *valup)
  32 {
  33 #define  THIS_ORD(i)    ((i) >> 1)
  34 #define  THIS_WHT(i)    ((i) & 001)
  35 #define  THIS_INC(i)    (THIS_WHT(i) << 2 | 001)
  36 
  37     int     pidx,
  38             less;
  39     int     addt[R2A2_ORDER],
  40             subt[R2A2_ORDER];
  41 
  42     for(pidx = 0;  pidx < R2A2_ORDER;  ++pidx)
  43     {
  44         addt[pidx] = 0;
  45         subt[pidx] = 0;
  46     }
  47     pidx = sizeof(sromt) / sizeof(*sromt) - 1;
  48     less = 0;
  49     do
  50     {
  51         int         aidx;
  52         char const  *fndp;
  53 
  54         if((fndp = strchr(sromt, toupper(*valup))) == NULL)
  55         {
  56             fprintf(stderr, "Unknown Digit: %s\n", valup);
  57             return;
  58         }
  59         aidx = fndp - sromt;
  60         do
  61         {
  62 #ifdef HAVE_CONDITION
  63             less  =  aidx < pidx  ?  0  :  less + 1;
  64 #else
  65             int     smask;
  66 
  67             smask = -(aidx >= pidx);
  68             less  =  less - smask  &  smask;
  69 #endif
  70             if(less <= 3)
  71             {
  72                 if(aidx <= pidx)
  73                     break;
  74                 if(less <= 1)
  75                 {
  76                     pidx = THIS_ORD(pidx);
  77                     subt[pidx] = addt[pidx];
  78                     addt[pidx] = 0;
  79                     break;
  80                 }
  81             }
  82             fprintf(stderr, "Unexpected Digit: %s\n", valup);
  83             return;
  84         } while(0);
  85         pidx = aidx;
  86         if((addt[THIS_ORD(aidx)] += THIS_INC(aidx)) > 9)
  87         {
  88             fprintf(stderr, "Too much Digits: %s\n", valup);
  89             return;
  90         }
  91     } while(*++valup != '\0');
  92     printf("%d\n", r2a2_value(addt) - r2a2_value(subt));
  93 
  94 #undef   THIS_ORD
  95 #undef   THIS_WHT
  96 #undef   THIS_INC
  97 }
  98 
  99 #undef   R2A2_ORDER
 100 #undef   R2A2_MAXORD

Obsah modulu r2a2.c je snadno srozumitelný, přesto stojí za to se u některých detailů pozastavit.

  1. Předně je to hodnota indexu římské cirfy (písmene) z tabulky sromt[] (viz roman.c). Index je v modulu r2a2.c určen výrazem aidx = fndp - sromt;
  2. Další zajímavostí jsou makra THIS_ORD(), THIS_WHT() a THIS_INC(). Jejich suffixy figurují v komentářích zdrojového textu roman.a ve stejných rolích jako v r2a2.c. Významy maker začínajících THIS_ nejlépe vysvětluje následující tabulka.

CIFRA I N D E X inc Vztahy mezy hodnotami
idx ord wht
I 0 000 0 0 1
idx  =  ord << 1  |  wht;
ord  =  idx >> 1;
wht  =  idx & 001;

inc  =  wht << 2  | 001;
inc  =  (idx & 001) << 2 | 001;
V 1 001 0 1 5
X 2 010 1 0 1
L 3 011 1 1 5
C 4 100 2 0 1
D 5 101 2 1 5
M 6 110 3 0 1

Závěr

  

Jedno z předchozích řešení převodu mezi čísly římskými a arabskými je v jazyku C přímo pro srdce HP-50g, tedy procesor ARM9. Vyznačuje se těmito vlatnostmi:

Vhozenou rukavicí by mohl být právě assembler pro Saturn. Rychlost je vyhovující (v průměru necelých 8 ms na dvojici převodů "tam a zpátky"), délka 546 bajtů jako z říše snů i proti UserRPL verzi (ta je více než dvojnásobná), ale tím výhody končí. Stačí se podívat na zdrojový text (i přes bohaté komentáře těžko srozumitelný) a zhodnotit, jak dlouho byl program vytvářen: bylo to několik dní! O opakovaných událostech nechvalně známých pod jmény Hardware reset, Memory Reset, Memory loss, ... z důvodu chyb ve vytvářeném programu ani nemluvě. Snad jen komfort, který nabízí debugger vývojového prostředí Jazz, četnost těchto nepříjemných zážitků snižoval.

Jaké je tedy resumé? Je to nenahraditelná zkušenost. A to i navzdory faktu, že Saturn se od roku 2003 nevyrábí a mimo sféru kalkulátorů by těžko hledal použití. Rozhodně to stálo za to, protože „Kdo nezkusil zkrotit Saturna, ví kulový o tom, jak se píše firmware pro pořádnou kalkulajdu“. Přesto se silně nedoporučuje preferovat tento styl programování. Vynaložené úsilí totiž naprosto neodpovídá dosaženému výsledku. Ale frajeřina je to ukrutná :-)

Pokud se někdo (nehledě na uvedené přitěžující okolnosti) cítí touto problematikou býti osloven, je zde pár drobtů ke stažení.

Zdrojové texty Binární kód Vše naráz
roman.c Výchozí zdrojový text v jazyku C ROMANSAT romansat.tar
r2a2.c Zdrojový text v jazyku C - modifikovaná funkce pro převod R→A
roman.a Zdrojový text v assembleru pro procesor Saturn