110 lines
2.6 KiB
Text
110 lines
2.6 KiB
Text
org 100h
|
|
jmp test
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Takes a zero-terminated Roman numeral string in BC
|
|
;; and returns 16-bit integer in HL.
|
|
;; All registers destroyed.
|
|
roman: dcx b
|
|
romanfindend: inx b ; load next character
|
|
ldax b
|
|
inr e
|
|
ana a ; are we there yet
|
|
jnz romanfindend
|
|
lxi h,0 ; zero HL to hold the total
|
|
push h ; stack holds the previous roman numeral
|
|
romanloop: dcx b ; get next roman numeral
|
|
ldax b ; (work backwards)
|
|
call romandgt
|
|
jc romandone ; carry set = not Roman anymore
|
|
xthl ; load previous roman numeral
|
|
call cmpdehl ; DE < HL?
|
|
mov h,d ; in any case, DE is now the previous
|
|
mov l,e ; Roman numeral
|
|
xthl ; bring back the total
|
|
jnc romanadd
|
|
mov a,d ; DE (current) < HL (previous)
|
|
cma ; so this Roman digit must be subtracted
|
|
mov d,a ; from the total.
|
|
mov a,e ; so we negate it before adding it
|
|
cma ; two's complement: -de = (~de)+1
|
|
mov e,a
|
|
inx d
|
|
romanadd: dad d ; add to running total
|
|
jmp romanloop
|
|
romandone: pop d ; remove temporary variable from stack
|
|
ret
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; 16-bit compare DE with HL, set flags
|
|
;; accordingly. A destroyed.
|
|
cmpdehl: mov a,d
|
|
cmp h
|
|
rnz
|
|
mov a,e
|
|
cmp l
|
|
ret
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Takes a single Roman 'digit' in A,
|
|
;; and returns its value in DE (0 if invalid)
|
|
;; All other registers preserved.
|
|
romandgt: push h ; preserve hl for the caller
|
|
lxi h,romantab
|
|
mvi e,7 ; e=counter
|
|
romandgtl: cmp m ; check table entry
|
|
jz romanfound
|
|
inx h ; move to next table entry
|
|
inx h
|
|
inx h
|
|
dcr e ; decrease counter
|
|
jnz romandgtl
|
|
pop h ; we didn't find it
|
|
stc ; set carry
|
|
ret ; return with DE=0
|
|
romanfound: inx h ; we did find it
|
|
mov e,m ; load it into DE
|
|
inx h
|
|
mov d,m
|
|
pop h
|
|
ana a ; clear carry
|
|
ret
|
|
romantab: db 'I',1,0 ; 16-bit little endian values
|
|
db 'V',5,0
|
|
db 'X',10,0
|
|
db 'L',50,0
|
|
db 'C',100,0
|
|
db 'D',0f4h,1
|
|
db 'M',0e8h,3
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; The following is testing and I/O code.
|
|
test: mvi c,10 ; read string from console
|
|
lxi d,bufdef
|
|
call 5
|
|
mvi c,9 ; print newline
|
|
lxi d,nl
|
|
call 5
|
|
lxi b,buf ; run `roman' on the input string
|
|
call roman ; the result is now in hl
|
|
lxi d,-10000
|
|
call numout ; print 10000s digit
|
|
lxi d,-1000
|
|
call numout ; print 1000s digit
|
|
lxi d,-100
|
|
call numout ; print 100s digit
|
|
lxi d,-10
|
|
call numout ; print 10s digit
|
|
lxi d,-1 ; ...print 1s digit
|
|
numout: mvi a,-1
|
|
push h
|
|
numloop: inr a
|
|
pop b
|
|
push h
|
|
dad d
|
|
jc numloop
|
|
adi '0'
|
|
mvi c,2
|
|
mov e,a
|
|
call 5
|
|
pop h
|
|
ret
|
|
nl: db 13,10,'$'
|
|
bufdef: db 16,0
|
|
buf: ds 17
|