汇编语言课后实验练习

  1. 编程统计DATA1单元开始存放的20个字符串中英文大写字母个数、小写字母个数,数字0~9的个数,分别放在NA,NB和N1中,并分行以十六进制显示在屏幕上。
  2. 编写一个程序,将长度30个的字符串STRING中所有的大写字母转换为小写字母,而保持其他字母不变,然后放回原存储区。
    题目要求:使用mov ah,10h int 21不使用1和2.
    使用masm for Windows 集成实验环境完成

1.

CRLF macro

MOV DL,0DH

MOV AH,02H

INT 21H

MOV DL,0AH

MOV AH,02H

INT 21H

ENDM

DATAS SEGMENT

dat1 db 'ksbcasubcoubciasu*'

na db ?

nb db ?

n1 db ?                     

DATAS ENDS

。。。。。。

mov si,offset dat1    

mov cx,20                   

LOP:

MOV AL,[SI]

CMP AL,'A'

JB NEXT

CMP AL,'Z'

JA NEXT

INC NA

JMP NEXT2

NEXT:

CMP AL,'a'

JB NEXT1

CMP AL,'z'

JA NEXT1

INC NB

JMP NEXT2

NEXT1:

CMP AL,'0'

JB NEXT2

CMP AL,'9'

JA NEXT2

INC N1

JMP NEXT2  

NEXT2:

INC SI

LOOP LOP

MOV BL,NA

CALL DISPP

CRLF

MOV BL,NB

CALL DISPP

CRLF

MOV BL,N1

CALL DISPP

MOV AH,4CH

INT 21H 

DISPP PROC

MOV DL,BL

MOV CL,04

ROL DL,CL

AND DL,0FH

ADD DL,30H

CMP DL,3AH

JB BBB

ADD DL,07H

BBB:

MOV AH,02H

INT 21H

MOV DL,BL

AND DL,0FH

ADD DL,30H

CMP DL,3AH

JB BBB1

ADD DL,07H

BBB1:

MOV AH,02H

INT 21H

RET

DISPP ENDP

。。。。。。

2.

DATAS SEGMENT

string db 'AUHvxiagAJBDiscuaAJISGADKTfHVa' 

DATAS ENDS

。。。。。。

CODES SEGMENT

ASSUME CS:CODES,DS:DATAS,SS:STACKS

START:

MOV AX,DATAS

MOV DS,AX

mov si,offset string

mov cl,30

lop:

mov al,[si]

cmp al,'A'

jb next

cmp al,'Z'

ja next

add al,20h

mov [si],al

next:

inc si

loop lop



MOV AH,4CH

INT 21H

。。。。。。

下面是使用masm for Windows集成实验环境编写的代码:


.model small
.stack 100h

.data
DATA1 DB "ABCDefgHi1234JKlmnoPqRS56789tuvWxYZ", 0
NA DB 20 dup(0)
NB DB 20 dup(0)
N1 DB 20 dup(0)
STRING DB 30 dup(0)

.code
main PROC
    ; 统计大写字母、小写字母和数字个数
    mov bx, offset DATA1
    mov cx, 20
    mov si, offset NA
    mov di, offset NB
    mov bp, offset N1
    call CountChar
    
    ; 打印统计结果
    mov ah, 9
    lea dx, NA
    int 21h
    lea dx, NB
    int 21h
    lea dx, N1
    int 21h
    
    ; 将字符串中的大写字母转换为小写字母
    mov bx, offset STRING
    mov cx, 30
    call ConvertUpperToLower
    
    ; 打印转换后的字符串
    mov ah, 9
    lea dx, STRING
    int 21h
    
    mov ah, 4ch
    int 21h
main ENDP

; 统计字符个数
CountChar PROC
    push bx
    push cx
    push dx
    
    xor ax, ax
    xor bx, bx
    xor cx, cx
    xor dx, dx
    
    ; 统计大写字母、小写字母和数字个数
    CountLoop:
        mov al, [bx]
        cmp al, 0
        je CountEnd
        cmp al, 'A'
        jb NextChar
        cmp al, 'Z'
        ja NextChar
        inc cx ; 大写字母个数加1
        jmp NextChar
        NextChar:
        cmp al, 'a'
        jb NextChar2
        cmp al, 'z'
        ja NextChar2
        inc dx ; 小写字母个数加1
        jmp NextChar2
        NextChar2:
        cmp al, '0'
        jb NextChar3
        cmp al, '9'
        ja NextChar3
        inc bx ; 数字个数加1
        jmp NextChar3
        NextChar3:
        inc bx ; 跳过其他字符
        jmp CountLoop
    CountEnd:
    
    ; 将结果转换为十六进制,并存储到NA、NB和N1中
    call WordToHex
    mov si, offset HexResult
    mov di, offset NA
    mov cx, 2
    rep movsb
    call WordToHex
    mov si, offset HexResult
    mov di, offset NB
    mov cx, 2
    rep movsb
    call WordToHex
    mov si, offset HexResult
    mov di, offset N1
    mov cx, 2
    rep movsb
    
    pop dx
    pop cx
    pop bx
    ret
