第2节 嵌套与递归子程序
2.1 子程序的嵌套
例6.2.1 试编写在ARRAY1无符号数组中,选出最大值及其所在的位置,然后以16进制数显示在CRT上显示的程序.
要求: SUB14找出最大值及其位置子程序;
输入:个数(CX),首地址(SI)
输出:最大值(CX),位置(SI)
SUB15 显示子程序
输入:BX ; 例20FF
SUB16 十六进制显示子程序
输入:DL ;0~F之间的数
DATA SEGMENT
ARRAY1 DW 100 DUB(?)
COUNT EQU ($-ARRAY1)/2
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
MAIN PROC FAR
MOV AX, DATA
MOV DS, AX
//1.在数组中找最大值及位置
LEA SI, ARRAY1
MOV CX, COUNT
CALL SUB14 ; 找到最大数在CX中,位置在SI中
MOV DI, CX ; 保存找到的最大值在DI中
//2.显示段地址
MOV BX, DATA
CALL SUB15
//3.显示’:’字符
MOV DL, ‘:’
MOV AH, 2
INT 21H
//4.显示偏移地址
MOV BX, SI
CALL SUB15
//5.显示空格
MOV DL, 20H
MOV AH, 2
INT 21H
//6.显示最大值
MOV BX, DI
CALL SUB15
//7.退出
MOV AH, 4CH
INT 21H
//找出最大值及其位置子程序;
输入:个数(CX),首地址(SI)
输出:最大值(CX),位置(SI)
SUB14 PROC NEAR
PUSH AX
PUSH DI
MOV DI, SI ;DI中保存最大值的地址
MOV AX, [SI] ;从ARRAY1数组中取第一个数
AA1: CMP AX, [SI]
JNC AA2 ; JAE AA2
MOV AX, [SI] ;AX中保存最大值
MOV DI, SI ;DI中保存最大值地址
AA2: ADD SI, 2
LOOP AA1 ;子程序输入参数CX中有个数
MOV SI, DI ;最大值地址值
MOV CX, AX ;最大值
POP DI
POP AX
ret
SUB14 ENDP
//显示子程序. 输入:BX ; 例20FF
SUB15 PROC NEAR
//显示BH中高4位
MOV DL, BH
MOV CL, 4
SHR DL, CL
CALL SUB16
//显示BH中低4位
MOV DL, BH
AND DL, 0FH
CALL SUB16
//显示BL中高4位
MOV DL, BL
MOV CL, 4
SHR DL, CL
CALL SUB16
//显示BL中低4位
MOV DL, BL
AND DL, 0FH
CALL SUB16
RET
SUB15 ENDP
//十六进制显示子程序. 输入:DL ;0~F之间的数.
SUB16 PROC NEAR
OR DL, 30H
CMP DL, 3AH
JC AA3 ;JB AA3
ADD DL, 7 ;41H~46H, 3AH+7=41H
AA3: MOV AH, 2
INT 21H
RET
SUB16 ENDP
MAIN ENDP
CODE ENDS
END MAIN
2.2 递归子程序
子程序递归调用: 子程序调用自身子程序.
例6.2.2 试编写计算N!的递归子程序
1. 用缓冲区存放N、N-1、…、2、1,然后再依次取出作1x2x3x…xN运算的方式。
FACT1递归子程序
输入:个数(AL), 缓冲区首地址(SI)
输出: 计数结果(AX)
DATA SEGMENT
BUFF1 DB 3 DUP(?)
NN1 DB 3
RESULT1 DW 0
DATA ENDS
SET1 SEGMENT ‘STACK’
DW 100 DUP(?)
SET1 ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA, SS:SEG1
START:MOV AX, DATA
MOV DS, AX
MOV AL, NN1
LEA SI, BUFF1
CALL FACT1 ;调用递归子程序
AA2: MOV RESULT1, AX ;保存结果
MOV AH, 4CH
INT 21H
;递归子程序.
;输入:个数(AL), 缓冲区首地址(SI)
;输出: 计数结果(AX)
FACT1 PROC NEAR
CMP AL, 0
JNZ AA1 ;递归中止条件
MOV AL, 1
AA4: RET ;转到AA3
AA1: MOV [SI],AL ; 存放N、N-1、…、2、1
DEC AL
INC SI
CALL FACT1 ;调用自身,每调用一次会把AA3压入栈
AA3: DEC SI
MOV BL, [SI]
MUL BL ;AX al*bl
AA5 : RET ;转到AA3、转到AA3、。。。、转到AA2
FACT1 ENDP
CODE ENDS
END START
2. 2.用堆栈依次压入N、N-1、…、2、1,然后再依次取出作1x2x3x…xN运算的方式。
FACT1递归子程序
输入:个数(AX)
输出: 计数结果(AX)
DATA SEGMENT
N DW 3
RESULT1 DW 0
DATA ENDS
SET1 SEGMENT ‘STACK’
DW 100 DUP(?)
SET1 ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA, SS:SEG1
START:MOV AX, DATA
MOV DS, AX
MOV AX, N
CALL FACT1 ;调用递归子程序,求N!
AA2: MOV RESULT1, AX ;保存结果
MOV AH, 4CH
INT 21H
;递归子程序.
;输入:个数(AX)
;输出: 计数结果(AX)
FACT1 PROC NEAR
CMP AX, 0
JNZ AA1 ;递归中止条件
MOV AX, 1
AA4: RET ;转到AA3
AA1: PUSH AX ; N、N-1、…、2、1依次入栈
DEC AX
CALL FACT1 ;调用自身,每调用一次会把AA3压入栈
AA3: POP BX
MUL BL ; axal*bl
AA5 : RET ;转到AA3、转到AA3、。。。、转到AA2
FACT1 ENDP
CODE ENDS
END START
例6.2.1 试编写在ARRAY1无符号数组中,选出最大值及其所在的位置,然后以16进制数显示在CRT上显示的程序.
要求: SUB14找出最大值及其位置子程序;
输入:个数(CX),首地址(SI)
输出:最大值(CX),位置(SI)
SUB15 显示子程序
输入:BX ; 例20FF
SUB16 十六进制显示子程序
输入:DL ;0~F之间的数
DATA SEGMENT
ARRAY1 DW 100 DUB(?)
COUNT EQU ($-ARRAY1)/2
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
MAIN PROC FAR
MOV AX, DATA
MOV DS, AX
//1.在数组中找最大值及位置
LEA SI, ARRAY1
MOV CX, COUNT
CALL SUB14 ; 找到最大数在CX中,位置在SI中
MOV DI, CX ; 保存找到的最大值在DI中
//2.显示段地址
MOV BX, DATA
CALL SUB15
//3.显示’:’字符
MOV DL, ‘:’
MOV AH, 2
INT 21H
//4.显示偏移地址
MOV BX, SI
CALL SUB15
//5.显示空格
MOV DL, 20H
MOV AH, 2
INT 21H
//6.显示最大值
MOV BX, DI
CALL SUB15
//7.退出
MOV AH, 4CH
INT 21H
//找出最大值及其位置子程序;
输入:个数(CX),首地址(SI)
输出:最大值(CX),位置(SI)
SUB14 PROC NEAR
PUSH AX
PUSH DI
MOV DI, SI ;DI中保存最大值的地址
MOV AX, [SI] ;从ARRAY1数组中取第一个数
AA1: CMP AX, [SI]
JNC AA2 ; JAE AA2
MOV AX, [SI] ;AX中保存最大值
MOV DI, SI ;DI中保存最大值地址
AA2: ADD SI, 2
LOOP AA1 ;子程序输入参数CX中有个数
MOV SI, DI ;最大值地址值
MOV CX, AX ;最大值
POP DI
POP AX
ret
SUB14 ENDP
//显示子程序. 输入:BX ; 例20FF
SUB15 PROC NEAR
//显示BH中高4位
MOV DL, BH
MOV CL, 4
SHR DL, CL
CALL SUB16
//显示BH中低4位
MOV DL, BH
AND DL, 0FH
CALL SUB16
//显示BL中高4位
MOV DL, BL
MOV CL, 4
SHR DL, CL
CALL SUB16
//显示BL中低4位
MOV DL, BL
AND DL, 0FH
CALL SUB16
RET
SUB15 ENDP
//十六进制显示子程序. 输入:DL ;0~F之间的数.
SUB16 PROC NEAR
OR DL, 30H
CMP DL, 3AH
JC AA3 ;JB AA3
ADD DL, 7 ;41H~46H, 3AH+7=41H
AA3: MOV AH, 2
INT 21H
RET
SUB16 ENDP
MAIN ENDP
CODE ENDS
END MAIN
2.2 递归子程序
子程序递归调用: 子程序调用自身子程序.
例6.2.2 试编写计算N!的递归子程序
1. 用缓冲区存放N、N-1、…、2、1,然后再依次取出作1x2x3x…xN运算的方式。
FACT1递归子程序
输入:个数(AL), 缓冲区首地址(SI)
输出: 计数结果(AX)
DATA SEGMENT
BUFF1 DB 3 DUP(?)
NN1 DB 3
RESULT1 DW 0
DATA ENDS
SET1 SEGMENT ‘STACK’
DW 100 DUP(?)
SET1 ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA, SS:SEG1
START:MOV AX, DATA
MOV DS, AX
MOV AL, NN1
LEA SI, BUFF1
CALL FACT1 ;调用递归子程序
AA2: MOV RESULT1, AX ;保存结果
MOV AH, 4CH
INT 21H
;递归子程序.
;输入:个数(AL), 缓冲区首地址(SI)
;输出: 计数结果(AX)
FACT1 PROC NEAR
CMP AL, 0
JNZ AA1 ;递归中止条件
MOV AL, 1
AA4: RET ;转到AA3
AA1: MOV [SI],AL ; 存放N、N-1、…、2、1
DEC AL
INC SI
CALL FACT1 ;调用自身,每调用一次会把AA3压入栈
AA3: DEC SI
MOV BL, [SI]
MUL BL ;AX al*bl
AA5 : RET ;转到AA3、转到AA3、。。。、转到AA2
FACT1 ENDP
CODE ENDS
END START

2. 2.用堆栈依次压入N、N-1、…、2、1,然后再依次取出作1x2x3x…xN运算的方式。
FACT1递归子程序
输入:个数(AX)
输出: 计数结果(AX)
DATA SEGMENT
N DW 3
RESULT1 DW 0
DATA ENDS
SET1 SEGMENT ‘STACK’
DW 100 DUP(?)
SET1 ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA, SS:SEG1
START:MOV AX, DATA
MOV DS, AX
MOV AX, N
CALL FACT1 ;调用递归子程序,求N!
AA2: MOV RESULT1, AX ;保存结果
MOV AH, 4CH
INT 21H
;递归子程序.
;输入:个数(AX)
;输出: 计数结果(AX)
FACT1 PROC NEAR
CMP AX, 0
JNZ AA1 ;递归中止条件
MOV AX, 1
AA4: RET ;转到AA3
AA1: PUSH AX ; N、N-1、…、2、1依次入栈
DEC AX
CALL FACT1 ;调用自身,每调用一次会把AA3压入栈
AA3: POP BX
MUL BL ; axal*bl
AA5 : RET ;转到AA3、转到AA3、。。。、转到AA2
FACT1 ENDP
CODE ENDS
END START



