98_hzk_gb2312_v0.4.asm

来自「汇编语言 参考书 包含作业与答案 从入门到精通 通俗易懂」· 汇编 代码 · 共 486 行

ASM
486
字号
		.model small
		.stack 100h
		.data
				file_cclib	db	'hzk16',0
				handle_cclib	dw	?				; CCLIB 文件句柄
				buffer_cclib 	db	32	DUP(?),'$'
				file_read	db	'test.txt',0
				handle_read	dw	?				;读取文件句柄
				buffer_read	dw	?
				char_offset	db	4	DUP(?),'$'
				print_buffer	db	3	DUP(?),'  $'
				linex		dw	?
				liney		dw	?
				msg_open_error	db	'File open wrong!','$'
				msg_read_error	db	'File read wrong!','$'
				
		.code
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
main	proc	far

		mov	ax,@data
		mov	ds,ax
;;;;;;;;;;;;;;		

	mov	bh,0h		;读当前光标的位置
	mov	ah,3h
	INT	10h
	
	mov	ax,16		;保存光标位置,按象素点的行列保存
	mul	dh
	mov	linex,ax		
	mov	ax,16
	mul	dl
	mov	liney,ax
		
	mov	al,12h		;设置显示模式为640*480,16色模式
	mov	ah,0h
	INT	10h
;;*************************************************************************
open_file:

		lea	dx,file_read		;打开所读文件
		mov	al,0
		mov 	ah,3dh
		INT 	21h
		jc	open_error
		mov	handle_read,ax		;保存文件句柄
		
		lea	 dx,file_cclib		;打开CCLIB
		mov	 al,0
		mov 	ah,3dh
		INT 	21h
		jc	open_error
		mov 	handle_cclib,ax		;保存字库句柄

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;   读取并显示一个汉字,并循环

getword_file:			;从待显示的文件中读取两个字节			

		mov	bx,handle_read		;INT  21H   42号功能移动文件指针
		mov	cx,0
		mov	dx,0h
		mov	al,1		;移动方式,从当前位置开始移动
		mov 	ah,42h
		INT 	21h
		
		mov 	bx,handle_read		;读文件,INT  21H,3F号功能
		mov 	cx,1			;只读取一个字节
		lea 	dx,buffer_read		;保存位置
		mov 	ah,3fh
		INT 	21h
		jc	read_error		
	;;;;;;;;;;;;;;;	
		test	ax,0ffffh		;测试文件是否结束,AX中为实际写入的字节数,当为0时,表示EOF
		jz	done
	;;;;;;;;;;;;;;;
		mov 	ax,buffer_read		;判断读到的字符是否为ACSII字符,是则用INT  21H号中断显示
		cmp	al,0a0h
		jb	print_ansi_char
	;;;;;;;;;;;;;;;;		
		mov	bx,handle_read		;若为汉字,则再读取一个字节,并保存之后
		mov 	cx,1
		lea	dx,buffer_read+1
		mov 	ah,3fh
		INT 	21h
		jc	read_error
;***************************************************************
count_offset:					;计算在CCLIB中的偏移量   qh=c1-0xa0 wh=c2-0xa0 
	;;;;;;;;;;;;;;;;;;;;;;			;该汉字在字库中离起点的位置是: offset=(94*(qh-1)+(wh-1))*32L
		mov 	bx,buffer_read
		sub	bh,0a0h
		sub	 bl,0a0h
		dec 	bh
		dec 	bl
		
		xor 	ax,ax
		mov	al,bl
		mov	cl,94					;此时不会溢出
		mul	cl
		
		xor 	cx,cx
		mov	cl,bh
		add 	ax,cx
		mov 	cx,32
		mul 	cx
		;mov buffer_read,ax		;结果保存在DX+AX中,可再写入buffer_read
		
;;****************************************************************	
read_cclib:					;从CCLIB中读入16*16的点阵,32个字节,并保存在buffer_cclib中

		mov	bx,handle_cclib
		mov	cx,dx			;count_offset计算所得偏移量保存在DX:AX中,现在放入CX:DX中,42号功能
		mov	dx,ax
		mov	al,0		;从文件头开始读取,与待显示的文件指针移动方式不同
		mov 	ah,42h
		INT 	21h
		
		mov	bx,handle_cclib
		mov 	cx,32		;32个字节
		lea	dx,buffer_cclib
		mov 	ah,3fh
		INT 	21h		
		