CountChar ENDP

; 将字符串中的大写字母转换为小写字母
ConvertUpperToLower PROC
    push bx
    push cx
    push dx
    
    ; 将大写字母转换为小写字
  ConvertLoop:
  mov al, [bx]
  cmp al, 0
  je ConvertEnd
  cmp al, 'A'
  jb NextChar
  cmp al, 'Z'
  ja NextChar
  add al, 32 ; 大写字母转换为小写字母
  mov [bx], al
  NextChar:
  inc bx ; 处理下一个字符
  jmp ConvertLoop
  ConvertEnd:  

pop dx
pop cx
pop bx
ret
ConvertUpperToLower ENDP

; 将16位无符号整数转换为4位十六进制字符串
WordToHex PROC
push ax
push bx
push cx
push dx

; 将十六进制字符表存储到HexTable中
mov bx, offset HexTable
mov cx, 16
HexLoop:
    mov dl, cl
    and dl, 0fh
    cmp dl, 10
    jb NotLetter
    add dl, 7 ; 转换为大写字母
    NotLetter:
    mov [bx], dl
    add bx, 1
    loop HexLoop

; 将16位无符号整数转换为4位十六进制字符串
mov ax, bx ; 将bx的值复制到ax中
mov bx, offset HexResult
mov cx, 4
HexConvertLoop:
    mov dx, 0
    mov si, 1000h
    HexDivLoop:
        cmp ax, si
        jb HexDivEnd
        sub ax, si
        add dx, 1
        jmp HexDivLoop
    HexDivEnd:
    mov al, dl
    mov dl, [HexTable+ax]
    mov [bx], dl
    add bx, 1
    dec cx
    cmp cx, 0
    jne HexConvertLoop

pop dx
pop cx
pop bx
pop ax
ret

WordToHex ENDP

; 数据区
HexTable DB '0123456789ABCDEF'
HexResult DB 4 dup(0)

END main

在这个程序中,使用了三个过程:

  • CountChar:统计DATA1字符串中的大写字母、小写字母和数字个数,并将统计结果以十六进制格式存储到NA、NB和N1中。
  • ConvertUpperToLower:将长度30个的字符串STRING中的大写字母转换为小写字母,并保持其他字母不变。
  • WordToHex:将16位无符号整数转换为4位十六进制字符串。

由于题目要求不使用int 21h功能号1和2,所以在打印字符串时使用了int 21h功能号9。此外,为了将十六进制结果存储到NA、NB和N1中,还需要使用WordToHex过程将结果转换为十六进制字符串。

引用chatGPT作答,
1.以下是汇编语言程序,可以实现您的要求:

ORG 0
MOV AX, DATA
MOV DS, AX  ; 将DS寄存器设置为DATA段的基地址

MOV SI, OFFSET DATA1  ; 将SI寄存器设置为DATA1的偏移地址
MOV CX, 20  ; 循环20次,处理20个字符串

MOV AX, 0  ; 初始化NA、NB、N1为0
MOV BX, 0
MOV DX, 0

LOOP_START:
MOV AH, [SI]  ; 读取当前字符串的第一个字符
CMP AH, 0  ; 判断字符串是否结束
JE LOOP_END  ; 如果结束,跳出循环

CMP AH, 'A'  ; 判断字符是否为大写字母
JB NOT_UPPER_CASE
CMP AH, 'Z'
JA NOT_UPPER_CASE
INC AX  ; 如果是大写字母,NA加1
JMP CONTINUE_LOOP

NOT_UPPER_CASE:
CMP AH, 'a'  ; 判断字符是否为小写字母
JB NOT_LOWER_CASE
CMP AH, 'z'
JA NOT_LOWER_CASE
INC BX  ; 如果是小写字母,NB加1
JMP CONTINUE_LOOP

NOT_LOWER_CASE:
CMP AH, '0'  ; 判断字符是否为数字
JB CONTINUE_LOOP
CMP AH, '9'
JA CONTINUE_LOOP
INC DX  ; 如果是数字,N1加1

CONTINUE_LOOP:
INC SI  ; 指向下一个字符
JMP LOOP_START

LOOP_END:
; 将NA、NB、N1转换成16进制并输出到屏幕上
MOV AH, 2  ; 选择2号功能,用于显示字符
MOV DL, 'A'  ; 输出'A'
ADD AX, 55H  ; 将NA转换成16进制,并加上偏移量
CMP AX, 7FH  ; 判断是否为大写字母
JBE PRINT_HEX_DIGIT
ADD DL, 20H  ; 如果不是大写字母,输出数字
JMP PRINT_BYTE

