弄了两天多才搞定,累死我了。。。。。 assume cs:codesg,ds:data,es:table data segment db '1975','1976','1977','1978','1979','1980','1981','1982','1983' db '1984','1985','1986','1987','1988','1989','1990','1991','1992' db '1993','1994','1995' ;以上是表示21年的21个字符串 0~53H dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514 dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000 ;以上是表示21年公司总收入的21个dword型数据 54H~0A7H dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226 dw 11542,14430,15257,17800 ;以上是表示21年公司雇员人数的21个word型数据 0A8H~0D1H data ends table segment db 21 dup ('year sumn ne ?? ') table ends codesg segment start:mov ax,data mov ds,ax mov ax,table ;表 mov es,ax xor bx,bx xor si,si xor di,di mov cx,21 call s mov dh,8 mov dl,3 mov cl,2 call year_s mov ax,4c00H int 21H s:mov ax,ds:[bx] mov es:[si],ax ;19 mov ax,ds:[bx].2 ;75 mov es:[si].2,ax mov ax,ds:[di].0A8H mov es:[si].0AH,ax mov ax,ds:[bx].54H mov es:[si].5H,ax mov dx,ds:[bx].56H mov es:[si].7H,dx div word ptr es:[si].0AH mov es:[si].0DH,ax add bx,4 ;因为年份和总收入都为4字节,人数为2字节 add di,2 add si,10H loop s ret ;==============================================| ;----------------年份子程序--------------------| ;==============================================| year_s:push cx ;年份子程序 mov bx,0 mov si,0 c2:mov ax,0B800H ;显存地址 mov ds,ax mov al,0a0h mul dh ;8*160 要写入的偏移地址 mov bx,ax ;(bx)=(ax) mov al,2 mul dl ;起始地址 add bx,ax ;(bx)=(bx)+(ax) pop dx ;将cx中的值弹出栈放置dx里 mov cx,4 ;外层循环数 k:push cx push bx push si ;入栈是因为后面要用到这些 mov cx,21 ;内层循环数 k2:mov al,es:[si] ;es段为表段,此时si为0,取出其中字符 mov ah,dl ;原始cl里存放的是颜色属性信息,现在放入ah mov ds:[bx],ax ;将ax中值放入ds:[内存单元] add si,10H ;指向下一行,此时指向的字符是与开始si所对应位置的字符了 检索位置 add bx,0A0H ;bx为显存地址区偏移,(bx)=(bx)+0A0H,即字符输出的位置指向下一行与开始bx所对应位置的字符 输出位置 loop k2 pop si ;先前将si push进栈是为了混乱,现在pop 出来自加1 ,即指向要检索的下一个字符 inc si pop bx ;将bx pop出栈加2,因为一个字节存放字符,一个存放属性 add bx,2 pop cx ;将cx的值还给它 loop k ;跳至外层循环检索下一字符 add bx,20 push bx ;bx记录了写入年份的偏移,现在保存起来,用作总收入写入的起始偏移地址 ;==============================================| ;----------------总收入子程序------------------| ;==============================================| icome:mov bx,0 pop si ;将年份的偏移地址pop出栈到si中,用作总收入写入的起始偏移地址 mov cx,21 ;循环次数 mov bp,0 ;bp定位es段中要查询的首地址,bp用作索引es段中的数据位置 mov di,si ;将要写入的起始偏移地址放到di中,di用作屏幕写入位置定位 push di icome2:push cx ;将循环次数入栈保存,以免后继操作将cx打乱 mov ax,es:[bp+5] ;ax为低16位,es:[bp+5],指向了es段中第5个字节 mov dx,es:[bp+7] ;dx为高16位,es:[bp+7],指向了es段中第7个字节 call dwtoc ;跳转到dtoc,dtoc功能是将dword数据转换为十进制输出 add bp,10H ;初始bp为0,表明从0索引,现在bp加上10H(16),因为es段的长度为16个字节,现在加上16,表示将索引下一行与上一行对应的字符处,即索引第二行了 pop cx ;将循环次数pop出栈到cx中 loop icome2 ;==============================================| ;------------------人数子程序------------------| ;==============================================| number:pop si add si,30 mov cx,21 mov bp,0 mov di,si push di number1:push cx mov ax,es:[bp+0AH] call dtoc add bp,10H pop cx loop number1 ;==============================================| ;---------------平均工资子程序-----------------| ;==============================================| wage:pop si add si,30 mov cx,21 mov bp,0 mov di,si wage1:push cx mov ax,es:[bp+0DH] call dtoc add bp,10H pop cx loop wage1 ret dwtoc:mov cx,0 ; push cx dwtoc1:mov cx,10 ;cx为除数 call divdw ;跳转到divdw中,做不会溢出的除法运算 add cx,30H ;cx存放的是最后一次运算所得的余数,现在加30H,是为了得到它的ASCII码 push cx ;保存余数的ASCII码进栈 mov cx,dx ;判断商是否为0,如果高低位高都为0,则返回,首先判断高16位 jcxz dwtoc2 ;如果为0,则跳转到dtoc2,进行低位判断 jmp short dwtoc1 ;如果不为0,则跳转,继续进行除法运算 dwtoc2:mov cx,ax ;当高位为0时,判断低位 jcxz dwtoc3 ;如果低位也为0,表明除法运算已完成,已经获取了所有的余数的ASCII码,就跳转到dtoc3处,进行写入操作 jmp short dwtoc1 ;如果不为0,则跳转,继续进行除法运算 dwtoc3:pop cx ;因为先前将cx入栈了,cx中保存的是余数的ASCII码,现在出栈 mov ds:[si],cl ;cl保存的是余数,十进制 mov byte ptr ds:[si+1],2 ;mov byte ptr ds:[si+1],2 这句是给转换后字符赋颜色属性 jcxz dwtoc4 ;如果cx为0,则跳转到dtoc4处 add si,2 ;si+2是为下一个字符写入做准备 jmp short dwtoc3 ;如果cx不为0,则跳转到dtoc3处,继续写入字符 dwtoc4: mov byte ptr ds:[si],0 ;最后,当所有字符写入完毕后在末尾加0 ; pop cx ; mov si,0 add di,0A0H ;先前di中存放的是将要写入的起始偏移地址,现在加上0A0H,表明是指向屏幕的下一行,也就是指向了与上一行所对应的字符处 mov si,di ;di中已经存放了要写入的下一行的地址,现在将di中的值放到si中,因为si将会用作下一次循环,用作写入地址 ret divdw:mov bx,ax ;将ax的值临时存放到bx中 mov ax,dx ;此时ax为高16位 xor dx,dx div cx ;ax为商,dx为余数 rem(H/N)*1000H+L push ax ;高16位运算结果所得的商入栈 mov ax,bx ;此时ax为低16位 div cx ;结果:ax存放低16位,dx存放高16位,cx存放余数 mov cx,dx ;dx存放的是余数,现在将它给cx pop dx ;第一次是进行高16位运算,现在将它还给dx,dx中存放的是高16位商 ret dtoc:mov cx,0 ;cx为0入栈是为了下面的操作 push cx dtoc1:mov cx,10 xor dx,dx div cx ;L/N ax为商,dx为余 mov cx,dx ;把余放入cx中 add cx,30H ;现在cx+30为余数的ASCII码 push cx ;保存余数的ASCII码进栈 mov cx,ax ;将ax中的值放入cx中,判断ax的商 jcxz dtoc2 ;如果ax的商为零,表示各位余数都已经得到了,跳转至dtoc2处 jmp short dtoc1 ;如果商不为零,则跳转到dtoc1处继续进行除法运算,直到商为0止 dtoc2:pop cx mov ds:[si],cl mov byte ptr ds:[si+1],2 jcxz dtoc3 add si,2 jmp short dtoc2 dtoc3:mov byte ptr ds:[si],0 add di,0A0H mov si,di ret codesg ends end start