0

Well as the title said , I am working on a NASM project: the idea is simple , I need to take a month from input (string) and give the number of day (using cases regarding numbers). Until now I spent the day dealing with reading/printing and finally comparing 2 strings , which I could do after some struggles and thanks to some old questions I've found here and on other forums.My current problem is that I need to put the months (names) in an array so I could do the comparing with a loop, I saw on another answer that I could label the 'array' like this: label: db str1,str2 I tried that and when I try printing with just the label I get only the last month (I tried label+i but I still get the same thing) Well, here is a part of my code:

segment .data
org 100h
msg db "a"
mon1 db "janvier",0
mon2 db "fevrier",0
mon3 db "mars",0
mon4 db "avril",0
mon5 db "mai",0
mon6 db "juin",0
mon7 db "juillet",0
mon8 db "aout",0
mon9 db "septembre",0
mon10 db "octobre",0
mon11 db "novembre",0
mon12 db "decembre",24h
mo dw 1,2,3,4,5,6,7,8,9,10,11,12
mon:    
dw mon1,mon2,mon3,mon4,mon5,mon6,mon7,mon8,mon9,mon10,mon11,mon12
segment .code
    mov dx,mon
    mov ah,09h             
    int 21h

edit2: I tried the solution given by @ecm , I had to make a few change because It gave me some errors then after i could finally run it It went to error, Here is the whole code:

     segment .code
    display_month:
        ; takes month 1 to 12 in ax
        dec ax ; make number 0-based
        cmp ax,amount
        jae  error ; if out of range -->
        add ax, ax ; make it an index into a word array
        mov bx, ax ; use bx for addressing memory
        mov dx, word [mon+ bx] ; access array entry
        mov di, dx
        mov cx, -1
        mov al, 0
        repne scasb
        not cx
        dec cx ; string length
        mov bx, 1
        mov ah, 40h
        int 21h ; write to stdout
        clc ; indicate not error

        mov dx,msg1
        mov ah,09h
        int 21h
        mov ah,0Ah
        mov dx, len         ;start of buffer
        int 21h
        mov ah,02h
        mov dl,10
        int 21h
        mov dl,13
        int 21h     

        mov bx,act    
        mov dx,buffer 
        add dl,byte [bx]     
        mov bx,dx            ; move pointer into BX
        mov byte [bx],24h    ; put the $ there.

    ; compare input with msg variable(a placeholder for the moment ) I want to compare with the mon array values , and then use the index as an argument to call the cond procedure.
        mov ax,msg  
        mov si,ax
        mov ax,buffer
        mov di,ax
        cmpsb  
        jz Yep         ; if strings equal goto Yep
        jmp Nope       ; goto Nope


    Yep:
        mov dx,good
        mov ah,9
        int 21h    ; tell the user it's good
    Nope:
        mov dx,bad
        mov ah,9
        int 21h    ; tell the user it's bad
    end:
        mov  ah,4Ch
        int 21h
        ret
    error:
        stc
        retn
    cond:
        cmp ax,2
        je fev
        cmp ax,7
        jg odd
        jle even
    else:   mov bx,31
        jmp endif
    fev:    mov bx,28
    odd:    test ax,1
        jnz trente
        jmp else
    even:   test ax,1
        jp trente
        jmp else
    trente:  mov bx,30
    endif:  ret

    segment .data
    org 100h
        ;; variables declaration
    msg1 db "Veullez entrer un mois:",24h
    msg db "a",24h
    mon1:   db "janvier",0
    mon2:   db "fevrier",0
    mon3:   db "mars",0
    mon4:   db "avril",0
    mon5:   db "mai",0
    mon6:   db "juin",0
    mon7:   db "juillet",0
    mon8:   db "aout",0
    mon9:   db "septembre",0
    mon10:  db "octobre",0
    mon11:  db "novembre",0
    mon12:  db "decembre",0
    good db "Bon choix!",24h
    bad db "Mauvais choix!",24h
    mon:
     start:
        dw mon1,mon2,mon3,mon4,mon5,mon6,mon7,mon8,mon9,mon10,mon11,mon12
    tend:
    len db 254 ; a fair amount of space
    act db 0   ; will be filled with actual amount of chars received
    buffer times 254 db 0
    size equ  tend - start
    amount equ size / 2

I forgot to add how I am compiling , well I am using dosbox to run .com files , because they don't work on windows 10 , and I use the command : nasm name.asm -o name.com to create the .com file and then I just open it in dos. EDIT: Well I struggled a lot to make that happen , I couldn't do it even thought I tried different ways , the last thing I went with was to use the first month and keeping adding the size of months to pass to the other ones (i.e mon1+8 gives me mon2 ...) but then I encountered with the difference in sizes , so I changed all the months to just 3 letters (4 for june) so I could move with multiples of 4 but then I couldn't go all the way to the end .. So after that I just decided to use the mon(i) by calling the names and repeating the manoeuvre , which seemed to work thought I encountered a problem with comparing (I am still trying to figure out) , well here is the last version until I figure out how to fix that.The problem at this moment is that even if I type something different than the mon1 to mon12 I get this:Le mois de 'input' est de 30 jours while normally it should take me back to the start of the nope label.

        segment .code