PRINT_HEX_DIGIT:
MOV DL, AH  ; 将高4位转换成16进制并输出
AND DL, 0FH
CMP DL, 0AH
JBE PRINT_BYTE
ADD DL, 7  ; 输出A~F

PRINT_BYTE:
INT 21H  ; 调用DOS系统中断,显示字符

MOV DL, ' '
INT 21H  ; 输出一个空格

MOV AH, 2  ; 继续输出16进制数字
MOV DL, 'A'  ; 输出'A'
ADD BX, 55H  ; 将NB转换成16进制,并加上偏移量
CMP BX, 7FH  ; 判断是否为大写字母
JBE PRINT_HEX_DIGIT
ADD DL, 20H  ; 如果不是大写字母,输出数字
JMP PRINT_BYTE

PRINT_HEX_DIGIT:
MOV DL, BH  ; 将高4位转换成16进制并输出
AND DL, 0FH
CMP DL, 0AH
JBE PRINT_BYTE
ADD DL, 7  ; 输出A~F

PRINT_BYTE:
INT 21H  ; 调用DOS系统中断,显示字符

MOV DL, ' ' ; 输出一个空格
INT 21H

MOV AH, 4CH ; 选择4CH功能,程序结束
INT 21H

; 数据段定义
DATA SEGMENT
NA DB 0
NB DB 0
N1 DB 0
DATA1 DB 'AbCdEfGhIjKlMnOpQrStUvWxYz0123456789', '$'
DATA ENDS

END ; 程序结束符号

上述程序中,通过循环处理20个字符串,分别统计每个字符串中大写字母、小写字母和数字的个数,最后将结果转换成16进制并输出到屏幕上。程序中使用了以下指令和概念:

  • MOV 指令:用于将数据从一个寄存器或内存单元传送到另一个寄存器或内存单元中。
  • CMP 指令:用于比较两个操作数的大小,并根据比较结果设置标志位。
  • INC 指令:用于将指定操作数加1。
  • JBJAJBEJAE 等条件跳转指令:根据标志位的值来决定是否跳转到指定的目标地址。
  • OFFSET 运算符:用于获取某个变量在数据段中的偏移地址。
  • 16进制转换:将10进制数转换成16进制数,可以将其除以16并取余数,得到低4位的值,再将商继续除以16,得到高4位的值。将高4位和低4位转换成16进制字符即可。

2.以下是使用MASM for Windows集成实验环境完成题目要求的汇编程序:

.MODEL SMALL
.STACK 100H

.DATA
    STRING DB 'AaBbCcDdEeFfGgHhIiJjKkLlMmNn', '$'
    LENGTH DB 30

.CODE
MAIN PROC
    MOV AX, @DATA  ; 初始化数据段寄存器
    MOV DS, AX

    ; 循环处理字符串中的每个字符
    MOV CX, LENGTH  ; 循环计数器,初始值为字符串长度
    MOV SI, 0  ; SI寄存器指向字符串的第一个字符
LOOP_BEGIN:
    MOV AL, [SI]  ; 读取一个字符
    CMP AL, 'A'  ; 判断是否为大写字母
    JB SKIP  ; 如果不是大写字母,跳过转换
    CMP AL, 'Z'
    JA SKIP
    ADD AL, 20H  ; 转换成小写字母

SKIP:
    MOV [SI], AL  ; 将处理后的字符存回字符串
    INC SI  ; 指向下一个字符
    LOOP LOOP_BEGIN  ; 继续处理下一个字符

    ; 输出转换后的字符串
    MOV AH, 9  ; 选择9号功能,用于输出字符串
    MOV DX, OFFSET STRING  ; 字符串存储的偏移地址
    INT 21H  ; 调用DOS系统中断

    ; 程序结束
    MOV AH, 4CH
    INT 21H
MAIN ENDP

END MAIN

在程序中,我们使用了以下指令和概念:

MOV 指令:用于将数据从一个寄存器或内存单元传送到另一个寄存器或内存单元中。
CMP 指令:用于比较两个操作数的大小,并根据比较结果设置标志位。
ADD 指令:用于将指定操作数加上一个值。
INC 指令:用于将指定操作数加1。
LOOP 指令:用于根据循环计数器的值来判断是否继续执行循环。
INT 21H:DOS系统中断,可以用于输出字符串、读取键盘输入等操作。
在处理字符串时,我们使用循环遍历每个字符,并通过比较ASCII码值来判断是否为大写字母。如果是大写字母,将其转换成小写字母(通过将其ASCII码值加上20H),并将处理后的字符存回字符串。最后,使用DOS系统中断将转换后的字符串输出到屏幕上。

  1. 假设 DATA1 是存储这 20 个字符串的内存块名称,下面是一个示例代码:
