任务要求
编写一个汇编程序,使得从键盘上输入十个以内的字符,以输入回车结束,然后按数字、字母和其它符号三类统计各自的个数,统计结果分别保存在BL(保存小写字母的个数)、BH(保存大写字母的个数)、DH(保存数字的个数)和DL(保存其他字符的个数)四个寄存器中。
正确代码
DATA SEGMENT
S_OUT DB 'Please enter a string less than 10 characters:$'
S_INT DB 11, ?, 11 DUP(0)
COUNT EQU $-S_INT
DATA ENDS
STACK SEGMENT STACK
DB 100 DUP(?)
STACK ENDS
CODE SEGMENT
ASSUME DS:DATA, CS:CODE, SS:STACK
START:
MOV AX, DATA
MOV DS,AX
MOV AH,09H
LEA DX, S_OUT
INT 21H
MOV AH, 0AH
LEA DX, S_INT
INT 21H
LEA SI, S_INT+2
MOV CX, COUNT-3 ;防止地址出现遍历次数过多的情况
MOV BX, 0
MOV DX, 0
CALL ENUMERATE
MOV AH, 4CH
INT 21H
ENUMERATE PROC
AGAIN: MOV AL, [SI]
CMP AL, 'A'
JB NEXT
CMP AL, 'Z'
JA NEXT1
ADD BH, 1
INC SI
LOOP AGAIN
RET
NEXT: CMP AL, '0'
JB DONE
CMP AL, '9'
JA DONE
ADD DH, 1
INC SI
LOOP AGAIN
RET
DONE: ADD DL, 1
INC SI
LOOP AGAIN
RET
NEXT1: CMP AL, 'a'
JB DONE
CMP AL, 'z'
JA DONE
ADD BL, 1
INC SI
LOOP AGAIN
RET
ENUMERATE ENDP
CODE ENDS
END START
执行结果
从执行结果可以看到,程序执行完毕后,数字存入了要求的寄存器中
心路历程
来吧分析
第一个要求是从键盘上输入十个以内的字符,以输入回车结束,这个其实好实现,关键在回车结束而不是以字符$结束,(LEA CRLF)还有要求输入十个以内的字符,这样的话需要限定存储单元的长度为10,并且设置超出范围的报错(用C++先预演下)提示信息为:请输入十个以内的字符,请重新输入:,需要有提示后返回主程序继续执行,继续判断的功能
按数字,字母和其他三类统计各自的个数,BL(存小写字母的个数,小写字母其实是61-7A),BH(存大写字母个数,大写字母是41-5A),DH(保存数字的个数,30-39),DL(保存其他字符的个数,不是大小写字母,数字,剩下的就是其他字符)
注意MOV指令中寄存器的匹配问题
那,题目解析完了,基本的判断逻辑架构也有了,接下来解决下具体的实现问题
本来是用子程序的,写着写着成分支结构了
DATA SEGMENT
S_OUT DB '请输入长度小于十的字符串:$'
S_INT DB 10, ?, DUP(10)
COUNT EQU $-S_INT
DATA ENDS
STACK SEGMENT STACK
DB 200 DUP(?)
STACK ENDS
CODE SEGMENT
ASSUME DS:DATA, CS:CODE, SS:STACK
START MOV AX,DATA
MOV DS,AX
MOV AH,09H
LEA DX,S_OUT
INT 21H
MOV AH, 0AH
LEA DX,S_INT
INT 21H
MOV [SI],DX
MOV CX, COUNT
MOV BX, 0
MOV DX, 0
AGAIN: MOV AL,[SI]
CMP AL,'A'
JL NEXT
CMP AL,'Z'
JB NEXT1
ADD BH, 1
INC SI
LOOP AGAIN
NEXT: CMP AL, '0'
JL DONE
CMP AL, '9'
JB DONE
ADD DH, 1
INC SI
LOOP AGAIN
DONE: ADD DL, 1
INC SI
LOOP AGAIN
NEXT1: CMP AL, 'a'
JL DONE
CMP AL, 'z'
JB DONE
ADD BL, 1
INC SI
LOOP AGAIN
CODE ENDS
END START
第二版代码
改了第一版的报错,但产生了卡死,估计是CX循环的问题
DATA SEGMENT
S_OUT DB 'Enter a string less than 10 characters:$'
S_INT DB 10, ?, 10 DUP(10)
COUNT EQU $-S_INT
DATA ENDS
STACK SEGMENT STACK
DB 100 DUP(?)
STACK ENDS
CODE SEGMENT
ASSUME DS:DATA, CS:CODE, SS:STACK
START:
MOV AX, DATA
MOV DS,AX
MOV AH,09H
LEA DX,S_OUT
INT 21H
MOV AH, 0AH
LEA DX,S_INT
INT 21H
MOV [SI],DX
MOV CX, COUNT
MOV BX, 0
MOV DX, 0
AGAIN: MOV AL,[SI]
CMP AL,'A'
JL NEXT
CMP AL,'Z'
JB NEXT1
ADD BH, 1
INC SI
LOOP AGAIN
MOV AH, 4CH
INT 21H
NEXT: CMP AL, '0'
JL DONE
CMP AL, '9'
JB DONE
ADD DH, 1
INC SI
LOOP AGAIN
MOV AH, 4CH
INT 21H
DONE: ADD DL, 1
INC SI
LOOP AGAIN
MOV AH, 4CH
INT 21H
NEXT1: CMP AL, 'a'
JL DONE
CMP AL, 'z'
JB DONE
ADD BL, 1
INC SI
LOOP AGAIN
MOV AH, 4CH
INT 21H
CODE ENDS
END START
第三版代码
本来就觉得分支写的不符合题意,既然报错了,不妨改成子程序,现在好像也明白了为什么得用子程序写,子程序写的话,代码的逻辑简洁度会高一点
DATA SEGMENT
S_OUT DB 'Please enter a string less than 10 characters:$'
S_INT DB 10, ?, 10 DUP(10)
DATA ENDS
STACK SEGMENT STACK
DB 100 DUP(?)
STACK ENDS
CODE SEGMENT
ASSUME DS:DATA, CS:CODE, SS:STACK
START:
MOV AX, DATA
MOV DS,AX
MOV AH,09H
LEA DX,S_OUT
INT 21H
MOV AH, 0AH
LEA DX,S_INT
INT 21H
MOV [SI],DX
MOV CX, 0
MOV CX, SI+1
MOV BX, 0
MOV DX, 0
CALL ENUMERATE
MOV AH, 4CH
INT 21H
ENUMERATE PROC
AGAIN: MOV AL,[SI]
CMP AL,'A'
JL NEXT
CMP AL,'Z'
JB NEXT1
ADD BH, 1
INC SI
LOOP AGAIN
RET
NEXT: CMP AL, '0'
JL DONE
CMP AL, '9'
JB DONE
ADD DH, 1
INC SI
LOOP AGAIN
RET
DONE: ADD DL, 1
INC SI
LOOP AGAIN
RET
NEXT1: CMP AL, 'a'
JL DONE
CMP AL, 'z'
JB DONE
ADD BL, 1
INC SI
LOOP AGAIN
RET
ENUMERATE ENDP
CODE ENDS
END START
结果还是卡死,那问题很有可能出在了循环上
第四版代码
后来发现是存储空间的问题,是声明原因还没搞清楚,猜想可能和定义空间存储有关,第一个单元存的是整个空间的长度,之后才存储字符
DATA SEGMENT
S_OUT DB 'Please enter a string less than 10 characters:$'
S_INT DB 10, ?, 10 DUP(10)
DATA ENDS
STACK SEGMENT STACK
DB 100 DUP(?)
STACK ENDS
CODE SEGMENT
ASSUME DS:DATA, CS:CODE, SS:STACK
START:
MOV AX, DATA
MOV DS,AX
MOV AH,09H
LEA DX,S_OUT
INT 21H
MOV AH, 0AH
LEA DX,S_INT
INT 21H
MOV [SI],DX
MOV CX, 0
MOV CX, [SI+1]
MOV BX, 0
MOV DX, 0
CALL ENUMERATE
MOV AH, 4CH
INT 21H
ENUMERATE PROC
AGAIN: MOV AL,[SI+1]
CMP AL,'A'
JL NEXT
CMP AL,'Z'
JB NEXT1
ADD BH, 1
INC SI
LOOP AGAIN
RET
NEXT: CMP AL, 30
JL DONE
CMP AL, 39
JB DONE
ADD DH, 1
INC
LOOP AGAIN
RET
DONE: ADD DL, 1
INC SI
LOOP AGAIN
RET
NEXT1: CMP AL, 'a'
JL DONE
CMP AL, 'z'
JB DONE
ADD BL, 1
INC SI
LOOP AGAIN
RET
ENUMERATE ENDP
CODE ENDS
END START
第五版代码
逻辑有问题,连用了JL和JB两个判断符,导致寄存器存储的不是对应的值
符号JB/JA是一组(无符号数的判断),JL/JG是一组(有符号数的判段),下面的代码把判断大小搞混了
DATA SEGMENT
S_OUT DB 'Please enter a string less than 10 characters:$'
S_INT DB 11, ?, 11 DUP(11)
DATA ENDS
STACK SEGMENT STACK
DB 100 DUP(?)
STACK ENDS
CODE SEGMENT
ASSUME DS:DATA, CS:CODE, SS:STACK
START:
MOV AX, DATA
MOV DS,AX
MOV AH,09H
LEA DX,S_OUT
INT 21H
MOV AH, 0AH
LEA DX,S_INT
INT 21H
MOV [SI],DX
MOV CX, 0
MOV CX, [SI+1]
MOV BX, 0
MOV DX, 0
CALL ENUMERATE
MOV AH, 4CH
INT 21H
ENUMERATE PROC
AGAIN: MOV AL,[SI+1]
CMP AL,'A'
JL NEXT
CMP AL,'Z'
JB NEXT1
ADD BH, 1
INC SI
LOOP AGAIN
RET
NEXT: CMP AL, 30
JL DONE
CMP AL, 39
JB DONE
ADD DH, 1
INC SI
LOOP AGAIN
RET
DONE: ADD DL, 1
INC SI
LOOP AGAIN
RET
NEXT1: CMP AL, 'a'
JL DONE
CMP AL, 'z'
JB DONE
ADD BL, 1
INC SI
LOOP AGAIN
RET
ENUMERATE ENDP
CODE ENDS
END START
今日小结
写代码的快乐在于一次又一次的突破,剥开层层迷雾,最终走向那个正确的结果。
这哪是工作呀,这分明是学习,是享受啊,从知识的学习者转变为知识的应用者,成为知识的创造者,脑中的一个又一个可能,流淌到指尖,在键盘上不断跳跃,汇聚成一行行代码,开出灿烂而美妙的花朵,心中无比宁静,空气中充满了自由的味道
看到一个又一个关键点,寻找一种接一种的可能,带着期望,带着忐忑,带着兴奋不断尝试,最终,在那个恰当的时间,砰的一声,豁然开朗,长舒一口气,满是幸福
继续努力吧,做一个开心学习的人儿
报告心路历程
亲爱的老师,这是我这次实验的心路历程,无人述说,可以的话,请允许我以这样的方式向您述说,和您接触很是亲切。
这是实验版块的最后一个报告,写完报告已是晚上八点,我从下午五点开始写,因为之前用将近三周的时间做完了实验的全部,只剩下最后的整理工作,所以时间不长。写完我就去吃饭了,此刻的食堂已是空无一人,很安静,微微亮起的几盏灯,指着出口。一人独坐,心中感到了巨大的落空感,这样的感受早已熟悉,每完成一次考试或实验就会有这样的感觉。但当它来临的一刻还是忍不住的波澜。我知道那是长久专注于一个目标的原因,当它完成的一刻,目标消失,一时不知何去何从。
我从来没有过用这样近乎疯狂的方式对待一门课程,课前的预习,课上笔不停,课后看PPT,说这些不是在表达我有多努力,这些是一个学生的本分,只是说这是我的又一次成长和突破,我体会到了成为一名合格学生的快乐,那是珠峰山顶的朝阳,一抹金黄,逐渐弥漫整个山谷,洒在我的身上,很是惬意,一抹清凉,还有些许自由。
我以此篇献给您,和您学习很是快乐,也是写给我自己,带着这美妙的经历继续向前。
此致,敬礼!