org 100h
    mov dx,msg1     
    mov ah,09h
    int 21h
here:   mov ah,0Ah  
    mov dx, len     
    int 21h
    mov ah,02h  
    mov dl,10
    int 21h
    mov dl,13
    int 21h     

    mov bx,act    
    mov dx,buffer
    add dl,byte [bx]     
    mov bx,dx            
    mov byte [bx],24h    
    jmp comp
yep:
    mov dx,g1       
    mov ah,09h
    int 21h
    mov dx,buffer
    int 21h
    mov dx,g2
    int 21h
    mov ax, [i]
    call cond       
    mov ah,02h
    mov dl,bh
    int 21h
    mov dl,bl
    int 21h
    mov dx,g3
    mov ah,09h
    int 21h
    jmp end
comp:   mov bx,0
    mov [i],bx

jan:    call inct   
    mov bx,buffer
    mov si,bx
    mov bx,mon1
    mov di,bx
        cmpsb
    jz yep

fevr:   call inct
    mov bx,buffer
    mov si,bx
    mov bx,mon2
    mov di,bx
    cmpsb
        jz yep

mar:    call inct
    mov bx,buffer
    mov si,bx
    mov bx,mon3
    mov di,bx
    cmpsb
    jz yep

avr:    call inct
    mov bx,buffer
    mov si,bx
    mov bx,mon4
    mov di,bx
    cmpsb
    jz yep

mai:    call inct
    mov bx,buffer
    mov si,bx   
    mov cx,mon5     
    mov di,cx
    cmpsb
    jz yep

juin:   call inct
    mov bx,buffer
    mov si,bx
    mov bx,mon6     
    mov di,bx
    cmpsb
    jz yep
    jmp jui

jui:    call inct
    mov cx,buffer
    mov si,cx
    mov cx,mon7
    mov di,cx
    cmpsb
    jz yep

aout:   call inct
    mov cx,buffer
    mov si,cx
    mov cx,mon8
    mov di,cx
    cmpsb
    jz yep
    jmp sep

sep:    call inct
    mov bx,buffer
    mov si,bx
    mov cx,mon9
    mov di,cx
    cmpsb
    jz yep
    jmp oct

oct:    call inct
    mov bx,buffer
    mov si,bx
    mov cx,mon10
    mov di,cx
    cmpsb
    jz yep
    jmp nov

nov:    call inct
    mov bx,buffer
    mov si,bx
    mov cx,mon11
    mov di,cx
    cmpsb
    jz yep
    jmp dect

dect:   call inct
    mov bx,buffer
    mov si,bx
    mov cx,mon12
    mov di,cx
    cmpsb
    jz yep
    jmp nope
nope:
    mov dx,bad      
    mov ah,9
    int 21h
    jmp here        
end:
    mov  ah,4Ch     
    int 21h         
    ret
inct:
    push bx
    mov bx,[i]
    inc bx
    mov [i],bx
    pop bx
    ret

cond:               
    cmp ax,2
    je fev
    cmp ax,6
    je th
    cmp ax,8
    je th
    cmp ax,7
    jg odd
    jle even
else:   mov bl,'1'
    mov bh,'3'
    jmp endif
fev:    mov bl, '8'
    mov bh,'2'
    jmp endif
th: jmp else
odd:    test ax,1
    jnz trente
    jmp else
even:   test ax,1
    jp trente
    jmp else
trente:  mov bh,'3'
     mov bl,'0'
endif:  ret


segment .data
i db 0
msg1 db "Veullez entrer un mois:",24h
mon1:   db "janvier",24h
mon2:   db "fevrier",24h
mon3:   db "mars",24h
mon4:   db "avril",24h
mon5:   db "mai",24h
mon6:   db "juin",24h
mon7:   db "juillet",24h
mon8:   db "aout",24h
mon9:   db "septembre",24h
mon10:  db "octobre",24h    
mon11:  db "novembre",24h
mon12:  db "decembre",24h
g1 db "Le mois de",20h,24h
g2 db 20h,"est de",20h,24h
g3 db 20h,"jours",24h
bad db "Le mois saisi  n'est pas correct!",10,13,"Veuillez entrer un autre mois:",24h
len db 254 ; a fair amount of space
act db 0   ; will be filled with actual amount of chars received
buffer times 254 db 0

