汇编代码
1 assume cs:code , ds:data , ss:stack 2 3 ; 数据段 4 data segment 5 6 db '1975','1976','1977','1978','1979','1980','1981','1982','1983' ;第一个偏移值:0 7 8 db '1984','1985','1986','1987','1988','1989','1990','1991','1992' 9 10 db '1993','1994','1995' ;最后一个偏移值:53H(83D) 11 12 ;以上是表示21年的21个字符串 13 14 15 16 dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514 ;第一个偏移值:54H(84D) 17 18 dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000 ;最后一个偏移值:A7H(167D) 19 20 ;以上是表示21年公司总收入的21个dword型数据 21 22 23 24 dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226 ;第一个偏移值是:A8H(168D) 25 26 dw 11542,14430,15257,17800 ;最后一个偏移值是:D2(210D) 27 28 ;以上是表示21年公司雇员人数的21个word型数据 29 30 dw 64 dup(?) ; 因为最后转换成字符串的空间不够,所以需要再多申请这么多空间 31 32 data ends 33 34 35 36 ; 栈段 37 stack segment 38 39 db 256 dup (?) 40 41 stack ends 42 43 44 ; 计算后的数据存放段 45 table segment 46 47 db 21 dup ('year sunm ne ?? ') 48 49 dw 32 dup(?) ; 因为最后转换成字符串的空间不够,所以需要再多申请这么多空间 50 51 table ends 52 53 54 55 ; 代码段 56 code segment 57 58 start: 59 60 ; 设置栈段地址 61 mov ax , stack 62 mov ss , ax 63 mov sp , 256 64 65 66 67 ; 计算数据段中的数据(计算人均收入,也就是收入除以雇员数) 68 mov ax , data 69 mov ds , ax 70 mov bx , 0 71 call Calculate 72 73 74 75 76 ; 循环,将双字节的数据的整型数转换成字符型 77 mov bx , 0 78 mov si , 0 ; 设置字符串输出的首地址 79 mov cx , 21 ; 设置循环次数 80 again: 81 ; 复制年份到ds段 82 mov ax , es:[ bx ] 83 mov ds:[ si ] , ax 84 mov ax , es:[ bx + 2 ] 85 mov ds:[ si + 2 ] , ax 86 mov word ptr ds:[ si + 4 ] , 0 ; 存入0,表示间隔 87 add bx , 5 ; 因为只需跳过一个空格,空格占一个字节,再加上前面读取的4个字节 88 add si , 6 89 90 91 mov ax , es:[ bx ] ; 获取公司总收入的dword型数据的低位 92 mov dx , es:[ bx + 2 ]; ; 获取公司总收入的dword型数据的高位 93 call dtoc ; 调用子程序,将dword型数据转换成数字符串型,放到ds:si指定的位置 94 add bx , 5 ; 跳过已经读取的字节再加上一个空格 95 inc si ; 如果去掉这个自增1,则存放他们之间的间隔0为一个字节,没有去掉这个自增就为一个字 96 97 mov ax , es:[ bx ] ; 获取公司雇员人数的word型数据 98 mov dx , 0 ; 因为是word型数据,所以高位不需要,为0 99 call dtoc ; 调用子程序,将dword型数据转换成数字符串型,放到ds:si指定的位置 100 add bx , 3 ; 跳过已经读取的字节再加上一个空格 101 inc si ; 如果去掉这个自增1,则存放他们之间的间隔0为一个字节,没有去掉这个自增就为一个字 102 103 mov ax , es:[ bx ] ; 获取公司雇员的人均收入 104 mov dx , 0 ; 因为是word型数据,所以高位不需要,为0 105 call dtoc ; 调用子程序,将dword型数据转换成数字符串型,放到ds:si指定的位置 106 add bx , 3 ; 跳过已经读取的字节再加上一个空格 107 inc si ; 如果去掉这个自增1,则存放他们之间的间隔0为一个字节,没有去掉这个自增就为一个字 108 109 loop again 110 111 112 113 ; 循环,用于显示所有的字符串 114 mov dh , 0 ; 第0行 115 mov dl , 2 ; 第2列 116 mov si , 0 ; 设置指向字符串首地址偏移量 117 mov cx , 22 ; 外循环共循环21次(因为第一次为了直接跳到循环处而一次性执行循环,所以需要多加一次循环) 118 119 jmp show_start ; 跳到开始出,以便能直接使用loop循环一次性输出 120 121 show_again1: 122 123 push cx ; 现场保护 124 mov cx , 4 ; 内循环共循环4次 125 126 show_again2: 127 128 push cx ; 因为CX还要用来设置颜色,所以还要保护 129 mov ch , 0 130 mov cl , 01h ; 设置颜色(蓝色) 131 call show_str 132 add si , 2 ; 加上间隔符,进行下一组字符串的输出 133 add dl , 10 ; 每输出一串字符列就空开几列 134 pop cx ; 恢复内循环的循环次数值 135 136 loop show_again2 137 138 add dh , 1 ; 输出完一组就要换下一行 139 mov dl , 2 ; 输出完一组列就要归位 140 pop cx ; 恢复外循环的循环次数值 141 show_start: 142 loop show_again1 143 144 145 146 ; 结束程序 147 mov ax , 4c00h 148 int 21h 149 150 151 152 ; 子程序 153 ; 计算数据段中的数据(计算平均收入,也就是收入除以雇员数) 154 ; 入口参数:ds:bx为待计算的数据段 155 ; 出口参数:计算好后的数据将放在table数据段中,也可以用 es:0 来直接获取这个table数据段的首地址 156 Calculate: 157 158 mov ax , table 159 mov es , ax ;设置要写入数据的段寄存器 160 161 mov bp , 0 ;设置table段的偏移地址 162 163 mov di , 0 ;设置雇员数每次增加的值(因为与其他值相比只有雇员数是2字节,所以要做特殊处理) 164 165 mov cx , 21 ;设置循环的值为21次 166 167 again_1: 168 169 mov ax , ds:[bx] ;复制年份的低字 170 mov es:[bp] , ax 171 172 mov ax , ds:[bx + 2] ;复制年份的高字 173 mov es:[bp + 2] , ax 174 175 176 177 mov ax , ds:0A8H.[di] ;复制雇员数(十进制168) 178 179 mov es:[bp + 0AH] , ax ;加10是因为复制了2个字节,而且写入的时候要输入一个空格, 180 ;并且这个位置是在复制了4个字节后的再加5个字节的位置 181 182 183 mov ax , ds:54H.[bx] ;复制收入的低字节(十进制84) 184 mov es:[bp + 5] , ax 185 186 mov dx , ds:54H.[bx + 2] ;复制收入的高字节(十进制84) 187 mov es:[bp + 7] , dx 188 189 190 191 div word ptr ds:0A8H.[di] ;因为除数是2个字节(16位)的,所以也用di(di每次循环增加2) 192 193 mov es:[bp + 0DH] , ax ;复制算好的人均收入 194 195 196 197 add bp , 16 ;进行下一组写入 198 199 add di , 2 ;用于计算雇员数的值加2,因为他一次值复制了2个字节 200 201 add bx , 4 ;复制了一次后要加上4字节,以便下一次读出和计算 202 203 loop again_1 204 205 ret ; Calculate子程序返回 206 207 208 209 210 ;参数: (ax) = dword型数据的低16位 211 ; (dx) = dword型数据的高16位 212 ; (cx) = 除数 213 ;返回: (dx) = 结果的高16位 214 ; (ax) = 结果的低16位 215 ; (cx) = 余数 216 divdw: ;子程序定义开始 217 218 push ax 219 220 mov ax,dx 221 222 mov dx,0 223 224 div cx 225 226 mov bx,ax 227 228 pop ax 229 230 div cx 231 232 mov cx,dx 233 234 mov dx,bx 235 236 ret ;子程序定义结束 237 238 239 240 241 ; 功能:将dword型数据转变为表示十进制数的字符,字符以0为结尾符 242 ; 参数:(ax) = dword型数据的低16位 243 ; (dx) = dword型数据的高16位 244 ; ds:si指向字符串的首地址 245 ; 返回:无 246 dtoc: push cx ; 保护现场 247 push bx ; 保护现场 248 push si ; 保存用来输出结果的字符串的首地址 249 250 mov byte ptr ds:[ si ] , 0 ;先写入结束符(写在首位,以便配合栈结构) 251 252 inc si 253 254 mov cx , 1 255 256 again_3:mov cx , 10 ; 做除数,每次都除以10,以便得到余数,从而求出每个位的值 257 258 call divdw ; 调用除法子程序,因为这个除法子程序可以防止数据溢出 259 260 add cl , 30H ;加上30H成为字符的ASCII码 261 262 mov ds:[ si ] , cl ;存入到指定的数据段 263 264 265 ; 判断商的低位和高位是否都为0如果都为0,则表示结束 266 mov cx , 0 267 or cx , ax 268 or cx , dx 269 270 jcxz ok1 271 272 inc si 273 inc cx ;因为loop会将cx减少1,所以要先加1 274 275 loop again_3 276 277 ok1: mov byte ptr ds:[ si + 1 ] , 0 ;尾部也写入结束符 278 279 pop si ; 取出用来输出结果的首地址 280 mov bx , si ; bx用来做最后的数据存入,所以也是为输出结果的首地址 281 282 mov al , ds:[ si ] ;从得到的第一个数据开始遍历 283 mov ah , 0 ;只要低位,高位归零 284 285 push ax ;结束符先入栈 286 287 ;把得出的字符倒过来,因为求余得到的数是倒着的 288 again_4:inc si 289 290 mov al , ds:[ si ] 291 mov ah , 0 ;只要低位,高位归零 292 293 mov cx , ax 294 295 jcxz ok2 ;已经全部临时存入栈中 296 297 push ax 298 299 inc cx ;因为loop会将cx减少1,所以要先加1 300 301 loop again_4 302 303 ok2: pop cx ;从栈中取出,正好实现倒叙 304 305 mov ds:[ bx ] , cl ;只要低位,高位归零 306 307 jcxz return 308 309 inc bx 310 inc cx ;因为loop会将cx减少1,所以要先加1 311 312 loop ok2 313 314 return: pop bx ; 恢复现场 315 pop cx ; 恢复现场 316 ret ; 返回 317 318 319 320 321 ;子程序 322 ;功能:在指定的位置 , 用指定的颜色 , 显示一个用0结束的字符串 323 ;参数:(dh) = 行号(取值范围0~24) , (dl) = 列号(取值范围0~79) 324 ; (cl) = 颜色 , ds:si指向字符串首地址 325 show_str: 326 327 push dx ; 现场保护 328 329 mov ax , 000ah ;转换成行需要乘以a(10) 330 mul dh ;计算写入位置的行 331 add ax , 0b800h ;B800是起始位置,所以加上规定的行数 332 333 334 add dl , dl ;计算写入位置的列 335 mov dh , 0 336 337 338 mov es , ax ;设置写入位置的寄存器 339 mov di , dx 340 341 mov al , cl ;保存颜色 342 343 344 mov cx , 2 345 jmp first_start 346 again_2: 347 348 mov cl , ds:[si] ;获取要显示的数据 349 mov ch , 0 ;不需要高位 350 jcxz ok ;如果是0则返回(结束这个子程序) 351 352 mov es:[di] , cl ;将字符写入 353 mov es:[di + 1] , al ;写入颜色 354 add di , 2 ;指向下一个要写入的位置 355 inc si ;指向下一个要读取字符的位置 356 mov cl , 2 ;again循环每次都成立 357 first_start: 358 loop again_2 359 ok: pop dx ; 恢复 360 ret ;返回(结束)这个子程序 361 362 363 code ends 364 365 366 end start