第 17 章 17.3 节示例
可运行的完整测试程序如下:
assume cs:code,ds:stack
; 声明字符栈
stack segment
db 128 dup (0)
stack ends
code segment
start: mov ax,stack
mov ds,ax
mov si,0
mov dh,8 ; 行号:8
mov dl,4 ; 列号:4
call getstr
mov ax,4c00h
int 21h
getstr: push ax
getstrs: mov ah,0 ; 调用 int 16h 中断(参 17.2 节)的 0 号功能
int 16h
cmp al,20h
jb nochar ; ASCII 码小于 20h,说明不是字符
mov ah,0
call charstack ; 字符入栈
mov ah,2
call charstack ; 显示栈中的字符
jmp getstrs
nochar: cmp ah,0Eh ; 退格键的扫描码
je backspace
cmp ah,1Ch ; Enter 键的扫描码
je enter
jmp getstrs
backspace: mov ah,1
call charstack ; 字符出栈
mov ah,2
call charstack ; 显示栈中的字符
jmp getstrs
enter: mov al,0
mov ah,0
call charstack ; 0 入栈
mov ah,2
call charstack ; 显示栈中的字符
pop ax
ret
charstack: jmp short charstart
table dw charpush,charpop,charshow
top dw 0 ; 栈顶
charstart: push bx
push dx ; 将存储着行、列信息的 DX 寄存器数据入栈。注意,这不是字符栈
push di
push es
cmp ah,2
ja sret
mov bl,ah
mov bh,0
add bx,bx
jmp word ptr table[bx]
sret: pop es
pop di
pop dx
pop bx
ret
charpush: mov bx,top
mov [si][bx],al ; 关于 (si) 参见上面的“参数说明”所述
inc top
jmp sret
charpop: cmp top,0
je sret
dec top
mov bx,top
mov al,[si][bx]
jmp sret
charshow: mov bx,0B800h
mov es,bx
; 添加:调用 BIOS 的 int 10h 中断例程,以定位光标位置
mov bx,0
int 10h
mov cx,dx ; 添加:将 DX 寄存器存储的行、列信息转存到 CX 寄存器
mov al,160
mov ah,0
mul dh ; DH 寄存器存放行号,执行 (al)×(dh) 乘法运算,结果存放在 AX 寄存器中
mov di,ax
add dl,dl ; DL 寄存器存放列号
mov dh,0
add di,dx ; 这时,DI 寄存器将存放着需要在显示缓冲区显示字符的屏幕具体位置
charshows: cmp bx,top ; 比较 (bx) 和 top,以判断字符栈是否到达栈顶
jne noempty
mov byte ptr es:[di],' ' ; 如果字符栈已经到达栈顶,则在屏幕显示一个空格字符后退出
mov byte ptr es:[di+1],64 ; 设置字符属性:背景色为红色
jmp sret
noempty: mov al,[si][bx]
mov es:[di],al
mov byte ptr es:[di+1],2 ; 设置字符属性:绿色字体
mov byte ptr es:[di+2],' ' ; 在屏幕所显示字符的后一个屏幕位置显示一个空格字符,以表示下一个要显示的字符将会在此位置显示、输出
mov byte ptr es:[di+3],64 ; 设置字符属性:背景色为红色
inc bx
add di,2
; 添加:调用 BIOS 的 int 10h 中断例程,以定位光标位置
; 由于 (bx) 的初始值为 0,而屏幕一行最多容纳 80 个字符,则 (bh)=0,所以无需设置 (bh)
inc cl ; 增加一列,以令光标向后移动一列
mov ah,2
mov dx,cx
int 10h
jmp charshows
code ends
end start
程序说明:本程序代码添加了利用 BIOS 的 int 10h 中断例程来定位光标(参 13.6 节),所添加的代码均在其注释处写了“添加”字样。