Jump to content

Letter frequency: Difference between revisions

Add 8080 assembly version
No edit summary
(Add 8080 assembly version)
Line 8:
but some only count letters A to Z.
<br><br>
 
=={{header|8080 Assembly}}==
 
This program prints the frequency of each printable ASCII character
contained in the file.
 
<lang 8080asm>bdos: equ 5 ; CP/M syscalls
putch: equ 2 ; Print a character
puts: equ 9 ; Print a string
fopen: equ 15 ; Open a file
fread: equ 20 ; Read a file
fcb: equ 5ch ; FCB for file given on command line
dma: equ 80h ; Default DMA
org 100h ; CP/M loads the program starting at page 1
;; Zero out pages two and three (to keep a 16-bit counter
;; for each possible byte in the file).
;; We can do this because this program is small enough to
;; fit in page 1 in its entirety.
xra a ; Zero A.
mov b,a ; Zero B too (make it loop 256 times)
lxi d,200h ; Start of page two
zero: stax d ; Zero out a byte (store A, which is zero)
inx d ; Next byte
stax d ; Zero out another byte
inx d ; Next byte
dcr b ; Decrement the loop counter.
jnz zero ; Continue until B comes back to zero.
;; Open the file given on the command line.
lxi d,fcb ; CP/M always tries to parse the command line,
mvi c,fopen ; and gives us a file "object" in page zero.
call bdos ; We can just call fopen on it.
inr a ; It sets A=FF on error, so if incrementing A
jz error ; rolls back over to 0, that's an error.
;; Process the file record by record.
;; In CP/M, each file consists of a number of 128-byte
;; records. An exact size is not kept.
;; If a text file is not an exact multiple of 128 bytes
;; long, the last record will contain a ^Z (26 decimal),
;; and anything after that byte should be ignored.
read: lxi d,fcb ; From the file control block (the "object"),
mvi c,fread ; read one record. By default it ends up in
call bdos ; the last half of page zero.
ana a ; Zero carry flag.
rar ; Low bit says if end reached
jc output ; If so, go print the table
ana a ; If any other bits are set, that's a
jnz error ; read error.
;; Count the characters in the current record.
lxi d,dma-1 ; Set DE to point just before the record
byte: inr e ; Go to the next byte.
jz read ; If end of record, go get next record.
ldax d ; Grab the current byte
cpi 26 ; If it is EOF, we're done.
jz output ; Go print the table
mov l,a ; Otherwise, increment the counter for this
mvi h,2 ; character: the low byte is kept in page 2.
inr m ; 'm' means the value in memory at HL.
jnz byte ; If no rollover, we're done; count next byte
inr h ; But we're keeping a 16-bit counter, so
inr m ; if there is rollover, increment high byte.
jmp byte ; The high byte is in page 3 -unorthodox, but
; it's easy to access here.
;; We've done the whole file. For each printable
;; ASCII character (32..126), print the character and
;; the count.
output: mvi a,32 ; Start at 32.
;; Print a character and its counter
char: mov l,a ; Load 16-bit counter into DE. Low byte
mvi h,2 ; is in page 2 at a;
mov e,m
inr h ; And the high byte is in page 3.
mov d,m
mov a,d ; Test if the counter is zero
ora e
mov a,l ; Put the character back in A
jz next ; If zero, don't print anything.
push psw ; If not, push the character,
push d ; and the counter.
mvi c,putch ; Print the current character
mov e,a
call bdos
lxi d,separator ; Then print ': '
call outs
;; Then convert the counter to ASCII
pop d ; Retrieve the counter
lxi h,numend ; Get pointer to end of digit string
push h ; And put it on the stack
dgtloop: xchg ; Put counter in HL (16-bit accumulator)
lxi b,-10 ; Dividend is 10
mov d,b ; Start quotient at -1 (we'll loop once
mov e,b ; too many, this corrects for it)
divloop: inx d ; Increment the quotient,
dad b ; subtract 10 from the dividend,
jc divloop ; and keep doing it until it goes negative
lxi b,10+'0' ; Add 10 back to get the remainder,
dad b ; plus '0' to make it ASCII.
mov a,l
pop h ; Retrieve digit pointer
dcx h ; Decrement it (to point at current digit)
mov m,a ; Store the digit
push h ; And store the new pointer
mov a,d ; Check if the quotient is now zero
ora e
jnz dgtloop ; If not, do the next digit.
pop d ; Set DE to point at the first digit
call outs ; And output it as a string.
pop psw ; Restore the character
next: inr a ; Increment it
cpi 127 ; Did we just do the last character?
jnz char ; If not, go do the next character.
ret ; If so, we're done.
;; Print the error message
error: lxi d,errmsg
;; Print string
outs: mvi c,puts
jmp bdos
;; Strings
errmsg: db '?$' ; "Error message" (if file error)
separator: db ': $' ; Goes in between character and number
number: db '00000' ; Space to keep ASCII representation of
numend: db 13,10,'$' ; a 16-bit number, plus newline.
 
</lang>
 
=={{header|ACL2}}==
2,124

edits

Cookies help us deliver our services. By using our services, you agree to our use of cookies.