求助第二发

c1z1h1 2016-03-23 08:10:43
上次提问了作业的问题后,回去好好的研究了半天,也是明白了很多东西,后来的作业也能自己独立完成了,但是!这次的作业简直丧心病狂!我实在不明白老师为什么要这么写。子程序难道不能和前面写在一起吗看着还方便我这还得前后来回拉着看!以至于这回的作业实在是看不出什么门道,只好厚颜无耻原封不动地贴上了求大神给点思路让我先思考思考!

这次的 程序是要从键盘输入一个字符串(长度限制在50以内),并显示
;提示:输入字符串可以用DOS调用,功能3FH,BX=0
;统计这个字符串的长度,并显示
;统计字符串里的数字字符的个数,并显示
;将字符串做逆序处理,并显示
;将字符串中的小写字母转换为大写字母,并显示
老师啊你为什么要样!分成几个程序不好吗!

.model small
.DATA
STR DB 50 DUP(0)
STR_I DB 50 DUP(0) ; 存放逆序的字符串
LEN DB ?
num_D DB ?
.code
MAIN PROC NEAR
MOV AX,@DATA
MOV DS,AX

; 以下程序用文件的方式读取字符串STR
LEA AX,STR
PUSH AX
CALL GETS
ADD SP,2
MOV LEN,AL

; 以下程序打印字符串STR
LEA AX,STR
PUSH AX
CALL PRINTS
ADD SP,2

; 以下程序返回字符串STR的长度
LEA AX,STR
PUSH AX
CALL STR_LEN
ADD SP,2
MOV LEN,AL

; 以下程序打印LEN的数字
MOV AL,LEN
XOR AH,AH
PUSH AX
CALL PRINT_N
ADD SP,2

; 以下程序统计STR中数字的个数
LEA AX,STR
PUSH AX
CALL N_NUM
ADD SP,2
MOV num_D,AL

; 以下程序打印num_D的数字
MOV AL,num_D
XOR AH,AH
PUSH AX
CALL PRINT_N
ADD SP,2

; 以下程序返回字符串STR的逆序
LEA AX,STR
PUSH AX
LEA AX,STR_I
PUSH AX
CALL STR_INV
ADD SP,4

; 以下程序打印字符串STR_I
LEA AX,STR_I
PUSH AX
CALL PRINTS
ADD SP,2

; 以下程序将字符串中的小写字母转换为大写字母
LEA AX,STR
PUSH AX
CALL STR_UCASE
ADD SP,2

; 以下程序打印字符串STR
LEA AX,STR
PUSH AX
CALL PRINTS
ADD SP,2

MOV AX,4C00H
INT 21H
MAIN ENDP

; 键盘读取字符的子程序
GETS PROC NEAR
PUSH BP
MOV BP,SP
MOV DX,[BP+4]
; ......
POP BP
RET
GETS ENDP

; 打印字符串的子程序
PRINTS PROC NEAR
PUSH BP
MOV BP,SP
MOV SI,[BP+4]
; ......
POP BP
RET
PRINTS ENDP

STR_LEN PROC NEAR
PUSH BP
MOV BP,SP
MOV SI,[BP+4]
; ......
POP BP
RET
STR_LEN ENDP

STR_INV PROC NEAR
PUSH BP
MOV BP,SP
MOV DI,[BP+4]
MOV SI,[BP+6]

; ......
POP BP
RET
STR_INV ENDP

; 打印字符串的子程序
STR_UCASE PROC NEAR
PUSH BP
MOV BP,SP
MOV SI,[BP+2]
; ......
POP BP
RET
STR_UCASE ENDP

; 两位十进制数的打印子程序
PRINT_N PROC NEAR
PUSH BP
MOV BP,SP
MOV AX,[BP+4]
; ......
POP BP
RET
PRINT_N ENDP

; 统计STR中数字个数的子程序
N_NUM PROC NEAR
PUSH BP
MOV BP,SP
MOV SI,[BP+4]
; ......
POP BP
RET
N_NUM ENDP
END MAIN

