您的位置:首页 > 其它

第十章课程设计1(完成版)

2009-09-05 17:37 113 查看
解题思路:结合实验七和第十章的实验三就可以实现程序。



assume cs:codesg

datasg 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'
   
    dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
    dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
    
    dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
    dw 11542,14430,15257,17800    
    
datasg ends

table segment
    db 21 dup ('year summ ne ?? ')  
    
table ends 

data segment
  db 10 dup(0)
data ends

stacksg segment
    db 16 dup (0) 
    
stacksg ends

codesg segment
start:   
    mov ax,datasg
    mov es,ax 
     
    mov ax,table
    mov ds,ax  
    
    mov ax,stacksg
    mov ss,ax
    mov sp,10h 
    
    mov bx,0
    mov si,0
    mov di,0
    mov cx,21

;data_to_tablesg循环是为了把datasg段中的数据经过处理后放入table段,为了后面的输出做准备    
 data_to_tablesg:
    ;copy the year data
    push es:[bx]
    push es:[bx+2]
    pop ds:[si+2]
    pop ds:[si]
     
    ;copy the income data 
    push es:[bx+54h ]
    push es:[bx+54h +2]
    pop ds:[si+7]
    pop ds:[si+5]
    
    ;copy the count of employees 
    push es:[di+0a8h] 
    pop ds:[si+0ah]
    
    mov ax,ds:[si+5]
    mov dx,ds:[si+7]

    div  word ptr ds:[si+10] 

    mov ds:[si+0dh],ax  
    
    add di,2
    add si,10h 
    add bx,4

    loop data_to_tablesg

;下面开始从table段中拿出数据,然后到显存段中输出,这里的思路是挨个输出table段中的数据
    mov sp,10h;设置ss:sp指向stacsg栈段的栈顶   
    
    mov si,0;ds:[si]指向我们将要处理的数据的table段  

    mov ax,0b800h   
    mov es,ax
    mov bx,0;设置es:[bx]为显示的缓存器的地址 
        
    mov cx,21;因为要处理的数据为21,所以循环次数为21
       
 display: 
    ;在每次循环一开始就计算该次循环所对应的行的显存段的偏移地址,结果存储到dx中
    call calculate_line_value

    push bx   
    push es   
    push cx 
    push di;因为下面的程序中将要用到es、bx、cx、di,所以这里先把他们入栈保存起来
   
    call show_year
     ;因为在调用子程序时,已经改变了显存段的偏移地址,而为了对齐输出,我们必须确保每行的开始地址即di的值不能改变,所以入栈保护起来
    pop di;
    push di
    add di,40;这是为了对齐输出,在输出收入数据应该从

    call show_income
    pop di
    push di
    add di,80;输出完后,要把di的值恢复,再放到栈中保护起来,再设置该行的偏移地址

    ;恢复ds指向table段,使其能继续取table段中的值
    mov cx,table
    mov ds,cx

    call show_sum_employees
    pop di
    add di,120;输出完后,要把di的值恢复,再放到栈中保护起来,再设置该行的偏移地址

    ;恢复ds的值
    mov cx,table
    mov ds,cx

    call show_avarage_salary
     ;恢复ds的值
    mov cx,table
    mov ds,cx

    ;在调用完子程序后要把cx、es、bx的值恢复给他们   
    pop cx   
    pop es    
    pop bx   
       
    add bx,10h ;把bx的值加2使得es:[bx]能取得下一个数据     
    loop display     
      
    mov ax,4c00h   
    int 21h 

;计算该次循环要显示的行号的开始地址 
calculate_line_value:
    mov dh,24
    sub dh,cl;这里是用24减去cl中的值就是该次循环要显示的行号,我设置成从第二行开始显示   
    mov dl,0;列号        
  
    ;我们在第九章的实验材料中知道显示的一行的偏移为0a0h   
    mov al,0a0h   
    dec dh;因为0a0h是第二行的开始,所以减去1后,比如要在第八行显示,就要7*0a0h,不减的话就是在第九行显示了   
  
    mul dh;  
    mov di,ax;把上面乘积的值给我们使用的偏移地址的寄存器di  
    ret