MOV SI, OFFSET DATA1 ; 指向数据块开头
MOV DI, SI ; 复制指针到结果的目标位置

; 初始化计数器为零
MOV NA, 0 ; 大写字母个数
MOV NB, 0 ; 小写字母个数
MOV N1, 0 ; 数字 0~9 的个数

; 循环遍历所有 20 个字符串
FOR_LOOP:
  MOV CX, 20 ; 每个字符串有 20 个字符
  LOOP_START:
    LODSB ; 从 AL 中加载下一个字符
    CMP AL, 'A' ; 检查是否为大写字母
    JB CHECK_LOWER ; 如果不是则跳过
    CMP AL, 'Z'
    JA CHECK_LOWER ; 如果不是则跳过
    INC NA ; 增加大写字母计数
    JMP NEXT_CHAR
    CHECK_LOWER:
    CMP AL, 'a' ; 检查是否为小写字母
    JB CHECK_DIGIT ; 如果不是则跳过
    CMP AL, 'z'
    JA CHECK_DIGIT ; 如果不是则跳过
    INC NB ; 增加小写字母计数
    JMP NEXT_CHAR
    CHECK_DIGIT:
    CMP AL, '0' ; 检查是否为数字
    JB NEXT_CHAR ; 如果不是则跳过
    CMP AL, '9'
    JA NEXT_CHAR ; 如果不是则跳过
    INC N1 ; 增加数字计数
    NEXT_CHAR:
    LOOP LOOP_START
  ADD DI, 5 ; 跳到下一个计数器组
  CMP DI, OFFSET NA+15 ; 检查是否到达计数器的末尾
  JB FOR_LOOP ; 如果没有则继续循环
  1. 假设字符串的内存块名称为 STRING,下面是一个示例代码:
MOV SI, OFFSET STRING ; 指向字符串开头
MOV CX, 30 ; 字符串长度

FOR_LOOP:
  LODSB ; 从 AL 中加载下一个字符
  CMP AL, 'A' ; 检查是否为大写字母
  JB SKIP_CONVERT ; 如果不是则跳过
  CMP AL, 'Z'
  JA SKIP_CONVERT ; 如果不是则跳过
  ADD AL, 32 ; 转换为小写字母
  SKIP_CONVERT:
  STOSB ; 将转换或未转换的字符存回
  LOOP FOR_LOOP
  1. 不使用 int 21 的函数 1 和 2,我们仍然可以使用 int 16 和 int 6 从控制台获取和输出数据。下面是一个示例代码:
; 首先,打印提示用户输入字符串的消息
MOV DX, OFFSET PROMPT ; PROMPT 是以 null 结尾的字符串
MOV AH, 09h ; 用于打印字符串的服务
INT 21h

; 其次,从用户获取输入
MOV DX, OFFSET BUFFER ; BUFFER 是一个 128 字节的字符数组
MOV AH, 0Ah ; 用于读取带缓存区的字符串的服务
INT 21h

; 第三,将字符串输出到屏幕上
MOV DX, OFFSET BUFFER+2 ; 缓冲区的前两个字节表示字符串的长度
ADD DX, 2 ; 跳过长度字节
MOV AH, 09h ; 用于打印字符串的服务
INT 21h
  1. 使用 MASM for Windows 集成开发环境,我们可以轻松地编写和调试汇编代码。下面是创建新控制台应用程序的步骤:
  2. 打开 Visual Studio,然后转到“文件 > 新建 > 项目...”(或者按 Ctrl + Shift + N)。
  3. 选择“Visual C++ > Win32”,然后选取“Win32 控制台应用程序”。
  4. 命名您的项目,然后单击“创建”。
  5. 在下一个屏幕中,选取“控制台应用程序”,并保留默认设置。
  6. 单击“完成”以创建项目。
  7. 在“解决方案资源管理器”中,右键单击源文件(通常命名为“source.cpp”),然后选择“重命名”。将文件扩展名从“.cpp”更改为“.asm”。
  8. 双击新命名的文件以在编辑器中打开它。
  9. 开始编写汇编代码,使用编辑器的语法高亮和 IntelliSense 功能来辅助编写。
  10. 要汇编和连接程序,请转到“生成 > 生成解决方案”(或者按 Ctrl + Shift + B)。
  11. 如果有任何错误或警告,输出窗口将显示它们。修复它们,然后尝试再次生成。
  12. 要运行程序,请转到“调试 > 无调试启动”(或者按 Ctrl + F5)。控制台窗口将打开,程序将运行。
  13. 要调试程序,请在代码中设置断点,单击左侧空白区域(通常指行号左侧的灰色区域)即可设置断点。然后转到“调试 > 启动调试”(或者按 F5)。调试器将在第一个断点处暂停,允许您检查变量并逐步调试代码。