【汇编学习笔记】2:判断并输出各类字符数

以下”数字>…>”代表层次结构。

1>首先在数据段中存入三个字节长度的变量,初始值为0,分别用来计数找到的数字的个数、字母的个数、其它字符的个数。

1>进入代码段后,先指明段关联关系,然后根据END指明的程序入口执行程序。首先用AX寄存器过渡把段地址装入段寄存器,然后立即进入主循环。

2>>在主循环中,调用21H号中断的01H号用DOS输入并回显一个字符,将其ASCII码放在AL里。然后判断这个字符是不是回车(0DH),如果遇到输入了回车就直接跳转到程序的ENDR段。

3>>>在ENDR段中,每次CALL(给出子程序地址的调用方式)调用FUN_NEWLINE输出换行回车,然后调用数字/字母/其它字符对应的输出函数。

4>>>>建立这样的函数的目的是因为保存下来的计数值如果直接输出,将会输出其值对应的ASCII码字符,却不能按照十进制的方式显示。在每个这样的函数中,首先把其值给AX作为被除数,然后除以100(放入寄存器,这里用的BL),然后调用了一个FUN_OUTER函数。

5>>>>>在FUN_OUTER函数中,首先把这位值(本次商值,在AL里)加上字符’0’对应的ASCII码准备输出(因为输出时总是输出ASCII码),在输出时因为21H号中断总要用到AH寄存器指明做什么事,而我们现在的AH里又存了本次除法的余数值,要备份它,我这里备份给了寄存器DH,然后输出。输出后将余数(本来是AH里的,现在备份到了DH里)重新拼成16位数给AX作为下次除法的被除数。

4>>>>RET到FUN_ABC/NUM/OTR调用FUN_OUTER的位置,继续除以10,调用FUN_OUTER,除以1,调用FUN_OUTER…。

3>>>RET到ENDR代码块中,对于剩下的没输出的变量继续这样进行输出,最终程序将结束。

2>>对于输入值不是回车的情况,用CMP按照ASCII码表的顺序判断它是数字、字母还是其他字符,分别跳转到各自的段中去。

3>>>对于这三个段,会使用INC将变量值加1,然后JMP无条件跳转回主循环中,继续输入->判断->跳转。

DATAS SEGMENT
    HINT_NUM DB 00H ;存16进制数:数字的个数
    HINT_ABC DB 00H ;存16进制数:字母的个数
    HINT_OTR DB 00H ;存16进制数:其它的个数
DATAS ENDS

CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS
START:
    ;段地址装入段寄存器,用AX过渡
    MOV AX,DATAS
    MOV DS,AX

    ;主循环:输入一个字符一个字符输入
    XUN1:
        MOV AH,1
        INT 21H     ;调用DOS输入,输入后放在AL里

        CMP AL,0DH  ;判断是不是回车
        JE ENDR     ;如果是,跳转到ENDR

        CMP AL,30H  ;'0'
        JB OTHER    ;比'0'小属其它

        CMP AL,39H  ;'9'
        JBE NUMBER  ;'0'~'9'属数字

        CMP AL,41H  ;'A'
        JB OTHER

        CMP AL,5AH  ;'Z'
        JBE WORD1

        CMP AL,61H  ;'a'
        JB OTHER

        CMP AL,7AH  ;'z'
        JBE WORD1

        JMP OTHER   ;剩下的都算其它字符

    ;调试块(执行不经过)
    TIAOSHI:
        ;输出显示
        MOV DL,AL
        MOV AH,2
        INT 21H

        ;HINT_NUM++
        MOV DL,HINT_NUM
        INC DL
        MOV HINT_NUM,DL

        JMP XUN1

    ;是数字
    NUMBER:
        INC HINT_NUM
        JMP XUN1

    ;是字母
    WORD1:
        INC HINT_ABC
        JMP XUN1

    ;是其它
    OTHER:
        INC HINT_OTR
        JMP XUN1

    ;终
    ENDR:

        ;输出换行回车
        CALL FUN_NEWLINE

        ;输出数字数目
        CALL FUN_NUM
        ;输出换行回车
        CALL FUN_NEWLINE


        ;输出字母数目
        CALL FUN_ABC
        ;输出换行回车
        CALL FUN_NEWLINE


        ;输出其它数目
        CALL FUN_OTR
        ;输出换行回车
        CALL FUN_NEWLINE

        ;必须有,否则MASM FOR WIN不能正常结束
        MOV AX,4C00H
        INT 21H

    ;函数:NUM数转10进制变ASCII码输出
    FUN_NUM PROC NEAR
        ;拼成16位给AX作为被除数
        MOV AH,00H
        MOV AL,HINT_NUM
        ;以下每次DIV(无符号除法)后,余数在AH,商在AL
        MOV BL,100  ;除数不妨给BL
        DIV BL
        CALL FUN_OUTER  ;输出这次商,并把余数当成被除数(即拼成16位给AX)
        MOV BL,10   ;除数不妨给BL
        DIV BL
        CALL FUN_OUTER  ;输出这次商,并把余数当成被除数(即拼成16位给AX)
        MOV BL,1    ;除数不妨给BL
        DIV BL
        CALL FUN_OUTER  ;输出这次商,并把余数当成被除数(即拼成16位给AX)
        RET ;返回调用者
    FUN_NUM ENDP

    ;函数:ABC数转10进制变ASCII码输出
    FUN_ABC PROC NEAR
        ;拼成16位给AX作为被除数
        MOV AH,00H
        MOV AL,HINT_ABC
        ;以下每次DIV(无符号除法)后,余数在AH,商在AL
        MOV BL,100  ;除数不妨给BL
        DIV BL
        CALL FUN_OUTER  ;输出这次商,并把余数当成被除数(即拼成16位给AX)
        MOV BL,10   ;除数不妨给BL
        DIV BL
        CALL FUN_OUTER  ;输出这次商,并把余数当成被除数(即拼成16位给AX)
        MOV BL,1    ;除数不妨给BL
        DIV BL
        CALL FUN_OUTER  ;输出这次商,并把余数当成被除数(即拼成16位给AX)
        RET ;返回调用者
    FUN_ABC ENDP    

    ;函数:OTR数转10进制变ASCII码输出
    FUN_OTR PROC NEAR
        ;拼成16位给AX作为被除数
        MOV AH,00H
        MOV AL,HINT_OTR
        ;以下每次DIV(无符号除法)后,余数在AH,商在AL
        MOV BL,100  ;除数不妨给BL
        DIV BL
        CALL FUN_OUTER  ;输出这次商,并把余数当成被除数(即拼成16位给AX)
        MOV BL,10   ;除数不妨给BL
        DIV BL
        CALL FUN_OUTER  ;输出这次商,并把余数当成被除数(即拼成16位给AX)
        MOV BL,1    ;除数不妨给BL
        DIV BL
        CALL FUN_OUTER  ;输出这次商,并把余数当成被除数(即拼成16位给AX)
        RET ;返回调用者
    FUN_OTR ENDP

    ;函数:输出换行
    FUN_NEWLINE PROC NEAR
        ;输出换行
        MOV DL,0AH
        MOV AH,2
        INT 21H
        ;输出回车
        MOV DL,0DH
        MOV AH,2
        INT 21H
        RET ;返回调用者
    FUN_NEWLINE ENDP

    ;函数:输出本位,并把余数当成被除数(即拼成16位给AX)
    FUN_OUTER PROC NEAR
        ADD AL,30H  ;商值AL变ASCII
        MOV DL,AL
        ;关键!因为输出时要用AH,而它又存了余数
        MOV DH,AH   ;因此,这里用DH暂存其值
        MOV AH,2
        INT 21H
        ;余数AH(现在值在DH里)拼成16位给AX作被除数
        MOV AL,DH
        MOV AH,00H
        RET ;返回调用者
    FUN_OUTER ENDP

CODES ENDS  ;代码段结束
    END START   ;指明程序入口

这里写图片描述

此外,如果要去掉每个输出值前面的0,可以指定一个变量作为标志,在三次输出中分别先设置标志是0,从开始判断这个商是不是0以及标志是不是0,如果两个条件都满足就直接RET不做输出,并保持这个标志是0,一旦出现商不是0的情况,就把标志设置为1,这样在以后的判断中就能保证此后的值都是有效的,要输出的。并且因为有两个判断条件,所以即便是60这样的0也会正确输出。

下面是具有去掉0功能的代码。

DATAS SEGMENT
    HINT_NUM DB 00H ;存16进制数:数字的个数
    HINT_ABC DB 00H ;存16进制数:字母的个数
    HINT_OTR DB 00H ;存16进制数:其它的个数
    FLAG DB 00H     ;标志位:判断是否要输出
DATAS ENDS

CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS
START:
    ;段地址装入段寄存器,用AX过渡
    MOV AX,DATAS
    MOV DS,AX

    ;主循环:输入一个字符一个字符输入
    XUN1:
        MOV AH,1
        INT 21H     ;调用DOS输入,输入后放在AL里

        CMP AL,0DH  ;判断是不是回车
        JE ENDR     ;如果是,跳转到ENDR

        CMP AL,30H  ;'0'
        JB OTHER    ;比'0'小属其它

        CMP AL,39H  ;'9'
        JBE NUMBER  ;'0'~'9'属数字

        CMP AL,41H  ;'A'
        JB OTHER

        CMP AL,5AH  ;'Z'
        JBE WORD1

        CMP AL,61H  ;'a'
        JB OTHER

        CMP AL,7AH  ;'z'
        JBE WORD1

        JMP OTHER   ;剩下的都算其它字符

    ;调试块(执行不经过)
    TIAOSHI:
        ;输出显示
        MOV DL,AL
        MOV AH,2
        INT 21H

        ;HINT_NUM++
        MOV DL,HINT_NUM
        INC DL
        MOV HINT_NUM,DL

        JMP XUN1

    ;是数字
    NUMBER:
        INC HINT_NUM
        JMP XUN1

    ;是字母
    WORD1:
        INC HINT_ABC
        JMP XUN1

    ;是其它
    OTHER:
        INC HINT_OTR
        JMP XUN1

    ;终
    ENDR:

        ;输出换行回车
        CALL FUN_NEWLINE

        ;输出数字数目
        CALL FUN_NUM
        ;输出换行回车
        CALL FUN_NEWLINE


        ;输出字母数目
        CALL FUN_ABC
        ;输出换行回车
        CALL FUN_NEWLINE


        ;输出其它数目
        CALL FUN_OTR
        ;输出换行回车
        CALL FUN_NEWLINE

        ;必须有,否则MASM FOR WIN不能正常结束
        MOV AX,4C00H
        INT 21H

    ;函数:NUM数转10进制变ASCII码输出
    FUN_NUM PROC NEAR
        ;标志位清0
        MOV FLAG,0
        ;拼成16位给AX作为被除数
        MOV AH,00H
        MOV AL,HINT_NUM
        ;以下每次DIV(无符号除法)后,余数在AH,商在AL
        MOV BL,100  ;除数不妨给BL
        DIV BL
        CALL FUN_OUTER  ;输出这次商,并把余数当成被除数(即拼成16位给AX)
        MOV BL,10   ;除数不妨给BL
        DIV BL
        CALL FUN_OUTER  ;输出这次商,并把余数当成被除数(即拼成16位给AX)
        MOV BL,1    ;除数不妨给BL
        DIV BL
        CALL FUN_OUTER  ;输出这次商,并把余数当成被除数(即拼成16位给AX)
        RET ;返回调用者
    FUN_NUM ENDP

    ;函数:ABC数转10进制变ASCII码输出
    FUN_ABC PROC NEAR
        ;标志位清0
        MOV FLAG,0
        ;拼成16位给AX作为被除数
        MOV AH,00H
        MOV AL,HINT_ABC
        ;以下每次DIV(无符号除法)后,余数在AH,商在AL
        MOV BL,100  ;除数不妨给BL
        DIV BL
        CALL FUN_OUTER  ;输出这次商,并把余数当成被除数(即拼成16位给AX)
        MOV BL,10   ;除数不妨给BL
        DIV BL
        CALL FUN_OUTER  ;输出这次商,并把余数当成被除数(即拼成16位给AX)
        MOV BL,1    ;除数不妨给BL
        DIV BL
        CALL FUN_OUTER  ;输出这次商,并把余数当成被除数(即拼成16位给AX)
        RET ;返回调用者
    FUN_ABC ENDP    

    ;函数:OTR数转10进制变ASCII码输出
    FUN_OTR PROC NEAR
        ;标志位清0
        MOV FLAG,0
        ;拼成16位给AX作为被除数
        MOV AH,00H
        MOV AL,HINT_OTR
        ;以下每次DIV(无符号除法)后,余数在AH,商在AL
        MOV BL,100  ;除数不妨给BL
        DIV BL
        CALL FUN_OUTER  ;输出这次商,并把余数当成被除数(即拼成16位给AX)
        MOV BL,10   ;除数不妨给BL
        DIV BL
        CALL FUN_OUTER  ;输出这次商,并把余数当成被除数(即拼成16位给AX)
        MOV BL,1    ;除数不妨给BL
        DIV BL
        CALL FUN_OUTER  ;输出这次商,并把余数当成被除数(即拼成16位给AX)
        RET ;返回调用者
    FUN_OTR ENDP

    ;函数:输出换行
    FUN_NEWLINE PROC NEAR
        ;输出换行
        MOV DL,0AH
        MOV AH,2
        INT 21H
        ;输出回车
        MOV DL,0DH
        MOV AH,2
        INT 21H
        RET ;返回调用者
    FUN_NEWLINE ENDP

    ;函数:输出本位,并把余数当成被除数(即拼成16位给AX)
    FUN_OUTER PROC NEAR
        CMP FLAG,0  ;判断FLAG是不是0
        JNE NOZERO  ;不是0才跳转到NOZERO
        CMP AL,0    ;判断AL是否是0
        JNE SET1    ;如果不是0,跳入SET1置1并进入NOZERO
        ;如果两个条件都是0,只要拼好然后返回
        MOV AL,AH
        MOV AH,00H
        RET
    SET1:
        MOV FLAG,1  ;FLAG置1
    NOZERO:         ;不是0的话必然要输出了
        ADD AL,30H  ;商值AL变ASCII
        MOV DL,AL
        ;关键!因为输出时要用AH,而它又存了余数
        MOV DH,AH   ;因此,这里用DH暂存其值
        MOV AH,2
        INT 21H
        ;余数AH(现在值在DH里)拼成16位给AX作被除数
        MOV AL,DH
        MOV AH,00H
        RET ;返回调用者
    FUN_OUTER ENDP

CODES ENDS  ;代码段结束
    END START   ;指明程序入口

这里写图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值