;这里是输出年份,因为年份已经是一字符的形式存储的,不需要在经过转换,所以直接输出 
show_year:
    mov al,ds:[bx];去取data段的数据,这里bx是偏移量 
    call show_str_year;顾名思义,就是专门为输出年份所写的输出子程序
    mov al,ds:[bx+1]
    call show_str_year
    mov al,ds:[bx+2]
    call show_str_year
    mov al,ds:[bx+3]
    call show_str_year
    ret

;下面是输出收入的数据,在输出后面的收入数据、雇员人数和平均工资时都要先把数字转换成对应的字符。再调用show_str_other子程序输出
;这里的关键是运用定义的段data段来存放相应的数据如收入数据转换后的字符,然后马上输出。
show_income:
    mov ax,ds:[bx+5]
    mov dx,ds:[bx+7];
    mov cx,data
    mov ds,cx;这里将要用到程序刚开始时定义的用来存放相应的数据如收入数据转换后的字符
    mov si,10;设置ds:[si]用来存放从data段中取出的数据转换为对应字符串的值,特别注意这里ds中存放的是data段的段地址 
    mov byte ptr ds:[si],0;因为在调用dtoc子程序时得到的数据室逆序的,故我这里采用的是先填充末尾,倒着填过来。   
    call change_to_char;调用把数字转换成对应得字符的子程序,结果存储在data段中
    call show_str_other;调用输出字符串子程序show_str_others输出change_to_char中存放在data段中的字符串   
    ret
;处理雇员人数并显示
show_sum_employees:
     mov ax,ds:[bx+10]
    mov dx,0;
    mov cx,data
    mov ds,cx
    mov si,10;设置ds:[si]用来存放从data段中取出的数据转换为对应字符串的值   
    mov byte ptr ds:[si],0;因为在调用dtoc子程序时得到的数据室逆序的,故我这里采用的是先填充末尾,倒着填过来。   
    call change_to_char
    call show_str_other 
    ret

;处理雇员人数并显示
show_avarage_salary:
    mov ax,ds:[bx+13]
    mov dx,0;
    mov cx,data
    mov ds,cx
    mov si,10;设置ds:[si]用来存放从data段中取出的数据转换为对应字符串的值   
    mov byte ptr ds:[si],0;因为在调用dtoc子程序时得到的数据室逆序的,故我这里采用的是先填充末尾,倒着填过来。   
    call change_to_char
    call show_str_other 
    ret
    
;把table段中的数据转换成对应的字符串
change_to_char:
    mov cx,ax;把ax的值给cx,借以判断ax中的值是否为0,因为ax中的值是除法中的商   
    jcxz changeOK;如果ax中的值为0,说明除法结束了   
    mov cx,10;把要现实的数据转换成十进制数对应的字符,所以基数是10    
       
    ;由于下面还要用到si和ax,所以先把他们的值给保存起来。   
    push si   
    push ax   
    ;下面就是除法不会溢出的公式的应用   
    mov ax,dx   
    mov dx,0   
       
    div cx    
    mov si,ax   
       
    pop ax   
    div cx   
    mov cx,dx         
    mov dx,si     
  
    pop si   
    add cx,30h    
    sub si,1;每处理传进来的数据的每一位数据时,记得要把si减一以便ds:[si]指向下一个内存单元   
    mov ds:[si],cl      
    jmp short change_to_char     
          
changeOK:ret   

;输出单个字符的子程序
show_str_year:
    mov cl,0ah ;设置显示的字体颜色   
    mov ah,cl   
    mov es:[di],ax    
    add di,2
    ret  

;输出字符串的子程序
show_str_other:
    mov al,ds:[si]
    mov cl,al     
    jcxz ok     
    mov cl,0ah   
    mov ah,cl   
    mov es:[di],ax    
    add di,2   
    inc si;   
    jmp short show_str_other
ok: ret  
  
codesg ends
end start


在郁闷半天之后,静下心来之后分析知道是display段程序过长,所以把当中的显示年份、处理收入数据并显示、处理雇员人数并显示、处理平均工资并显示分成了四个子程序,在display中调用它们,结果证明实验成功。由此可见,分模块、分功能是很重要的编程思维方式。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