繁体   English   中英

汇编 x8086 获取字符直到“z”或“Z”并打印小字符、大字符、数字

[英]Assembly x8086 getting chars till 'z' or 'Z' and print small chars,big chars,numbers

我有问题:

  1. 从用户获取输入的程序,直到输入 'z' 或 'Z' 程序将检查字符,并打印(换行)小字符
    (新行)大字符
    (新行)数字
    [没有'z'或'Z']
    不能使用变量。
    只有堆栈。
    示例:输入:ASdf154sdgdf123vcvbz 小字符:dfsdgdfvcvb 大字符:AS 数字:154123

  2. 字符串大小的程序 定义N,程序将接受用户的输入,并且只从输入中取数字并将它们放入大小为N的字符串中,输入大小为N。并打印带有字符串的消息(必须只有来自输入的数字)输入)和数字的数量。
    示例(字符串大小 10)
    输入:1adr1t23g7
    字符串:11237
    打印:
    数字字符串是:11237 和 Tolat 数字是:5

卡在问题1,不明白主题,不能继续问题2。感谢每一位可能帮助我的人

这是问题 1 的代码:

STA SEGMENT STACK
    DB 100H DUP (0)
STA ENDS
CODE SEGMENT
    ASSUME CS:CODE,SS:STA
MAIN:
    MOV BP, SP
    MOV BX, BP
    SUB BP, 2
    MOV CX, 0
INPUT:
    MOV AH, 01H
    INT 21H
    INC CX
    CMP AL, 'z'
    JE TOPRINT
    CMP AL, 'Z'
    JE TOPRINT
    MOV AH, 0
    PUSH AX
    MOV AX, 0
    JNE INPUT
    MOV DI, CX
TOPRINT:
    POP DX
    CMP DX, 'a'
    JL NEXT
    CMP DX, 'z'
    JG NEXT
    MOV AH, 02H
    INT 21H
    CMP DX, 'A'
    JL NEXT
    CMP DX, 'Z'
    JG NEXT
    MOV AH, 02H
    INT 21H
    CMP DX, '0'
    JL NEXT
    CMP DX, '9'
    JG NEXT
    MOV AH, 02H
    INT 21H
NEXT:
    SUB BP, 2
    DEC CX
    CMP CX, 0
    JMP TOPRINT
    MOV AX, 4C00H
    INT 21H
CODE ENDS
    END MAIN

好吧,似乎该任务旨在练习堆栈使用,以及您的评论:

看不懂题目

似乎是准确的。 但是然后你要求人们把书的短章节写成简单的 SO 答案......嗯,通常我不喜欢这样做,因为整本书就是整本书,简短的回答将不得不省略一些细节,但让我们尝试如果减少的东西可以作为答案:

16b实模式下的栈内存是普通的电脑内存,但是寄存器对ss:sp指向“栈顶”,有几条指令隐式使用这两个寄存器来访问内存,比如pop dx “读字值”在内存地址ss:sp到寄存器dx ,然后将sp加 2(使其指向内存中的下一个字)”(字意为“16 位信息”,而不是“文本”字)。

记下 push/pop 指令描述(检查指令指南,无论是来自英特尔的官方文档还是像https://www.felixcloutier.com/x86/这样的基础知识都可以), push确实从sp中减去,即堆栈从高内存地址向低内存地址“增长”,当您popsp回到高内存地址。 “栈顶”是压入其中的最后一项,位于当前地址ss:sp 上一个推入堆栈的项目是在ss:sp+2 (在 16b 模式下)等...所以如果你想使用bp进行寻址,并且在最后一次push项目push入堆栈后将sp值复制到bp ,那么您的项目可以通过使用[bp+0], [bp+2], [bp+4], ...寻址来访问(注意: bp默认与ss段相关联,因此mov ax,[bp]是隐式mov ax,ss:[bp] (从堆栈段加载值),而mov ax,[bx]默认隐式为mov ax,ds:[bx] (从数据段加载)..除非你明确指定不同的段在源代码中覆盖)。

还要注意callret指令,这些也是隐式使用堆栈的,所以你是否会通过使用call / ret指令开始使用子程序,堆栈数据的结构在子程序内部时也会包含返回地址(在“顶部”进入子程序时堆栈”)。

在 emu8086 中的代码中,您通过在代码的开头定义堆栈段来为堆栈保留内存区域,保留 256 字节(128 个字),对于此类堆栈繁重的任务来说,这是非常小的堆栈,因为您的代码会吃以“每个输入字符一个单词”的速度堆栈,您最多可以输入 128 个字符......这似乎是合理的,直到您了解到实际的用户堆栈也被 DOS 中断使用,这有两个主要后果:

  • 这 128 个字中的一些被中断使用(不确定有多少,假设是 30 个字),如果您输入 100 个字符,中断将低于您保留的内存,开始覆盖您没有保留的部分内存它(“堆栈溢出”问题)
  • 当前ss:sp下面的内存被 DOS 中断处理程序定期覆盖

你的任务听起来像你可以做的:

  • 在循环中读取用户输入,直到输入 z/Z,将每个项目放入堆栈(并计数 = 你现在有类似的东西,一旦你修复只pop正确的次数),或者有空堆栈的“结束”指针)
  • 遍历所有输入值,只输出小字符
  • 输出换行符
  • 遍历所有输入值,只输出大写字符
  • 输出换行符
  • 遍历所有输入值,只输出数字
  • 输出换行符
  • 出口

现在,您可能很想在第一个“遍历所有输入的值”中执行pop ,但这意味着您会将ss:sp向上移向原始的“空堆栈”……如果然后减去 2*items从sp ,您可能认为您现在可以再次从内存中pop相同的字符,通过sp修改作弊。 但是,如果同时发生了某些中断,那么此时ss:sp下方的原始字符将被销毁,因此不要在前两个循环中pop

使用bp来访问数据,即mov bp,sp在每个输出循环之前,然后循环项目-多次执行mov dl,[bp] add bp,2 ,但保持ss:sp不变(并保持项目的副本某处的数量,所以你有第二个和第三个循环......或者在开始时复制“空” spmov di,sp这样的地方,做cmp bp,di来检查输出循环,如果你读过所有项目。

如果你对汇编编程的主题更不了解,并且你对我的大部分文字感到迷惑,请先阅读一些书籍或教程。关于寄存器/内存/等的基础知识通常可以从这个总结http://www. cs.virginia.edu/~evans/cs216/guides/x86.html目标是 32 位模式,但我不知道 16b 的这么简短的介绍(我猜你的讲师给了你一些建议,学习什么),或使用谷歌...请记住,16b 模式比 32b 模式更棘手和困难,因为您还必须了解内存段,并且内存寻址受到更多限制( mov al,[cx]在 16b 中不存在模式,而mov al,[ecx]在 32b 模式下是合法的)。

如果您对某个特定部分有问题,请在评论中提问。

然后查看您的代码,学习使用调试器(这是绝对必要的,使用 stackoverflow web 作为调试服务效率较低,并且被许多人(包括我)认为是粗鲁和不良行为......如果您能证明您进行了调试代码,您可以很好地描述令人费解的行为(正在发生什么以及您确实想要/期望什么),会有更多的人愿意为您写答案,为什么会发生这种情况以及您的思维过程是错误的),并且尝试使用上面的信息来重写它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM