6502芯片:字符分类(Character Classifica
2021-05-25 本文已影响0人
苹果王子刘泽庆
标准的C库提供了一组用于分类(例如是字母,是数字,是ASCII,是大写,等等)和修改(例如变成大写和小写)定义在标题中称为<ctype.h>的字符的函数。本节描述如何在6502汇编程序中编码一组类似的功能。有两种技术可以用于解决这个问题,即比较或查找表。
注意:这些函数将仅限于普通ASCII字符范围7F。
实现字符分类所需的查找表需要每个字符一个字节。查找表中的位表示字符是如何分类的(例如,控制字符、可打印字符、空格、十进制数字、十六进制数字、标点、大写字母或小写字母)。为了测试一个字符的特定分类,你可以从表中加载它的描述字节,并测试是否存在某些位(例如用AND 指令)。
; Constants describing the role of each classification bit
_CTL EQU $80
_PRN EQU $40
_WSP EQU $20
_PCT EQU $10
_UPR EQU $08
_LWR EQU $04
_DGT EQU $02
_HEX EQU $01
; Test if the character in A is a control character
ISCNTRL TAX
LDA #_CTL
BNE TEST
; Test if the character in A is printable
ISPRINT TAX
LDA #_PRN
BNE TEST
; Test if the character in A is punctation
ISPUNCT TAX
LDA #_PCT
BNE TEST
; Test if the character in A is upper case
ISUPPER TAX
LDA #_UPR
BNE TEST
; Test if the character in A is lower case
ISLOWER TAX
LDA #_LWR
BNE TEST
; Test if the character in A is a letter
ISALPHA TAX
LDA #_UPR|_LWR
BNE TEST
; Test if the character in A is a decimal digit
ISDIGIT TAX
LDA #_DGT
BNE TEST
; Test if the character in A is a hexadecimal digit
ISXDIGIT TAX
LDA #_HEX
BNE TEST
; Test if the character in A is letter or a digit
ISALNUM TAX
LDA #_DGT|_UPR|_LWR
; Tests for the required bits in the look up table value
TEST AND CTYPE,X
BEQ FAIL
; Set the carry flag if any target bits were found
PASS TXA
SEC
RTS
; Test if the character in A is in the ASCII range $00-$7F
ISASCII TAX
BPL PASS
; Clear the carry flag if no target bits were found
FAIL TXA
CLC
RTS
; If A contains a lower case letter convert it to upper case
TOUPPER JSR ISLOWER
BCC *+4
AND #$DF
RTS
; If A contains an upper case letter convert it to lower case
TOLOWER JSR ISUPPER
BCC *+4
ORA #$20
RTS
; The lookup table of character descriptions
CTYPE DB _CTL ; NUL
DB _CTL ; SOH
DB _CTL ; STX
DB _CTL ; ETX
DB _CTL ; EOT
DB _CTL ; ENQ
DB _CTL ; ACK
DB _CTL ; BEL
DB _CTL ; BS
DB _CTL|_WSP ; TAB
DB _CTL|_WSP ; LF
DB _CTL|_WSP ; VT
DB _CTL|_WSP ; FF
DB _CTL|_WSP ; CR
DB _CTL ; SO
DB _CTL ; SI
DB _CTL ; DLE
DB _CTL ; DC1
DB _CTL ; DC2
DB _CTL ; DC3
DB _CTL ; DC4
DB _CTL ; NAK
DB _CTL ; SYN
DB _CTL ; ETB
DB _CTL ; CAN
DB _CTL ; EM
DB _CTL ; SUB
DB _CTL ; ESC
DB _CTL ; FS
DB _CTL ; GS
DB _CTL ; RS
DB _CTL ; US
DB _PRN|_WSP ; SPACE
DB _PRN|_PCT ; !
DB _PRN|_PCT ; "
DB _PRN|_PCT ; #
DB _PRN|_PCT ; $
DB _PRN|_PCT ; %
DB _PRN|_PCT ; &
DB _PRN|_PCT ; '
DB _PRN|_PCT ; (
DB _PRN|_PCT ; )
DB _PRN|_PCT ; *
DB _PRN|_PCT ; +
DB _PRN|_PCT ; ,
DB _PRN|_PCT ; -
DB _PRN|_PCT ; .
DB _PRN|_PCT ; /
DB _PRN|_DGT|_HEX ; 0
DB _PRN|_DGT|_HEX ; 1
DB _PRN|_DGT|_HEX ; 2
DB _PRN|_DGT|_HEX ; 3
DB _PRN|_DGT|_HEX ; 4
DB _PRN|_DGT|_HEX ; 5
DB _PRN|_DGT|_HEX ; 6
DB _PRN|_DGT|_HEX ; 7
DB _PRN|_DGT|_HEX ; 8
DB _PRN|_DGT|_HEX ; 9
DB _PRN|_PCT ; :
DB _PRN|_PCT ; ;
DB _PRN|_PCT ; <
DB _PRN|_PCT ; =
DB _PRN|_PCT ; >
DB _PRN|_PCT ; ?
DB _PRN|_PCT ; @
DB _PRN|_UPR|_HEX ; A
DB _PRN|_UPR|_HEX ; B
DB _PRN|_UPR|_HEX ; C
DB _PRN|_UPR|_HEX ; D
DB _PRN|_UPR|_HEX ; E
DB _PRN|_UPR|_HEX ; F
DB _PRN|_UPR ; G
DB _PRN|_UPR ; H
DB _PRN|_UPR ; I
DB _PRN|_UPR ; J
DB _PRN|_UPR ; K
DB _PRN|_UPR ; L
DB _PRN|_UPR ; M
DB _PRN|_UPR ; N
DB _PRN|_UPR ; O
DB _PRN|_UPR ; P
DB _PRN|_UPR ; Q
DB _PRN|_UPR ; R
DB _PRN|_UPR ; S
DB _PRN|_UPR ; T
DB _PRN|_UPR ; U
DB _PRN|_UPR ; V
DB _PRN|_UPR ; W
DB _PRN|_UPR ; X
DB _PRN|_UPR ; Y
DB _PRN|_UPR ; Z
DB _PRN|_PCT ; [
DB _PRN|_PCT ; \
DB _PRN|_PCT ; ]
DB _PRN|_PCT ; ^
DB _PRN|_PCT ; _
DB _PRN|_PCT ; `
DB _PRN|_LWR|_HEX ; a
DB _PRN|_LWR|_HEX ; b
DB _PRN|_LWR|_HEX ; c
DB _PRN|_LWR|_HEX ; d
DB _PRN|_LWR|_HEX ; e
DB _PRN|_LWR|_HEX ; f
DB _PRN|_LWR ; g
DB _PRN|_LWR ; h
DB _PRN|_LWR ; i
DB _PRN|_LWR ; j
DB _PRN|_LWR ; k
DB _PRN|_LWR ; l
DB _PRN|_LWR ; m
DB _PRN|_LWR ; n
DB _PRN|_LWR ; o
DB _PRN|_LWR ; p
DB _PRN|_LWR ; q
DB _PRN|_LWR ; r
DB _PRN|_LWR ; s
DB _PRN|_LWR ; t
DB _PRN|_LWR ; u
DB _PRN|_LWR ; v
DB _PRN|_LWR ; w
DB _PRN|_LWR ; x
DB _PRN|_LWR ; y
DB _PRN|_LWR ; z
DB _PRN|_PCT ; {
DB _PRN|_PCT ; |
DB _PRN|_PCT ; }
DB _PRN|_PCT ; ~
DB _CTL ; DE
如果我们使用比较,那么每个函数将由若干个比较阶段组成,以确定所提供的字符是否有适当的值。在大多数情况下,这些功能都很小,但其中的一两个可能涉及到很多阶段(例如标点符号)。执行时间将根据字符所受测试的次数而变化。
ISUPPER CMP #'A'
BCC FAIL
CMP #'Z'+1
BCS FAIL
; Drop thru here on success
ISLOWER CMP #'a'
BCC FAIL
CMP #'z'+1
BCS FAIL
; Drop thru here on success
ISALPHA CMP #'A'
BCC FAIL
CMP #'Z'+1
BCC PASS
CMP #'a'
BCC FAIL
CMP #'z'+1
BCS FAIL
PASS EQU *
; Drop thru here on success
究竟哪种解决方案最好?在很多情况下,它取决于我们所要编写的程序。如果您只需要一个或两个测试,并且内存大小是个问题,那么比较方法将生成更少的代码,但可能会稍微慢一些(对于复杂的测试),否则查找表是简单和快速的。