;;**************************************************************	;输出汉字
	call	print_normal
	;call	print_left
	;call	print_right
	;call 	print_reverse

;;****************************************************************************
change:					;屏幕满时开始上滚一行
	cmp	linex,480
	jz	reset_x
	jmp	changerow	
reset_x:
	mov	al,1
	mov	ah,6h
	xor	cx,cx
	mov	dh,30
	mov	dl,80
	mov	bh,0
	INT	10h

	sub	linex,16	;恢复到上一行	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;换行
changerow:
	cmp	liney,624
	jae	reset_y		;大于等于跳至换行
	add	liney,16
	jmp	next		
reset_y:
	mov	liney,0h
	add	linex,16
;;;;;;;************************************************************				;开始读第二个字
next:		jmp getword_file	;loop	getword_file	;为什么用LOOP提示超出NEAR的范围,如何解决?
;;********************************************************	;附加的一些处理程序段			
print_ansi_char:		;用来显示一些非汉字字符,即ASCII字符
		mov dx,buffer_read
		cmp	dl,10
		jz	needchangeline
		jmp	gogogo
needchangeline:
		mov	liney,624		;置Y轴的坐标大于边界,跳至上边会自动换行。  不用在此强制换行mov liney,0并且不会产生换行多两个字符的BUG
		;add	linex,16	
		jmp	change
		
gogogo:
	mov	bl,16
	mov	ax,linex
	cmp	ax,0
	jz	cannotdiv_x
	div	bl
	mov	dh,al
	jmp	get_y
cannotdiv_x:
	mov	dh,0

get_y:
	mov	ax,liney
	cmp	ax,0
	jz	cannotdiv_y
	mov	bl,8
	div	bl
	mov	dl,al
	jmp	positionisok
cannotdiv_y:
	mov	dl,0
	
positionisok:
	mov	ah,2h
	INT	10h

		mov dx,buffer_read
		mov ah,2h
		INT 21h
	;sub	liney,8
	
		jmp	change
;;****************************************************************  ;错误处理程序		
open_error:
		lea	dx,msg_open_error
		mov	ah,9h
		INT	21h
		jmp	done
read_error:
		lea	dx,msg_read_error
		mov ah,9h
		INT 21h
		jmp done
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;		
done:
		mov ah,4ch
		INT 21h

main	ENDP
;;****************************************************************  ;正常显示汉字子程序
print_normal	proc	near
					
	mov	dx,linex		;设置X轴的坐标
	mov	cx,16			;每个汉字显示为16行
	lea	si,buffer_cclib
writex:
	push	cx
	mov	bx,liney		;设置Y轴的坐标
	;;;;;;;;;;
	mov	cx,8			;一个汉字为16列,此为第一个字节显示
	mov	ah,[si]
writey:
	shl	ah,1
	jc	iszero
	xor	al,al
	jmp	goon
iszero:
	mov	al,7h
goon:
	push	ax
	mov	ah,0ch
	xchg	cx,bx
	push	bx
	xor	bx,bx
	INT	10h
	pop	bx
	xchg	cx,bx	
	pop	ax
	
	inc	bx
	loop	writey
	;;;;;;;;;;;;;	

inc	si
	mov	cx,8
	mov	ah,[si]
writey2:
	shl	ah,1
	jc	iszero2
	xor	al,al
	jmp	goon2
iszero2:
	mov	al,7h
goon2:
	push	ax
	mov	ah,0ch
	xchg	cx,bx
	push	bx
	xor	bx,bx
	INT	10h
	pop	bx
	xchg	cx,bx	
	pop	ax
	
	inc	bx		;bx代替CX来计算列地址,右移一列
	loop	writey2
;;;;;;;;;;;;;;;;

	pop	cx
	inc	dx		;DX为行地址,下移一行
	inc	si
	loop	writex		;开始行循环

	RET
print_normal	ENDP
;;****************************************************************  ;左转90度显示汉字子程序
print_left	proc	near
					
	mov	bx,liney		;设置X轴的坐标
	;add	bx,16
	mov	cx,16			;每个汉字显示为16行
	lea	si,buffer_cclib
writex:
	push	cx
	mov	dx,linex		;设置Y轴的坐标
	add	dx,16
	;;;;;;;;;;
	mov	cx,8			;一个汉字为16列,此为第一个字节显示
	mov	ah,[si]
