编译环境:emu8086
附:ASCII码表
https://baike.baidu.com/item/ASCII/309296?fr=aladdin
datas segment para 'data'
three db 3 ;JUN等是3个字母的,因此在数组定位中,每3个字节是一个月
mess db 'Input month number',13,10,'$'
monin label byte ;为数据段中定义的下一个变量提供不同的名称和大小属性,共享同一个内存位置,label伪指令自身不分配内存
max db 1 ;最多输入的字符数
act db 0 ;在读入缓冲区时,此位置会自动存储输入数字的位数
mon db 3 dup(0) ;存储输入的数字,最多2个数字+1回车
;
alfmon db '>>>',13,10,'$' ;作为缓冲区使用,这里的>>>可以替换成别的字符,如?代表随机填入。
montab db 'JAN','FEB','MAR','APR','MAY','JUN'
db 'JUL','AUG','SEP','OCT','NOV','DEC'
datas ends
codes segment para 'code'
assume cs:codes,ds:datas,es:datas
;关联段与段寄存器,编译软件对assume不生成机器码
start:
main proc far
push ds
mov ax,0
push ax
mov ax,datas
mov ds,ax
mov es,ax
;Input month
lea dx,mess ;输出提示信息
mov ah,09
int 21h ;执行这条指令时,al的值会改变成24,原因是中断时al会返回刚刚输出的字符,输出的字符$的ASCII码就是24H
lea dx,monin
mov ah,0Ah ;键盘输入到缓冲区,(DS:DX+2)=输入字符串起始地址
int 21h
mov DL,13 ;回车->回到当前行的行首
mov ah,02 ;显示输出,DL=输出字符
int 21h
mov DL,10 ;换行->移动到下一行的相同位置
mov ah,02 ;显示输出,DL=输出字符
int 21h
;cmp的功能相当于减法指令,cmp不保存结果,只影响符号位。sub指令执行过后ax被赋为减法的结果
cmp act,0 ;用act减去0,判断输入的数字位数是否为0(直接回车,就退出)
je exit ;若ZF=1->减法运算结果全为0 则跳转
;Convert ASCII to binary
mov ah,30h ;set up month
cmp act,2 ;用act减去2,判断输入的数字位数是否为2
je two ;若ZF=1->减法运算结果全为0 则跳转
mov al,mon
jmp conv
two:
mov al,mon+1
mov ah,mon
conv:
xor ax,3030h ;由于0的ascii码为30,所以要减去30才能获得对应的数字
cmp ah,0 ;Month 01-09? 是否输入了01,02,03这样的形式
jz loc ;输入了02等形式,直接跳转到loc代码段
sub ah,ah ;ah寄存器置0
add al,10 ;al寄存器中的值+10
;Locate month in table
loc:
lea si,montab ;取得月份缩写数组的地址
dec al ;数组从0开始
mul three ;每个月份缩写占3个字节,移动到下一个月份需要移动3个字节
add si,ax ;定位到对应月份缩写的地址
mov cx,03 ;设置循环次数为3
cld ;将标志寄存器Flag的方向标志位DF清零。在字串操作中使变址寄存器SI或DI的地址指针自动增加,字串处理由前往后
lea di,alfmon ;取得待输出变量的地址到di中
rep movsb ;重复movsb指令3次 movsb字符传送指令,将DS:SI的字节复制到ES:DI指向的地址。此处是将月份缩写数组中 3个缩写字母复制到待输出区中
;Display alpha month
lea dx,alfmon ;将待输出区的地址存到dx中,即将调用09功能输出月份缩写
mov ah,09
int 21h
jmp start ;重复
exit:
mov ah,4ch
int 21h
main endp
codes ends
end main
一些语句的解释:
-
label
name label type
为数据段中定义的下一个变量提供不同的名称和大小属性,共享同一个内存位置,label伪指令自身不分配内存。在本代码中可以视为用monin来作为输入缓冲区内存地址的名字,在mov dx,monin并调用输入功能时,系统会根据内存地址开始第一个字来设置最大可输入的字符数(包括回车,回车必须要占用1个字符数),月份的数字最多是2位+1位回车符,因此max设置为3。第二个字用于存储实际输入字符的个数,在输入字符后,系统会自动将第二个字赋值为实际输入字符的个数(此处回车不会算入其中,如果直接回车,那么act是0,在后续cmp act 0会调用退出代码)。第三~n个字作为输入的缓冲区,系统会将输入的字符存储到第三个字开始的地址中(回车也会被存储进去),本代码中缓冲区从第3个字开始到第6个字(包含)结束,因此最多2个数字+回车。
具体看代码中的注释 -
cmp
cmp的功能相当于减法指令,cmp不保存结果,只影响符号位。sub指令执行过后ax被赋为减法的结果。如果减法的结果为0,则会将ZF置为1 -
je
je code如果ZF=1,则跳转到语句code -
rep
先将循环次数存入cx,重复(cx)次语句。注意:每循环一次cx会自动减1 -
cld
将标志寄存器Flag的方向标志位DF清零。在字串操作中使变址寄存器SI或DI的地址指针自动增加,字串处理由前往后。 -
movsb
movsb字符传送指令,将DS:SI的字节复制到ES:DI指向的地址。在本代码中是将月份缩写数组中 3个缩写字母复制到变量alfmon(待输出区)中