DOS程序集读取两个后续字符,并转换为数字

时间:2009-10-29 00:33:39

标签: assembly dos

我正在编写一个简单的程序,它在1-99之间输入两个数字,添加它们并打印出结果。我已经完成了打印部分,我可以打印三个数字,99 + 99 = 198所以这对于这个程序来说已经足够了。我有两个一位数的程序。

实施例: 1 1 = 2, 4 4 = 8

所以数字用空格分隔。现在我需要以下内容; 11 1 = 12, 1 45 = 46

到目前为止我得到的是,当我第一次读取有效数字时,我将它存储在堆栈上,而我检查下一个字符是什么,如果下一个是空格,那么这个数字只有一位数。如果我有另一个角色,我必须将第一个乘以10,然后添加最新的角色。

22将如下所示:2 2 * 10 = 20 + 2 = 22

请注意,我程序的其余部分需要将此结果存入寄存器dl。 有一个关于寄存器和汇编的小问题,存储在dl中的数字可以用dx引用吗?我想知道因为mov和算术运算符似乎要求寄存器(操作数)具有相同的大小。

到目前为止我的代码

ReadNumber: ;; Reads one number 1-99
push ax
push bx
push cx
Lokke:
;; reads from keyboard
mov ah,01h
int 21h
cmp al, " "
je Lokke
cmp al,"0"
jb PrintError
cmp al,"9"
ja PrintError
;; First character is a valid number
push ax
;;storing the first on the stack while checking the next character
mov ah,01h
int 21h
cmp al," " 
je OneNumber
;;This part runs if the next char is a valid digit.
mov cl, al ;cl next digit
pop ax ; getting back the first from the stack
sub ax,"0" THIS LINE IS ADDED THANKS!!!!
mov bl, 10 
mul bl 
add ax, cx
mov dx,ax
mov dh,0 ;success variable set to true
mov dl,al
sub dl,"0"
pop ax
pop bx
pop cx
ret
OneNumber: 
pop ax ;; Don't need it.
mov dh,0 ;success variable set too true
mov dl,al
sub dl,"0"
pop ax
pop bx
pop cx
ret

这不能正常工作,即使是一位数的数字,我也无法理解为什么:( 看起来很好!感谢输入:)

1 个答案:

答案 0 :(得分:3)

一个明显的错误(可能还有其他错误),就是你要存储数字的ASCII值,但是你将它乘以它是一个整数。

换句话说,临时存储在堆栈中的第一个数字的值在48到57(十进制)之间,分别为“0”到“9”。

我正在检查其他问题......

修改:第二遍......
我继续提供来自你的代码的进化版本,更改了一些我发现错误/缺失的内容,但也为处理超过2位数字奠定了基础。 主要变化是:

  • 为从输入
  • 读取的第二(及后续)字符添加了数字0-9的测试
  • 一旦数字有效性被断言,系统地从ASCII转换为整数值。 (通过保持一致,我们避免错误)
  • 使用堆栈顶部的单词来保存累积值(这种做法有点时髦,因为它会让你确保弹出它,无论何时你可以分支/退出。更多关于这一点
  • 确保寄存器的大部分被清零(这可能导致了一些错误)
  • 我们现在只有一个退出点(对于正常情况,即不计算“PrintError”

注意:此代码未经测试,实际上甚至没有编译(此处/现在没有MASM ...)

    ;; ReadNumber
    ;;    Reads a number from the input and returns its value in dx register
    ;;    For now 0-99 values only
    ;;      dh contains 0 = success code
    ;;      dl contains the value
    ;;    (this API should change so that bigger # can be returned)
    ReadNumber: 
    push ax
    push bx
    push cx
    Lokke:
    ;; First digit is handled separately, as to to allow for preceding spaces
    mov ah,01h
    int 21h
    cmp al, " "
    je Lokke   ;; skip spaces till first digit
    cmp al,"0"
    jb PrintError
    cmp al,"9"
    ja PrintError
    ;; First character is a valid number

    mov dh, 0
    mov dl, al
    sub dl, "0"
    push dx     ;; *** Cumulative value kept on top of stack ***

    MoreDigits:
    mov ah,01h
    int 21h
    pop cx   ;; in case of premature exit want the stack as expected...
    cmp al," "
    je DoneWithDigits
    cmp al,"0"
    jb PrintError
    cmp al,"9"
    ja PrintError
    mov dh, 0       ;; good: character is a digit
    mov dl, al
    sub dl, "0"     ;; down from ASCII
    mov ax, cx
    mov bl, 10
    mul bl
    add ax, dx    ;; fixed syntax error...
    push ax       ;; *** keep cumulative value on top of stack
    jmp DoneWithDigits  ;; For now only 2 digit max  (remove this 
                        ;; jmp to try with more)
    ;; @@@ here to test for overflow / too many char input
    jmp MoreDigits

    ;; Almost done
    DoneWithDigits: 
    pop dx 
    mov dh,0 ;success variable set too true   
    pop ax
    pop bx
    pop cx
    ret

现在,还有一些一般性考虑因素

  • 注意到您没有使用任何内存变量(即您使用“MyLabel dw?”类型语法定义的内存位置)来创建“全局”变量),甚至本地变量(在帧指针的相对偏移处找到)。这可能只是为了简化装配编程等和/或(?)赋值的要求。不急于解决这些变量,但是当你这样做时,你会发现这些变量很有用。
  • 调用约定:ReadNumber()方法似乎负责保护ax,bx和cx寄存器。 (并在退出前重新建立这些)。这是一个奇怪的约定,通常方法的调用者将他自己的上下文推送到堆栈(然后将任何参数推送到函数,如果有的话)。无论如何,你会看到这些约定的实际应用,以及帧指针寄存器(BP)的使用方式等。也许请将此wikipedia article作为预览(BTW,具体取决于您使用的汇编程序,如果这是一个宏汇编程序,你可以得到很多这样的机制。)不要急于做这一切,先熟悉基础组装。
  • 代码的布局有点奇怪,使用程序集我们通常喜欢4列布局,第一列中有标签,漂亮可见,然后是说明,后跟操作数,最后一行评论。

希望这有帮助,
现在,玩得开心!