有省略号的地方是需要自己补全的,每个子程序都要,应该是有七处
在此先行谢过,求大神帮看
...全文
654 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
c1z1h1 2016-03-30
  • 打赏
  • 举报
回复
。。好的,周末没怎么看。。看了也不懂。。不过子程序调用的部分懂了,还是谢谢大神讲解@fornetuse123 。完后剩下就是专门作用的代码了,显示的部分会写,但是其他的几项好像没学过。。所以希望能有个样例,因为网上的其他程序真的看不明白,好多代码都没见过。。所以只好伸手了。。 .model small .DATA STR DB 50 DUP(0) STR_I DB 50 DUP(0) ; 存放逆序的字符串 LEN DB ? num_D DB ? .code MAIN PR+OC NEAR MOV AX,@DATA MOV DS,AX ; 以下程序用文件的方式读取字符串STR LEA AX,STR PUSH AX CALL GETS ADD SP,2 MOV LEN,AL ; 以下程序打印字符串STR LEA AX,STR PUSH AX CALL PRINTS ADD SP,2 ; 以下程序返回字符串STR的长度 LEA AX,STR PUSH AX CALL STR_LEN ADD SP,2 MOV LEN,AL ; 以下程序打印LEN的数字 MOV AL,LEN XOR AH,AH PUSH AX CALL PRINT_N ADD SP,2 ; 以下程序统计STR中数字的个数 LEA AX,STR PUSH AX CALL N_NUM ADD SP,2 MOV num_D,AL ; 以下程序打印num_D的数字 MOV AL,num_D XOR AH,AH PUSH AX CALL PRINT_N ADD SP,2 ; 以下程序返回字符串STR的逆序 LEA AX,STR PUSH AX LEA AX,STR_I PUSH AX CALL STR_INV ADD SP,4 ; 以下程序打印字符串STR_I LEA AX,STR_I PUSH AX CALL PRINTS ADD SP,2 ; 以下程序将字符串中的小写字母转换为大写字母 LEA AX,STR PUSH AX CALL STR_UCASE ADD SP,2 ; 以下程序打印字符串STR LEA AX,STR PUSH AX CALL PRINTS ADD SP,2 MOV AX,4C00H INT 21H MAIN ENDP ; 键盘读取字符的子程序 GETS PROC NEAR PUSH BP MOV BP,SP MOV DX,[BP+4] ; ...... POP BP RET GETS ENDP ; 打印字符串的子程序 PRINTS PROC NEAR PUSH BP MOV BP,SP MOV SI,[BP+4] ; ...... POP BP RET PRINTS ENDP STR_LEN PROC NEAR PUSH BP MOV BP,SP MOV SI,[BP+4] ; ...... POP BP RET STR_LEN ENDP STR_INV PROC NEAR PUSH BP MOV BP,SP MOV DI,[BP+4] MOV SI,[BP+6] ; ...... POP BP RET STR_INV ENDP ; 打印字符串的子程序 STR_UCASE PROC NEAR PUSH BP MOV BP,SP MOV SI,[BP+2] LEA DX,STR MOV BX,0 LEA DX,STR MOV BX,0 MOV CX,STR_LEN MOV AH,40H INT 21H POP BP RET STR_UCASE ENDP ; 两位十进制数的打印子程序 PRINT_N PROC NEAR PUSH BP MOV BP,SP MOV AX,[BP+4] ; ...... POP BP RET PRINT_N ENDP ; 统计STR中数字个数的子程序 N_NUM PROC NEAR PUSH BP MOV BP,SP MOV SI,[BP+4] ; ...... POP BP RET N_NUM ENDP END MAIN
fornetuse123 2016-03-24
  • 打赏
  • 举报
回复
子程序难道不能和前面写在一起吗看着还方便 至于为什么要用子程序,其实很简单,1、因为子程序经常被用到,每次都重复写子程序中的代码是不是很无聊很没效率 2、你仔细看看,就会发现子程序都是别人给它赋值的,也就是子程序没有在自身内部为自己赋值,这样,万一你要变化参数数值,就不用去更改子程序,这样很好维护代码。 当你不会写程序的时候,你觉得很有趣,但是让你整天都写程序的时候,特别是每天都写相同功能 的相同代码的时候,你就能理解他们为什么会自称码农了
fornetuse123 2016-03-24
  • 打赏
  • 举报
