如何用汇编语言创建文本编辑器?
How to create a text editor in Assembly language?
到目前为止,我已经创建了一个程序来读取箭头键并在屏幕上移动光标。首先,用户必须输入 0 才能开始,并且可以在 getch() != 27 (ESC) 期间四处移动。但是,光标根本没有移动。
model tiny
.code
org 100h
program:
mov cx, 10
mov ah, 7
int 21h
cmp al, 0 ; start
je clearS ; clear screen
start:
mov ah, 7 ; AL = getch()
int 21h
cmp al, 27 ; ESC
je fin
cmp al, 72
je moveUp
cmp al, 75
je moveLeft
cmp al, 77
je moveRight
cmp al, 80
je moveDown
moveRight:
mov dl, posY
inc dl ; posY ++
mov posY, dl
jmp prntCrs
jmp start
moveLeft:
mov dh, posX
mov dl, posY
dec dl ; posY --
mov posY, dh
jmp prntCrs
jmp start
moveUp:
mov dl, posY
mov dh, posX
dec dh ; posX --
mov posX, dh
jmp prntCrs ; print cursor
jmp start
moveDown:
mov dl, posY
mov dh, posX
inc dh ; posX ++
mov posX, dh
jmp prntCrs
jmp start
prntCrs: ; print cursor
mov ah, 2h
int 10h
clearS: ; clear screen
mov ah, 7
mov al, 25
mov ch, 0
mov cl, 0
mov dh, 24
mov dl, 79
int 10h
mov ah, 2
mov bh, 0
mov dh, 0
mov dl, 0
int 10h
jmp start
fin:int 20h
posX db 1 dup(0) ; dh = posX -> controls row
posY db 1 dup(0) ; dl = posY -> controls column
end program
-------------------------------------------- ----------------------
假设我有这个:
moveDown:
mov dl, posX
mov dh, posY
cmp dh, 9 ; limit
je stayLine
inc dh ; posY ++
mov posY, dh
add curr_line, 36 ;increment by line/string size
jmp prntCrs
goBackLine:
mov dl, posX
mov dh, posY
cmp dh, 1 ; limit
je stayLine
mov dl, 37
dec dh
mov posX, dl
mov posY, dh
sub curr_line, 36 ; go to start of last line
add curr_char, 35 ; to go to last char of last line
jmp prntCrs
nextLine:
mov dl, posX
mov dh, posY
mov dl, 1
inc dh
mov posX, dl
mov posY, dh
add curr_line, 36
mov curr_char, 0 ; or move it to whatever dl is?
jmp prntCrs
posX db 1 dup(1) ; dl = posX -> controls column
posY db 1 dup(1) ; dh = posY -> controls row
xlimit dw 38 ; number of columns (w/ border)
ylimit dw 10 ; number of rows (w/ border)
matrix db 36*8 dup(42)
curr_line dw ? ; pointer to current line
curr_char dw ? ; pointer to current char
如何保存用户输入?
mov si, offset ???
add si, curr_char
mov byte ptr [si], al
mov cl, dl ; to not lose value of posX
mov dl, al ; to be able to print
mov ah, 2h ; character output
int 21h ; display character in dl
mov dl, cl
inc dl ; to move right
mov posX, dl ; update posX
cmp posX, 38
je nextline
inc si
jmp writing
您的代码有一些重要错误:
- DL 代表 X,DH 代表 Y。您没有在标签 "moveLeft"、"moveRight"、"moveUp" 和 "moveDown" 中正确使用它们。
- Int 16h 更适合箭头等特殊键。
- 你每次按键后都在清屏,所以光标每次都会回到左上角。
这是您改进的代码,使用 EMU8086 测试(箭头指向更改):
.model tiny
.code
org 100h
program:
mov cx, 10
mov ah, 7
int 21h
cmp al, 0 ; start
je clearS ; clear screen
start:
mov ah, 0 ;<==================================
int 16h ;<==================================
cmp al, 27 ; ESC
je fin
cmp ax, 4800h ;<==================================
je moveUp
cmp ax, 4B00h ;<==================================
je moveLeft
cmp ax, 4D00H ;<==================================
je moveRight
cmp ax, 5000h ;<==================================
je moveDown
jmp start ;<==================================
moveRight:
mov dl, posX
mov dh, posY ;<==================================
inc dl ; posX ++
mov posX, dl
jmp prntCrs
jmp start
moveLeft:
mov dl, posX ;<==================================
mov dh, posY ;<==================================
dec dl ; posX -- ;<==================================
mov posX, dl ;<==================================
jmp prntCrs
jmp start
moveUp:
mov dl, posX ;<==================================
mov dh, posY ;<==================================
dec dh ; posY --
mov posY, dh ;<==================================
jmp prntCrs ; print cursor
jmp start
moveDown:
mov dl, posX ;<==================================
mov dh, posY ;<==================================
inc dh ; posY ++ ;<==================================
mov posY, dh ;<==================================
jmp prntCrs
jmp start
prntCrs: ; print cursor
mov ah, 2h
int 10h
clearS: ; clear screen
;mov ah, 7 ;<==================================
;mov al, 25 ;<==================================
;mov ch, 0 ;<==================================
;mov cl, 0 ;<==================================
;mov dh, 24 ;<==================================
;mov dl, 79 ;<==================================
;int 10h ;<==================================
;mov ah, 2 ;<==================================
;mov bh, 0 ;<==================================
;mov dh, 0 ;<==================================
;mov dl, 0 ;<==================================
;int 10h ;<==================================
jmp start
fin:int 20h
posX db 1 dup(0) ; dh = posX -> controls row
posY db 1 dup(0) ; dl = posY -> controls column
end program
编辑:现在它显示字符,将字符添加到矩阵,并更新 curr_line
和 curr_char
。我使用颜色是为了好玩。还是要防止游标不超过限制,比如不要超过0列和80列。接下来是新的代码:
.model tiny
.code
org 100h
program:
mov curr_line, offset matrix
mov curr_char, 0
start:
;CAPTURE KEY.
mov ah, 0
int 16h
;EVALUATE KEY.
cmp al, 27 ; ESC
je fin
cmp ax, 4800h ; UP.
je moveUp
cmp ax, 4B00h ; LEFT.
je moveLeft
cmp ax, 4D00H ; RIGHT.
je moveRight
cmp ax, 5000h ; DOWN.
je moveDown
cmp al, 32
jae any_char
jmp start
;DISPLAY LETTER, DIGIT OR ANY OTHER ACCEPTABLE CHAR.
any_char:
mov ah, 9
mov bh, 0
mov bl, color
mov cx, 1 ; how many times display char.
int 10h ; display char in al.
;UPDATE CHAR IN MATRIX.
mov si, curr_line ; si points to the beginning of the line.
add si, curr_char ; si points to the char in the line.
mov [ si ], al ; the char is in the matrix.
;!!! EXTREMELY IMPORTANT : PREVIOUS BLOCK DISPLAYS ONE
;CHAR, AND NEXT BLOCK MOVES CURSOR TO THE RIGHT. THAT'S
;THE NORMAL BEHAVIOR FOR ALL EDITORS. DO NOT MOVE THESE
;TWO BLOCKS, THEY MUST BE THIS WAY. IF IT'S NECESSARY
;TO MOVE THEM, ADD A JUMP FROM ONE BLOCK TO THE OTHER.
;RIGHT.
moveRight:
inc curr_char ; update current char.
mov dl, posX
mov dh, posY
inc dl ; posX ++
mov posX, dl
jmp prntCrs
;LEFT.
moveLeft:
dec curr_char ; update current char.
mov dl, posX
mov dh, posY
dec dl ; posX --
mov posX, dl
jmp prntCrs
;UP.
moveUp:
sub curr_line, 80 ; update current line.
mov dl, posX
mov dh, posY
dec dh ; posY --
mov posY, dh
jmp prntCrs ; print cursor
;DOWN.
moveDown:
add curr_line, 80 ; update current line.
mov dl, posX
mov dh, posY
inc dh ; posY ++
mov posY, dh
jmp prntCrs
prntCrs: ; print cursor
mov ah, 2h
int 10h
jmp start
fin:
int 20h
posX db 1 dup(0) ; dh = posX -> controls row
posY db 1 dup(0) ; dl = posY -> controls column
matrix db 80*25 dup(' ') ; 25 lines of 80 chars each.
curr_line dw ?
curr_char dw ?
color db 2*16+15
;FOR COLORS USE NEXT TABLE:
;
end program
如果您想保存到文件或从文件加载,矩阵将是必需的。此外,矩阵在编辑器的行数超过屏幕大小的情况下很有用,例如,如果矩阵有 100 行(矩阵 db 80*100),当用户按下键时,编辑器的第一行将消失,但是,当用户按下向上键时,可以从矩阵中重新显示第一行。
关于您的逻辑流程的一些要点。 moveRight:
等四个函数,调整光标位置,跳转到prntCrs:
使BIOS调用设置光标位置,然后运行到clearS:
函数,然后跳回start:
这些函数应该 call
ed 并在末尾有一个 ret
指令。
moveDown:
mov dl, posY
mov dh, posX
inc dh ; posX ++
mov posX, dh
call prntCrs ; call not jmp
jmp start
prntCrs: ; print cursor
mov ah, 2h
int 10h
ret ; added ret
此外,在 dh
和 dl
中,您并不总是正确处理行和列,而且您的光标位置变量定义不正确
posX db 1 dup(0) ; dh = posX -> controls row
posY db 1 dup(0) ; dl = posY -> controls column
这些可以是单个字节(也更正了用法)
posX db 0 ; dl = posX <--- swapped register names
posY db 0 ; dh = posY
最后你递增和递减了光标位置,但没有检查它的边界。仅在 > 0 时减少,仅在 < 79 时增加 PosX,在 < 24 时才增加 PosY。
到目前为止,我已经创建了一个程序来读取箭头键并在屏幕上移动光标。首先,用户必须输入 0 才能开始,并且可以在 getch() != 27 (ESC) 期间四处移动。但是,光标根本没有移动。
model tiny
.code
org 100h
program:
mov cx, 10
mov ah, 7
int 21h
cmp al, 0 ; start
je clearS ; clear screen
start:
mov ah, 7 ; AL = getch()
int 21h
cmp al, 27 ; ESC
je fin
cmp al, 72
je moveUp
cmp al, 75
je moveLeft
cmp al, 77
je moveRight
cmp al, 80
je moveDown
moveRight:
mov dl, posY
inc dl ; posY ++
mov posY, dl
jmp prntCrs
jmp start
moveLeft:
mov dh, posX
mov dl, posY
dec dl ; posY --
mov posY, dh
jmp prntCrs
jmp start
moveUp:
mov dl, posY
mov dh, posX
dec dh ; posX --
mov posX, dh
jmp prntCrs ; print cursor
jmp start
moveDown:
mov dl, posY
mov dh, posX
inc dh ; posX ++
mov posX, dh
jmp prntCrs
jmp start
prntCrs: ; print cursor
mov ah, 2h
int 10h
clearS: ; clear screen
mov ah, 7
mov al, 25
mov ch, 0
mov cl, 0
mov dh, 24
mov dl, 79
int 10h
mov ah, 2
mov bh, 0
mov dh, 0
mov dl, 0
int 10h
jmp start
fin:int 20h
posX db 1 dup(0) ; dh = posX -> controls row
posY db 1 dup(0) ; dl = posY -> controls column
end program
-------------------------------------------- ----------------------
假设我有这个:
moveDown:
mov dl, posX
mov dh, posY
cmp dh, 9 ; limit
je stayLine
inc dh ; posY ++
mov posY, dh
add curr_line, 36 ;increment by line/string size
jmp prntCrs
goBackLine:
mov dl, posX
mov dh, posY
cmp dh, 1 ; limit
je stayLine
mov dl, 37
dec dh
mov posX, dl
mov posY, dh
sub curr_line, 36 ; go to start of last line
add curr_char, 35 ; to go to last char of last line
jmp prntCrs
nextLine:
mov dl, posX
mov dh, posY
mov dl, 1
inc dh
mov posX, dl
mov posY, dh
add curr_line, 36
mov curr_char, 0 ; or move it to whatever dl is?
jmp prntCrs
posX db 1 dup(1) ; dl = posX -> controls column
posY db 1 dup(1) ; dh = posY -> controls row
xlimit dw 38 ; number of columns (w/ border)
ylimit dw 10 ; number of rows (w/ border)
matrix db 36*8 dup(42)
curr_line dw ? ; pointer to current line
curr_char dw ? ; pointer to current char
如何保存用户输入?
mov si, offset ???
add si, curr_char
mov byte ptr [si], al
mov cl, dl ; to not lose value of posX
mov dl, al ; to be able to print
mov ah, 2h ; character output
int 21h ; display character in dl
mov dl, cl
inc dl ; to move right
mov posX, dl ; update posX
cmp posX, 38
je nextline
inc si
jmp writing
您的代码有一些重要错误:
- DL 代表 X,DH 代表 Y。您没有在标签 "moveLeft"、"moveRight"、"moveUp" 和 "moveDown" 中正确使用它们。
- Int 16h 更适合箭头等特殊键。
- 你每次按键后都在清屏,所以光标每次都会回到左上角。
这是您改进的代码,使用 EMU8086 测试(箭头指向更改):
.model tiny
.code
org 100h
program:
mov cx, 10
mov ah, 7
int 21h
cmp al, 0 ; start
je clearS ; clear screen
start:
mov ah, 0 ;<==================================
int 16h ;<==================================
cmp al, 27 ; ESC
je fin
cmp ax, 4800h ;<==================================
je moveUp
cmp ax, 4B00h ;<==================================
je moveLeft
cmp ax, 4D00H ;<==================================
je moveRight
cmp ax, 5000h ;<==================================
je moveDown
jmp start ;<==================================
moveRight:
mov dl, posX
mov dh, posY ;<==================================
inc dl ; posX ++
mov posX, dl
jmp prntCrs
jmp start
moveLeft:
mov dl, posX ;<==================================
mov dh, posY ;<==================================
dec dl ; posX -- ;<==================================
mov posX, dl ;<==================================
jmp prntCrs
jmp start
moveUp:
mov dl, posX ;<==================================
mov dh, posY ;<==================================
dec dh ; posY --
mov posY, dh ;<==================================
jmp prntCrs ; print cursor
jmp start
moveDown:
mov dl, posX ;<==================================
mov dh, posY ;<==================================
inc dh ; posY ++ ;<==================================
mov posY, dh ;<==================================
jmp prntCrs
jmp start
prntCrs: ; print cursor
mov ah, 2h
int 10h
clearS: ; clear screen
;mov ah, 7 ;<==================================
;mov al, 25 ;<==================================
;mov ch, 0 ;<==================================
;mov cl, 0 ;<==================================
;mov dh, 24 ;<==================================
;mov dl, 79 ;<==================================
;int 10h ;<==================================
;mov ah, 2 ;<==================================
;mov bh, 0 ;<==================================
;mov dh, 0 ;<==================================
;mov dl, 0 ;<==================================
;int 10h ;<==================================
jmp start
fin:int 20h
posX db 1 dup(0) ; dh = posX -> controls row
posY db 1 dup(0) ; dl = posY -> controls column
end program
编辑:现在它显示字符,将字符添加到矩阵,并更新 curr_line
和 curr_char
。我使用颜色是为了好玩。还是要防止游标不超过限制,比如不要超过0列和80列。接下来是新的代码:
.model tiny
.code
org 100h
program:
mov curr_line, offset matrix
mov curr_char, 0
start:
;CAPTURE KEY.
mov ah, 0
int 16h
;EVALUATE KEY.
cmp al, 27 ; ESC
je fin
cmp ax, 4800h ; UP.
je moveUp
cmp ax, 4B00h ; LEFT.
je moveLeft
cmp ax, 4D00H ; RIGHT.
je moveRight
cmp ax, 5000h ; DOWN.
je moveDown
cmp al, 32
jae any_char
jmp start
;DISPLAY LETTER, DIGIT OR ANY OTHER ACCEPTABLE CHAR.
any_char:
mov ah, 9
mov bh, 0
mov bl, color
mov cx, 1 ; how many times display char.
int 10h ; display char in al.
;UPDATE CHAR IN MATRIX.
mov si, curr_line ; si points to the beginning of the line.
add si, curr_char ; si points to the char in the line.
mov [ si ], al ; the char is in the matrix.
;!!! EXTREMELY IMPORTANT : PREVIOUS BLOCK DISPLAYS ONE
;CHAR, AND NEXT BLOCK MOVES CURSOR TO THE RIGHT. THAT'S
;THE NORMAL BEHAVIOR FOR ALL EDITORS. DO NOT MOVE THESE
;TWO BLOCKS, THEY MUST BE THIS WAY. IF IT'S NECESSARY
;TO MOVE THEM, ADD A JUMP FROM ONE BLOCK TO THE OTHER.
;RIGHT.
moveRight:
inc curr_char ; update current char.
mov dl, posX
mov dh, posY
inc dl ; posX ++
mov posX, dl
jmp prntCrs
;LEFT.
moveLeft:
dec curr_char ; update current char.
mov dl, posX
mov dh, posY
dec dl ; posX --
mov posX, dl
jmp prntCrs
;UP.
moveUp:
sub curr_line, 80 ; update current line.
mov dl, posX
mov dh, posY
dec dh ; posY --
mov posY, dh
jmp prntCrs ; print cursor
;DOWN.
moveDown:
add curr_line, 80 ; update current line.
mov dl, posX
mov dh, posY
inc dh ; posY ++
mov posY, dh
jmp prntCrs
prntCrs: ; print cursor
mov ah, 2h
int 10h
jmp start
fin:
int 20h
posX db 1 dup(0) ; dh = posX -> controls row
posY db 1 dup(0) ; dl = posY -> controls column
matrix db 80*25 dup(' ') ; 25 lines of 80 chars each.
curr_line dw ?
curr_char dw ?
color db 2*16+15
;FOR COLORS USE NEXT TABLE:
;
end program
如果您想保存到文件或从文件加载,矩阵将是必需的。此外,矩阵在编辑器的行数超过屏幕大小的情况下很有用,例如,如果矩阵有 100 行(矩阵 db 80*100),当用户按下键时,编辑器的第一行将消失,但是,当用户按下向上键时,可以从矩阵中重新显示第一行。
关于您的逻辑流程的一些要点。 moveRight:
等四个函数,调整光标位置,跳转到prntCrs:
使BIOS调用设置光标位置,然后运行到clearS:
函数,然后跳回start:
这些函数应该 call
ed 并在末尾有一个 ret
指令。
moveDown:
mov dl, posY
mov dh, posX
inc dh ; posX ++
mov posX, dh
call prntCrs ; call not jmp
jmp start
prntCrs: ; print cursor
mov ah, 2h
int 10h
ret ; added ret
此外,在 dh
和 dl
中,您并不总是正确处理行和列,而且您的光标位置变量定义不正确
posX db 1 dup(0) ; dh = posX -> controls row
posY db 1 dup(0) ; dl = posY -> controls column
这些可以是单个字节(也更正了用法)
posX db 0 ; dl = posX <--- swapped register names
posY db 0 ; dh = posY
最后你递增和递减了光标位置,但没有检查它的边界。仅在 > 0 时减少,仅在 < 79 时增加 PosX,在 < 24 时才增加 PosY。