1870 字
9 分钟
从零开始的汇编语言笔记(3)
这里应该就是一些比较大的代码记录,其实就是课本题品鉴一下自己写一下。
[6.1] 编写一个子程序嵌套结构的程序模块,分别从键盘输入姓名及8个字符的电话号码,并以一定的格式显示出来。
主程序
TELIST:· 显示提示符
INPUT NAME:;· 调用子程序
INPUT_NAME输入姓名;· 显示提示符
INPUT A TELEPHONE NUMBER:;· 调用子程序
INPHONE输入电话号码;· 调用子程序
PRINTLINE显示姓名及电话号码。子程序
INPUT_NAME:· 调用键盘输入子程序
GETCHAR,把输入的姓名存放在INBUF缓冲区中;· 把
INBUF中的姓名移入输出行OUTNAME。子程序
INPHONE:· 调用键盘输入子程序
GETCHAR,把输入的8位电话号码存放在INBUF缓冲区中;· 把
INBUF中的号码移入输出行OUTPHONE。子程序
PRINTLINE:显示姓名及电话号码,格式为:
NAME TEL.X X X XXXXXXXX
这是课本答案的代码:
;******************************************; 数据段定义DSEG SEGMENT INBUF DB 12 DUP (' ') ; 输入缓冲区,初始化为空格,长度12个字节 OUTNAME DB 16 DUP (' ') ; 姓名输出行,初始化为空格,长度16个字节 OUTPHONE DB 12 DUP (' '), 0DH, 0AH, '$' ; 电话号码输出行,初始化为空格,后跟回车换行符和字符串结束符 MESG1 DB 'INPUT NAME:', '$' ; 提示输入姓名的字符串 MESG2 DB 'INPUT A TELEPHONE NUMBER:', '$' ; 提示输入电话号码的字符串 MESG3 DB 'NAME', 12 DUP (' '), 'TEL.', 0DH, 0AH, '$' ; 显示标题行的字符串 CRLF DB 0DH, 0AH, '$' ; 回车换行符字符串DSEG ENDS ; 数据段结束;******************************************
;******************************************; 堆栈段定义STACK SEGMENT DW 100 DUP (?) ; 堆栈空间,100个字(200字节),未初始化 TOS LABEL WORD ; 堆栈顶(Top of Stack)的标签STACK ENDS ; 堆栈段结束;******************************************
;******************************************; 代码段定义CSEG SEGMENT; 主程序TELIST,远过程(FAR PROC)TELIST PROC FAR ASSUME CS: CSEG, DS: DSEG, ES: DSEG, SS: STACK ; 假设段寄存器的关联关系
; 初始化堆栈段寄存器SS和堆栈指针SPSTART: MOV AX, STACK ; 将堆栈段的段地址加载到AX MOV SS, AX ; 将AX的值(STACK段地址)赋给SS寄存器 MOV SP, OFFSET TOS ; 将堆栈顶的偏移地址赋给SP寄存器
; 保存原有的数据段寄存器DS PUSH DS ; 将DS压入堆栈,保存原始DS SUB AX, AX ; 将AX清零 PUSH AX ; 将AX(现在为0)压入堆栈,可能用于设置段寄存器 MOV AX, DSEG ; 将数据段地址加载到AX MOV DS, AX ; 设置DS寄存器为DSEG MOV ES, AX ; 设置ES寄存器为DSEG
; 显示提示符“INPUT NAME:”BEGIN: LEA DX, MESG1 ; 将MESG1的地址加载到DX MOV AH, 09H ; 设置AH为09H,DOS显示字符串功能 INT 21H ; 调用DOS中断,显示字符串
CALL INPUT_NAME ; 调用子程序INPUT_NAME,输入姓名
; 显示提示符“INPUT A TELEPHONE NUMBER:” LEA DX, MESG2 ; 将MESG2的地址加载到DX MOV AH, 09H ; 设置AH为09H,DOS显示字符串功能 INT 21H ; 调用DOS中断,显示字符串
CALL INPHONE ; 调用子程序INPHONE,输入电话号码
CALL PRINTLINE ; 调用子程序PRINTLINE,显示姓名及电话号码
RET ; 远返回,结束主程序TELIST ENDP ; 主程序结束;--------------------------------------------------------------------------
; 子程序INPUT_NAME,近过程(NEAR PROC)INPUT_NAME PROC NEAR CALL GETCHAR ; 调用子程序GETCHAR,输入姓名
LEA SI, INBUF ; 将INBUF的地址加载到SI(源索引寄存器) LEA DI, OUTNAME ; 将OUTNAME的地址加载到DI(目的索引寄存器) MOV CX, 12 ; 设置循环计数器CX为12 CLD ; 清除方向标志,字符串操作向前移动 REP MOVSB ; 重复移动字节,将INBUF的数据复制到OUTNAME
RET ; 返回INPUT_NAME ENDP ; INPUT_NAME子程序结束;--------------------------------------------------------------------------
; 子程序INPHONE,近过程(NEAR PROC)INPHONE PROC NEAR CALL GETCHAR ; 调用子程序GETCHAR,输入电话号码
LEA SI, INBUF ; 将INBUF的地址加载到SI(源索引寄存器) LEA DI, OUTPHONE ; 将OUTPHONE的地址加载到DI(目的索引寄存器) MOV CX, 12 ; 设置循环计数器CX为12 CLD ; 清除方向标志,字符串操作向前移动 REP MOVSB ; 重复移动字节,将INBUF的数据复制到OUTPHONE
RET ; 返回INPHONE ENDP ; INPHONE子程序结束;--------------------------------------------------------------------------
; 子程序GETCHAR,近过程(NEAR PROC)GETCHAR PROC NEAR MOV AL, 20H ; 将空格字符(20H)加载到AL MOV CX, 12 ; 设置循环计数器CX为12 LEA DI, INBUF ; 将INBUF的地址加载到DI CLD ; 清除方向标志,字符串操作向前移动 REP STOSB ; 重复存储字节,将20H填充到INBUF
MOV CX, 12 ; 设置循环计数器CX为12,用于输入字符 MOV DI, 0 ; 将DI清零,用于索引INBUFINPUT: MOV AH, 1 ; 设置AH为1,DOS读取字符功能 INT 21H ; 调用DOS中断,读取一个字符
CMP AL, 0DH ; 比较输入字符是否为回车符(0DH) JZ QUIT ; 如果是回车符,跳转到QUIT
MOV [INBUF + DI], AL ; 将输入的字符存入INBUF[DI] INC DI ; 增加DI,指向下一个位置 LOOP INPUT ; 循环,直到CX为0QUIT: CALL DISP_CRLF ; 调用子程序DISP_CRLF,显示回车换行 RET ; 返回GETCHAR ENDP ; GETCHAR子程序结束;--------------------------------------------------------------------------
; 子程序PRINTLINE,近过程(NEAR PROC)PRINTLINE PROC NEAR LEA DX, MESG3 ; 将MESG3的地址加载到DX MOV AH, 09H ; 设置AH为09H,DOS显示字符串功能 INT 21H ; 调用DOS中断,显示字符串
LEA DX, OUTNAME ; 将OUTNAME的地址加载到DX MOV AH, 09H ; 设置AH为09H,DOS显示字符串功能 INT 21H ; 调用DOS中断,显示姓名
LEA DX, OUTPHONE ; 将OUTPHONE的地址加载到DX MOV AH, 09H ; 设置AH为09H,DOS显示字符串功能 INT 21H ; 调用DOS中断,显示电话号码
RET ; 返回PRINTLINE ENDP ; PRINTLINE子程序结束;--------------------------------------------------------------------------
; 子程序DISP_CRLF,近过程(NEAR PROC)DISP_CRLF PROC NEAR LEA DX, CRLF ; 将CRLF的地址加载到DX MOV AH, 09H ; 设置AH为09H,DOS显示字符串功能 INT 21H ; 调用DOS中断,显示回车换行 RET ; 返回DISP_CRLF ENDP ; DISP_CRLF子程序结束;--------------------------------------------------------------------------
CSEG ENDS ; 代码段结束;******************************************
END START ; 程序入口点下面是我的代码:
dataseg segment prompt_name db 'INPUT NAME: ', '$' prompt_phone db 'INPUT A TELEPHONE NUMBER: ', '$'
INBUF db 20 INBUF_LEN db ? INBUF_DATA db 20 dup(?)
OUTNAME db 20 dup(?) OUTPHONE db 20 dup(?)
prompt_title db 'NAME', 8 DUP (' '), 'TEL.', 0DH, 0AH, '$'dataseg ends
stackseg segment dw 100 dup(?) TOS label wordstackseg ends
codeseg segment assume cs: codeseg, ds: dataseg, ss: stacksegTELIST proc farstart: mov ax, stackseg mov ss, ax mov sp, offset TOS
push ds xor ax, ax push ax mov ax, dataseg mov ds, ax mov es, ax
call INPUT_NAME call INPHONE
call PRINTLINE
pop ax pop ds mov ax, 4C00h int 21h
TELIST endp
INPUT_NAME proc near mov ah, 09h lea dx, prompt_name int 21h
call GETCHAR mov cx, 0
lea si, INBUF_DATA lea di, OUTNAME mov cl, INBUF_LEN cld rep movsb
mov cl, 12 sub cl, INBUF_LEN mov al, ' ' rep stosb
mov byte ptr [di], '$'
retINPUT_NAME endp
INPHONE proc near mov ah, 09h lea dx, prompt_phone int 21h
call GETCHAR
lea si, INBUF_DATA lea di, OUTPHONE mov cl, INBUF_LEN cld rep movsb
mov cl, 12 sub cl, INBUF_LEN mov al, ' ' rep stosb
mov byte ptr [di], '$' retINPHONE endp
GETCHAR proc near mov ah, 0Ah lea dx, INBUF int 21h call newline retGETCHAR endp
newline proc near push ax push dx mov ah, 02h
mov dl, 0Dh int 21h mov dl, 0Ah int 21h
pop dx pop ax retnewline endp
PRINTLINE proc near mov ah, 09h lea dx, prompt_title int 21h
mov ah, 09h lea dx, OUTNAME int 21h
mov ah, 09h lea dx, OUTPHONE int 21h
retPRINTLINE endpcodeseg endsend start