回复
为了方便,本来可以用sp来做基址指针,但是因为sp总是会变化,所以选择bp将初始sp值存起来,这样bp就是固定值了 所以先PUSH BP 保护原始bp, MOV BP,SP 将子程序运行时的初值给bp MOV SI,[BP+4], 因为原来的子程序参数存在内存sp+2=bp+2处,现在因为上面PUSH BP 保护原始bp,所以初始sp=sp-2,那么 子程序参数存在内存sp+2=bp+2处就变成sp+2+2=bp+2+2=bp+4 CALL GETS ADD SP,2 这里也要注意,这里之所以要add是因为子程序调用是有规则的,即由调用者还是被调用者来平衡堆栈(简单的意思就是堆栈在调用前和调用返回后栈顶指针保持位置值不变),这里采用的是c语言规范,即由调用者平衡, 上面说过,call前push过一个被调用子程序的参数,然后call后又push了一个call命令行下面的那条指令内存地址,在子程序ret命令执行后,堆栈隐式的将该指令内存地址pop给ip,这样sp指针指向了被调用子程序的参数,所以要ADD SP,2恢复成调用者调用者调用前的堆栈状态 其它的你就跟以前学过的一样用就好,一个关键是在子程序的ret命令前不要忘记将子程序中push过的pop出来,以平衡子程序的堆栈
fornetuse123 2016-03-24
  • 打赏
  • 举报
回复
你大概看不懂的是被调用子程序中的 PUSH BP MOV BP,SP MOV SI,[BP+4] 这些吧,这些都是标准的被调用子程序中的标准语句,作用是用bp做堆栈(也称作子程序的栈帧)的基址指针, 你看每个子程序的调用规律: 一个或几个push行然后来个call,call前面的push就是给子程序传递参数数值的 你知道call这个命令实际上是将call命令行下面的那条指令内存地址push进了堆栈,但这是隐式的,也就是程序代码里看不到。 这样在子程序运行前的堆栈情况是这样的,sp指向call命令行下面的那条指令内存地址;sp+2指向子程序的参数值(这里只有一个参数,如果还有的话,将是sp+4,+6.。。)。 现在开始运行子程序: 为了方便,本来可以用sp来做基址指针,但是因为sp总是会变化,所以选择bp将初始sp值存起来,这样bp就是固定值了 所以先PUSH BP 保护原始bp, MOV BP,SP 将子程序运行时的初值给bp MOV SI,[BP+4], 因为原来的子程序参数存在内存sp+2=bp+2处,现在因为上面PUSH BP 保护原始bp,所以初始sp=sp+2,那么 子程序参数存在内存sp+2=bp+2处就变成sp+2+2=bp+2+2=bp+4 CALL GETS ADD SP,2 这里也要注意,这里之所以要add是因为子程序调用是有规则的,即由调用者还是被调用者来平衡堆栈(简单的意思就是堆栈在调用前和调用返回后栈顶指针保持位置值不变),这里采用的是c语言规范,即由调用者平衡, 上面说过,call前push过一个被调用子程序的参数,然后call后又push了一个call命令行下面的那条指令内存地址,在子程序ret命令执行后,堆栈隐式的将该指令内存地址pop,这样sp指针指向了被调用子程序的参数,所以要ADD SP,2恢复成调用者调用者调用前的堆栈状态
c1z1h1 2016-03-24
  • 打赏
  • 举报
回复
@fornetuse123 谢大神,待我研究一下
AK400 2016-03-24
  • 打赏
  • 举报
回复
赞一下,棒棒的

21,458

社区成员

发帖
与我相关
我的任务
社区描述
汇编语言(Assembly Language)是任何一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。
社区管理员
  • 汇编语言
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