tags:

views:

1066

answers:

2

I'm writing a simple program that takes in two numbers between 1-99, adds them and prints out the result. I'm done with the printing part, I can print up too three digits, 99+99=198 so it's enough for this program. I have the program working for two one digit numbers.

Example: 1 1 = 2 , 4 4 = 8

So the digits is separated by spaces. Now I need the following; 11 1 = 12, 1 45 = 46

what I got so far, when I first read a valid number i store it on the stack while I check what the next char is, if the next is space then this number is only one-digit. If I have another character I have to multiply the first by 10 and then add the latest character.

22 would be read like this: 2 2*10 = 20+2 = 22

Note that the rest of my program needs the result from this to be in register dl. Got one tiny question about registers and assembly, can a number stored in dl be referenced with dx? I'm wondering because mov and arithmetic operators seems to demand that the registers(operands) are of the same size.

My code so far

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

This does not work properly, not even for one-digit numbers, I can't understand why :( It looks just fine! Thanks for input :)

+1  A: 

One obvious mistake (there may be others), is that you you are storing the ASCII value of the digit, yet you are multiplying it as if it were an integer.

In other words, the value of the first digit, stored temporarily on the stack is between 48 and 57 (decimal), for respectively "0" through "9".

I'm checking for other issues...

Edit: Second pass...
I went ahead and provided an evolutionary version from your snippet, changing a few things which I found wrong/missing, but also laying the ground for handling more than 2 digits. The main changes are:

  • Added test for digit 0-9 for 2nd (and subsequent) characters read from input
  • Systematically converted to integer value from ASCII, as soon as digit validity is asserted. (by being consistent we avoid errors)
  • Used the word at top of stack to hold the cumulative value (this way of doing is a bit funky as it causes you to ensure to pop this out, whenever you may branch/exit. More on this late
  • ensured that the high part of the registers were zero-ed out (this may have been causing some of the bugs)
  • We now have only one exit point (for the normal case, i.e. not counting the "PrintError"

Note: this code is untested, indeed not even compiled (don't have MASM here/now...)

    ;; 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

And now, a few more general considerations

  • Noted that you do not use any in-memory variables (i.e. memory locations that you'd define with "MyLabel dw ?" type syntax, to create "global" variables), or even local variables (found at relative offset of the frame pointer). This is maybe just to ease into assembly programming etc. and/or a requirement of your (?) assignment. No rush to get into addressing such variables, but you'll find these handy when you do.
  • Calling convention: The ReadNumber() methods seems to be in charge of safeguarding the ax, bx and cx registers. (and to reestablish these before exiting). This is a bit of an odd convention, typically the caller to a method pushes his own context onto the stack (and then pushes any parameter to the function, if any). Anyway you'll see these conventions in action, along with the way the frame pointer register (BP) is used etc. Maybe check this wikipedia article as a preview (BTW, depending on the assembler you use in particular if this is a macro assembler, you can get much of this mechanics taken care of.) No rush to do all this, first get familiar with basics assembly.
  • the layout of the code is a bit strange, with assembly we typically like the 4 column layout with the labels in the first column, nice and visible, then the Instructions, followed by the operands, and last the line comments.

Hope this helps,
now, have fun!

mjv
Fixed the ASCII value, by sub "0". Just like already do further down in the code. That changes output to just spitting out the last entered digit for both 1-9 and two-digit numbers.
Algific
It's unclear, where the sub-ing of "0" are placed, do you have enough rep to edit the question with updated code ? FYI, I need to take leave now, but I'll check again here in +/- an hour's time in case no one else helped you...
mjv
I'll update it. Thanks =)
Algific
Thank you very much. I needed help with this. Compiler just finds two things; " mov ax" and " add dx ". I'll look trough later and see if I can see the missing parts. Again, THANK YOU!!!!!
Algific
I really need help with them...
Algific
@data_jepp "...help with them" Help with what?
mjv
The two lines that the compiler complains about: mov ax and add dx.Both mov and add requires two input.
Algific
@data_jepp. I fixed a typo/omission for the `add dx` case needs to be `add ax, dx` (look for "fixed syntax error..." comment. I don't know what/where the `move ax` issue you are talking about. The only place with this pattern is with `mov ax, cx` which should be syntactically ok... Maybe to move forward if this gives you issues, for now, replace with push cx followed by pop ax, which will do same thing albeit less efficiently. Again, sorry I don't have access to a compiler to check my "work".
mjv
Hmm diagnosis so far; If i enter only one char(1) followed by a space the program freezes. If I enter two two-digit numbers separated by space it just returns the right number as the answer. 55 33 = 33
Algific
You have been more than enough help, thank you. I will figure this out myself. I need the exercise. Thank you!
Algific
@data_jepp. The 2nd problem, for sure, is from another part of the code, the ReadNumber() function does just that (reading a number), not adding them (although of course it has multiply by 10 and adding logic, but for the current number only). As for the first problem, hard to tell. At any rate, `you need to get yourself a debugger` and step through the code to see that all is happening as you'd expect it. Insight from a brief debugging session will solve these two issues (and then some) in a few minutes!
mjv
You are right, but I can't get my hands on the turbo debugger 1.0. Tried to search the web for it.
Algific
I checked the code that calls the read. Were it adds the numbers, add cl,ch Here a found something. cl is the last digit, and ch is the first. And cl is 00, that is were the problem is. Some how it's not getting/remembering the first read char. It adds the last digit with 00.
Algific
Lets change strategy, when it comes to reading. Lets say that numbers less than 10 must start with 0. 01, 06 etc. Would that make it easier?
Algific
@data_jepp: Not a good idea, when you "graduate" to 3 and 4 digit numbers will you then also require that many leading zeros. Anyway it doesn't help very much. As said, and aside from the novelty of the language/technology, this is very simple stuff, and a bit of initiative, patience and a good debugger should allow you to move past these issues. You NEED to get these skills anyway, no point in running around the problem here! (But, yes, in some cases, rethinking the requirements may be a good idea, even producing a better solution sometimes)
mjv
I just hacked it together with 0 in front of numbers < 10. Very easy and it works. Thanks for you're guidance. :)
Algific
A: 

Hi I am new to assembly and still having a hard time with it. If you guys may, I would like to ask how to print the output? I am getting garbage data so most likely, I am doing something wrong. Thanks.

den