8086汇编实例:判断闰年详解(为初学者)

data segment    ;定义数据段
    infon db 0dh,0ah,'Please input a year: $'	;声明空间存储输入提示信息,其中0d回车,0a换行
    Y db 0dh,0ah,'This is a leap year! $'	;声明空间存储是闰年提示信息,同上另起一行输出
    N db 0dh,0ah,'This is not a leap year! $'	;声明空间存储不是闰年提示信息,同上另起一行输出
    w dw 0					;声明空间存储输入年份解析后生成的年份数字
    buf db 8
        db ?
      	db 8 dup(?)				;声明空间作为缓冲区,总共10个字节,第一个表示准备接受的字
						;符数,即8;第二个表示实际接受的字符数,初始为空(?);后面8	
						;个字节作为缓冲接收字符,后面两行只是做初始化工作
data ends

stack segment stack
    db 200 dup(0)
stack ends					;定义一个栈,200字节

code segment
          assume ds:data,ss:stack,cs:code
    start:mov ax,data
          mov ds,ax				;指定堆栈
          
          lea dx,infon  			;在屏幕上显示提示信息
          mov ah,9
          int 21h				;将infon开始的字符串输出到屏幕

          lea dx,buf    			;从键盘输入年份字符串
          mov ah,10
          int 21h
          
          mov cl, [buf+1]			;获取实际输入长度
	  mov ch,0				;保证cx的值为[buf+1]对应字节的值
          lea di,buf+2				;获取字符串首地址
          call datacate				;调用子程序,将输入字符串传化为年份数字
          call ifyears				;调用子程序,判断是否闰年
          jc a1					;如果进位标记C为1则跳转到a1
          
          lea dx,n				;否则输出不是闰年信息
          mov ah,9
          int 21h
          jmp exit
    a1:   lea dx,y				;输出是闰年信息
          mov ah,9
          int 21h
    exit: mov ah,4ch				;程序结束
          int 21h
       
 

 datacate proc near				;指明该子程序在主程序段内
          push cx				;备份cx                                                      
          dec cx				;cx自减1,保证下面的循环使si指向最后一个字符(buf中回车符前面的一个)
          lea si,buf+2				;将buf中第一个字符(即buf的第三个字节数据)的地址赋给si
     tt1: inc si				;循环,使得si指向最后一个字符(即buf中回车符前面的一个)
          loop tt1
          pop cx				;回复cx
     
      
          mov dh,30h				;辅助数据,用来将数字字符对应的ASCII码转换为其代表的数字本身
          mov bl,10				;辅助数据,用来在每进一位时使得ax乘以10
          mov ax,1				;ax用来装对应位的权值
      l1: push ax				;备份ax
	  push bx				;备份bx
	  push dx				;备份dx,下面dx将接收乘法运算结果的高位(实际上在本例中它不起任何作用,因为乘法结果不会超过ax表示的范围,之所以需要是因为有时乘数(某些权值)要用两个字节来表示)
          sub  byte ptr  [si],dh		;将单个字符转换为对应的数字
          mov  bl, byte ptr [si]		;获取该位的数字
	  mov  bh,0				;因为:1.我们要用两个字节装对应位数字;2.该数字不会超过一个字节表示的范围
          mul  bx				;将改位数字乘以相应的权值,结果存储在ax中,我们预定年份最大值不超过两个字节表示的范围
          add [w],ax				;加到结果上(易知当所有位都加完时,即是我们想要的年份数字)
 	  pop dx				;恢复dx
	  pop bx				;恢复bx
          pop ax				;恢复ax
          mul bl				;权值乘以10
          dec si				;si指向更高一位数字
          loop l1
          ret					;子程序返回
 datacate endp


   ifyears proc near				;指明该子程序段在主程序段内,该子程序用于检测是否是闰年,接收年份数据,改变C标记位表示不同结果
           push  bx				;备份bx
           push  cx				;备份cx,下面cx用于存储原始年份数据
           push  dx				;备份dx,下面dx用于存储除法余数
           mov ax,[w]				;获取年份数据
           mov  cx,ax				;将年份数据备份到cx,因为后面做除法时ax值将会改变
           mov  dx,0				;因为被除数要为32字节,高位在dx,本程序中为0
	   mov bx,100				;这三行判断是否能被100整除
           div  bx
           cmp  dx,0
           jnz  lab1				;若不能被100整除,跳转到lab1
           mov   ax,cx				;否则判断能否被400整除
	   mov bx,400
           div  bx
           cmp dx,0
	   jz lab2				;若能表示是闰年,跳转到lab2
	   clc					;否则不是闰年,将C标记位清零,并跳转到lab3
	   jmp lab3
     lab1: mov ax,cx				;不能被100整除时跳转到此处,进一步判断能否被4整除
	   mov dx,0				
	   mov bx,4
	   div bx
	   cmp dx,0
	   jz lab2				;若不能被100整除但能能被4整除是闰年,跳转到lab2
	   clc					;若不能被100整除也不能被4整除不是闰年,将c标志位置0,并跳转到lab3
           jmp lab3
     lab2: stc					;若是闰年跳转到此处将c标志位置1
     lab3: pop  dx				;相应寄存器恢复
           pop  cx
           pop  bx
           ret					;子程序返回
   ifyears endp
code ends
   end start
      
本文对应的实例源码

你可能感兴趣的:(汇编(Assembly))