writey:
	shl	ah,1
	jc	iszero
	xor	al,al
	jmp	goon
iszero:
	mov	al,7h
goon:
	push	ax
	mov	ah,0ch
	xchg	cx,bx
	push	bx
	xor	bx,bx
	INT	10h
	pop	bx
	xchg	cx,bx	
	pop	ax
	
	dec	dx
	loop	writey
	;;;;;;;;;;;;;	

inc	si
	mov	cx,8
	mov	ah,[si]
writey2:
	shl	ah,1
	jc	iszero2
	xor	al,al
	jmp	goon2
iszero2:
	mov	al,7h
goon2:
	push	ax
	mov	ah,0ch
	xchg	cx,bx
	push	bx
	xor	bx,bx
	INT	10h
	pop	bx
	xchg	cx,bx	
	pop	ax
	
	dec	dx		;bx代替CX来计算列地址,右移一列
	loop	writey2
;;;;;;;;;;;;;;;;

	pop	cx
	inc	bx		;DX为行地址,下移一行
	inc	si
	loop	writex		;开始行循环

	RET
print_left	ENDP
;;****************************************************************  ;右转90度显示汉字子程序
print_right	proc	near
					
	mov	bx,liney		;设置X轴的坐标
	add	bx,16
	mov	cx,16			;每个汉字显示为16行
	lea	si,buffer_cclib
writex:
	push	cx
	mov	dx,linex		;设置Y轴的坐标
	;add	dx,16
	;;;;;;;;;;
	mov	cx,8			;一个汉字为16列,此为第一个字节显示
	mov	ah,[si]
writey:
	shl	ah,1
	jc	iszero
	xor	al,al
	jmp	goon
iszero:
	mov	al,7h
goon:
	push	ax
	mov	ah,0ch
	xchg	cx,bx
	push	bx
	xor	bx,bx
	INT	10h
	pop	bx
	xchg	cx,bx	
	pop	ax
	
	inc	dx
	loop	writey
	;;;;;;;;;;;;;	

inc	si
	mov	cx,8
	mov	ah,[si]
writey2:
	shl	ah,1
	jc	iszero2
	xor	al,al
	jmp	goon2
iszero2:
	mov	al,7h
goon2:
	push	ax
	mov	ah,0ch
	xchg	cx,bx
	push	bx
	xor	bx,bx
	INT	10h
	pop	bx
	xchg	cx,bx	
	pop	ax
	
	inc	dx		;bx代替CX来计算列地址,右移一列
	loop	writey2
;;;;;;;;;;;;;;;;

	pop	cx
	dec	bx		;DX为行地址,下移一行
	inc	si
	loop	writex		;开始行循环

	RET
print_right	ENDP
;;****************************************************************  ;倒转显示汉字子程序
print_reverse	proc	near
					
	mov	dx,linex		;设置X轴的坐标
	add	dx,16
	mov	cx,16			;每个汉字显示为16行
	lea	si,buffer_cclib
writex:
	push	cx
	mov	bx,liney		;设置Y轴的坐标
	;;;;;;;;;;
	mov	cx,8			;一个汉字为16列,此为第一个字节显示
	mov	ah,[si]
writey:
	shl	ah,1
	jc	iszero
	xor	al,al
	jmp	goon
iszero:
	mov	al,7h
goon:
	push	ax
	mov	ah,0ch
	xchg	cx,bx
	push	bx
	xor	bx,bx
	INT	10h
	pop	bx
	xchg	cx,bx	
	pop	ax
	
	inc	bx
	loop	writey
	;;;;;;;;;;;;;	

inc	si
	mov	cx,8
	mov	ah,[si]
writey2:
	shl	ah,1
	jc	iszero2
	xor	al,al
	jmp	goon2
iszero2:
	mov	al,7h
goon2:
	push	ax
	mov	ah,0ch
	xchg	cx,bx
	push	bx
	xor	bx,bx
	INT	10h
	pop	bx
	xchg	cx,bx	
	pop	ax
	
	inc	bx		;bx代替CX来计算列地址,右移一列
	loop	writey2
;;;;;;;;;;;;;;;;

	pop	cx
	dec	dx		;DX为行地址,下移一行
	inc	si
	loop	writex		;开始行循环

	RET
print_reverse	ENDP
;;********************************************************************************************
END	main					

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?