A0 00 84 FD A2 00 B1 FB F0 0E C8 C9 29 18 F0 06 8A 48 E6 FD 90 EE B0 0A E0 01
90 06 E0 02 38 D0 01 18 A5 FD F0 09 C6 FD 68 AA E8 B0 F5 90 D7 60
内の文字列へのポインタを期待$fb
/ $fc
だけに期待されている含まれている(
と)
。文字列が「バランスの取れた」場合はC(キャリー)フラグをクリアし、そうでない場合は設定します(6502の典型的なイディオムで、キャリーを「on error」に設定します)。無効な入力に対しては意味がありません。
アルゴリズムは再帰的ですが、それ自体を呼び出しません(より多くのバイトとし、コードの位置に依存します)代わりに、再帰の深さ自体を維持し、「単純な」分岐を使用します。
コメント付きの分解
; function to determine a string is "paranthesly balanced"
;
; input:
; $fb/$fc: address of the string
; output:
; C flag set if not balanced
; clobbers:
; $fd: recursion depth
; A,X,Y
.isparbal:
A0 00 LDY #$00 ; string index
84 FD STY $FD ; and recursion depth
.isparbal_r:
A2 00 LDX #$00 ; set counter for parantheses pairs
.next:
B1 FB LDA ($FB),Y ; load next character
F0 0E BEQ .done ; end of string -> to final checks
C8 INY ; increment string index
C9 29 CMP #$29 ; compare with ')'
18 CLC ; and reset carry
F0 06 BEQ .cont ; if ')' do checks and unwind stack
8A TXA ; save counter ...
48 PHA ; ... on stack
E6 FD INC $FD ; increment recursion depth
90 EE BCC .isparbal_r ; and recurse
.cont:
B0 0A BCS .unwind ; on previous error, unwind directly
.done:
E0 01 CPX #$01 ; less than one parantheses pair
90 06 BCC .unwind ; -> ok and unwind
E0 02 CPX #$02 ; test for 2 parantheses pairs
38 SEC ; set error flag
D0 01 BNE .unwind ; if not 2 -> is error and unwind
18 CLC ; clear error flag
.unwind:
A5 FD LDA $FD ; check recursion depth
F0 09 BEQ .exit ; 0 -> we're done
C6 FD DEC $FD ; otherwise decrement
68 PLA ; get "pair counter" ...
AA TAX ; ... from stack
E8 INX ; and increment
B0 F5 BCS .unwind ; continue unwinding on error
90 D7 BCC .next ; otherwise continue reading string
.exit:
60 RTS
ルーチンを使用したC64アセンブラープログラムの例:
オンラインデモ
ca65構文のコード:
.import isparbal ; link with routine above
.segment "BHDR" ; BASIC header
.word $0801 ; load address
.word $080b ; pointer next BASIC line
.word 2018 ; line number
.byte $9e ; BASIC token "SYS"
.byte "2061",$0,$0,$0 ; 2061 ($080d) and terminating 0 bytes
.bss
linebuf: .res 256
.data
prompt: .byte "> ", $0
truestr: .byte "true", $0
falsestr: .byte "false", $0
.code
inputloop:
lda #<prompt ; display prompt
ldy #>prompt
jsr $ab1e
lda #<linebuf ; read string into buffer
ldy #>linebuf
ldx #0 ; effectively 256
jsr readline
lda #<linebuf ; address of string to $fb/fc
sta $fb
lda #>linebuf
sta $fc
jsr isparbal ; call function
bcs isfalse
lda #<truestr
ldy #>truestr
bne printresult
isfalse: lda #<falsestr
ldy #>falsestr
printresult: jmp $ab1e ; output true/false and exit
; read a line of input from keyboard, terminate it with 0
; expects pointer to input buffer in A/Y, buffer length in X
.proc readline
dex
stx $fb
sta $fc
sty $fd
ldy #$0
sty $cc ; enable cursor blinking
sty $fe ; temporary for loop variable
getkey: jsr $f142 ; get character from keyboard
beq getkey
sta $2 ; save to temporary
and #$7f
cmp #$20 ; check for control character
bcs checkout ; no -> check buffer size
cmp #$d ; was it enter/return?
beq prepout ; -> normal flow
cmp #$14 ; was it backspace/delete?
bne getkey ; if not, get next char
lda $fe ; check current index
beq getkey ; zero -> backspace not possible
bne prepout ; skip checking buffer size for bs
checkout: lda $fe ; buffer index
cmp $fb ; check against buffer size
beq getkey ; if it would overflow, loop again
prepout: sei ; no interrupts
ldy $d3 ; get current screen column
lda ($d1),y ; and clear
and #$7f ; cursor in
sta ($d1),y ; current row
output: lda $2 ; load character
jsr $e716 ; and output
ldx $cf ; check cursor phase
beq store ; invisible -> to store
ldy $d3 ; get current screen column
lda ($d1),y ; and show
ora #$80 ; cursor in
sta ($d1),y ; current row
lda $2 ; load character
store: cli ; enable interrupts
cmp #$14 ; was it backspace/delete?
beq backspace ; to backspace handling code
cmp #$d ; was it enter/return?
beq done ; then we're done.
ldy $fe ; load buffer index
sta ($fc),y ; store character in buffer
iny ; advance buffer index
sty $fe
bne getkey ; not zero -> ok
done: lda #$0 ; terminate string in buffer with zero
ldy $fe ; get buffer index
sta ($fc),y ; store terminator in buffer
sei ; no interrupts
ldy $d3 ; get current screen column
lda ($d1),y ; and clear
and #$7f ; cursor in
sta ($d1),y ; current row
inc $cc ; disable cursor blinking
cli ; enable interrupts
rts ; return
backspace: dec $fe ; decrement buffer index
bcs getkey ; and get next key
.endproc