Isu
  • 330
  • 1
  • 4
  • 16
  • You likely want zero terminated strings and put their addresses into the array. Putting 1-12 into an array makes no sense. – Jester Jan 11 '20 at 17:44
  • @jester well the mo array is just for making conditions for the number of days output, what I am currently looking for is a way to make a string's array , so when the user input the name of a month , I can check which month it's from the array and then take the index and make my conditions. – Isu Jan 11 '20 at 18:36
  • I told you how to do that. – Jester Jan 11 '20 at 18:50
  • I didn't understand well at first , the second part got me confused , but I guess it's clear now Thank you , I'll try that. – Isu Jan 11 '20 at 20:02

1 Answers1

2

Try this:

segment .code
display_month:
    ; takes month 1 to 12 in ax
    dec ax ; make number 0-based
    cmp ax, montab.amount
    jae .error ; if out of range -->
    add ax, ax ; make it an index into a word array
    mov bx, ax ; use bx for addressing memory
    mov dx, word [montab + bx] ; access array entry
    mov di, dx
    mov cx, -1
    mov al, 0
    repne scasb
    not cx
    dec cx ; string length
    mov bx, 1
    mov ah, 40h
    int 21h ; write to stdout
    clc ; indicate not error
    retn

.error:
    stc
    retn

segment .data
mon1: db "janvier",0
mon2: db "fevrier",0
mon3: db "mars",0
mon4: db "avril",0
mon5: db "mai",0
mon6: db "juin",0
mon7: db "juillet",0
mon8: db "aout",0
mon9: db "septembre",0
mon10: db "octobre",0
mon11: db "novembre",0
mon12: db "decembre",0

    align 2
montab:
.:
    dw mon1
    dw mon2
    dw mon3
    dw mon4
    dw mon5
    dw mon6
    dw mon7
    dw mon8
    dw mon9
    dw mon10
    dw mon11
    dw mon12
.end:
.size equ .end - .
.amount equ .size / 2

You could use 12 as the hardcoded array length in this case. But using equates for the length and amount of entries is useful for static data arrays more generally.

ETA: I added alignment for the table, which is good for performance. Not needed but it doesn't cost much.

Note that I dropped the org directive from my example. This is because I am presenting just one function that should be called from other program logic. If you're assembling into a simple style flat .COM executable for 86-DOS, you still need to include the org 256 at some point.


Here's a breakdown of your question's attempt:

msg db "a"

This seems like an unused leftover.

mon1 db "janvier",0
mon2 db "fevrier",0
mon3 db "mars",0
mon4 db "avril",0
mon5 db "mai",0
mon6 db "juin",0
mon7 db "juillet",0
mon8 db "aout",0
mon9 db "septembre",0
mon10 db "octobre",0
mon11 db "novembre",0

These are all fine, they define ASCIZ strings. (The Z stands for zero-terminated.)

mon12 db "decembre",24h

This one uses a different terminator, in this case the dollar sign (24h = 36). It is not appropriate to mix terminators between array entries. Either use all ASCIZ or all CP/M-style dollar-terminated strings.

mo dw 1,2,3,4,5,6,7,8,9,10,11,12

This is useless. If you wanted to map a number from 1 to 12 as index into this array, the original value would be found at that array entry. If the entries had different numbers this type of array could be useful, but not with identity mapping.

mon:    
dw mon1,mon2,mon3,mon4,mon5,mon6,mon7,mon8,mon9,mon10,mon11,mon12

This is essentially correct. (I put each entry on its own line and prepended the align directive, but neither is absolutely necessary.)

    mov dx,mon
    mov ah,09h             
    int 21h

This loads the address of your message table into dx then passes dx to interrupt 21h function 09h. This function expects a dollar-terminated string, so only your December string would work. More importantly, it will try to display the literal bytes that make up your array. You need to, instead, dereference a pointer to one of your array's entries to load the address stored therein, which is the address of the associated message string.

ecm
  • 2,583
  • 4
  • 21
  • 29
  • Thnak you for your answer , I'll read it and try it right now. – Isu Jan 11 '20 at 20:33
  • re: Thanks a lot for your efforts ,sadly I am not that fluent with nasm , I couldn't understand some of the steps , can you give me some simple explanations please? Based on what I've already done. – Isu Jan 11 '20 at 20:37
  • @Isumairu: I edited my answer to comment on your attempt. Please tell me if you need more, perhaps such as more comments on my solution. – ecm Jan 11 '20 at 20:50
  • Thanks again for your quick answer, so to explain things on my side, the msg db "a" was just for testing something in the rest of the code and I forgot to remove it. As for what you said about the mo array , yes I can see that's useless now that you said it and we can just use the other . As for ASCIZ , it can't work with the ah=09h int 21h so what can I do ? (I need to show what month has been picked , something like this : `February has 28 days` , can I use the dollar sign instead? If you want , I'll share all the code with you so you can get an idea about what I thought of. – Isu Jan 11 '20 at 20:56
  • @Isumairu: The part after `mov dx, word [montab + bx]` in my example uses a repeated string instruction (`repne scasb`, repeat-while-not-equal scan string byte) to determine the length of the string. Then I pass the string pointed to by `ds:dx` of length `cx` to interrupt 21h function 40h (write to file), with the handle given in `bx` equal to 1, which means standard output. The advantage over function 09h is that you can display a literal dollar sign this way. However, you can change all your data strings to be dollar-terminated if you prefer. The array entry dereferencing is crucial though. – ecm Jan 11 '20 at 21:04
  • I tried changing to dollar-terminated but I still got a not responding , and had to quit again , I'll try using your method , I am starting to see it more clearly , thanks for your time. – Isu Jan 11 '20 at 21:12
  • @Isumairu: "Not responding" means what? Perhaps you put your data first in the assembler's output, and whatever machine you use to execute the executable tries to interpret the data as machine code. You will have to show us a complete example including assembling command line and how you run the result, for us to know with any certainty. – ecm Jan 11 '20 at 21:16
  • I can't tag you, but check the code , I posted the whole program until now , I still haven't finished some conditions because I need to finish that part first. And yeah I put the data first, is that a problem ? – Isu Jan 11 '20 at 21:23
  • @Isumairu: It is a problem, and likely the cause of your crash. I didn't check all of the program, but this is certainly one problem. Do you see any output from the program at all, or what else happens if you try to run it? What OS or VM are you using to run the executable? – ecm Jan 11 '20 at 21:34
  • I am using DOSBox ECE r4301 , I tried moving the segment .data after the .code , and it worked but I got gibberish again , that I guess because of the ASCIZ I'll try using your code and see what happens . Note that I want the indexes of the month , but I guess I can extract them . – Isu Jan 11 '20 at 21:44
  • @Isumairu: What do you mean by "want the indexes"? Do you mean you want to determine the month's length from a month number? That would be out of the scope for this question, so you should make another if you cannot figure it out. – ecm Jan 11 '20 at 21:49
  • No not like that but as I said before (you'll get what I mean if you check the procedure at the end of the code) If you pick May , the equivalent number will be 5 (out of 12 months) and then I can check , if it's >7 and odd or <= 7 and even then the number of days is 30 , or if it's =2 then it's 28(I don't consider the 29 case) and else it's 31 (That's how the problem was given by my professor). – Isu Jan 11 '20 at 21:59
  • Hi , I tried your solution (with some changes) but It would directly go to error label , can you check please (I edited the code) , on the other hand how can I get the corresponding index of the array value (it should be on cx right?). – Isu Jan 12 '20 at 09:18
  • @Isumairu: You should put your code first, as the execution begins at address 100h, corresponding to the first instruction that you assemble. And you should restore the `retn` I put after `clc`. And then you should use an instruction `call display_month` at the point in your code where you want to call my function. If you have difficulties with this, try to read up on subfunction calls. Make sure that the value in register `ax` is 1 to 12 at that point. The `org 100h` directive belongs next to the initial `segment .code` directive. – ecm Jan 12 '20 at 10:04
  • See also https://stackoverflow.com/questions/31035361/how-to-take-digits-as-input-in-assembly-language-then-print-them-as-a-number – ecm Jan 12 '20 at 10:16
  • Ok I thought I should use it as the main , how can I check that the value of ax is 0 -> 12 ? Should I store the array first value on ax ? (like mov ax,mon ? before I call the display_month) – Isu Jan 12 '20 at 10:22
  • What I scan for is the month name , and then I need to use the month index (position between months) to check the cond. – Isu Jan 12 '20 at 10:23
  • I thought of an alternative solution which is to keep just the names of the months as vars (mon1,mon2..) and then when I need to check if a month was typed I could just do a loop starting with mon1 and then adding the number of characters (i.e: to pass to mon2 I need to use mon1+8) but then I thought of using just 4/3 letters so that the loop will be easier , in that case how can I get just 3/4 letter from the buffer ? – Isu Jan 12 '20 at 10:26
  • 1
    For comparing strings refer to https://stackoverflow.com/questions/14099832/how-to-compare-two-strings-assembly and https://stackoverflow.com/questions/33592661/string-comparison-in-8086 -- You can make a loop that uses part of the beginning of my function to get a pointer to each month string in turn, and for each one compare the string to your input. Keep track of a loop counter to tell which month you are checking. – ecm Jan 12 '20 at 15:18
  • Thank you for all your help , I'll post what I did later. – Isu Jan 12 '20 at 19:49