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
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.
I want to use the LOOP instruction to print this string in assembly :
abcccbcccabcccbccc
We have ab, ccc, b and then backup to ab and then ccc.
I hope I will find some solutions with your help.
I am using emu to compile the source !
.model small
.stack 200h
.code
main PROC
mov ah, 0
mov al, 12h ; Clear screen
int 10h
mov ah, 3
mov bh, 0 ; get cursor
int 10h
mov ah, 2
mov bh, 0 ;set cursor
mov dl,12
int 10h
mov cx, 5 ; counter
mov dl, 65 ; ASCII of 'A'
t1:
mov ah, 2h
int 21h
add dl, 32 ; 97 - 65 - convert to LC
mov ah, 2h
int 21h
sub dl,31 ;remove the 32 added, but increment
push dx ;save DX on stack
mov dl, 32 ;space character
mov ah, 2h
int 21h
pop dx ;return DX from stack
loop t1
mov ah, 4Ch ;exit DOS program
mov al, 00h ;return code = 0
int 21h
ENDP
END main
Next 2 small programs are 2 possible solutions to your problem :
SOLUTION #1
.stack 100h
.data
txt db 'abcccbccc$' ;STRING TO DISPLAY.
.code
mov ax, #data ;INITIALIZA DATA SEGMENT.
mov ds, ax
mov cx, 3 ;DISPLAY STRING 3 TIMES.
t1:
mov ah, 9
mov dx, offset txt
int 21h
loop t1
mov ax, 4c00h ;TERMINATE PROGRAM.
int 21h
SOLUTION #2
.stack 100h
.data
s1 db 'ab$' ;STRING TO DISPLAY.
s2 db 'ccc$' ;STRING TO DISPLAY.
s3 db 'b$' ;STRING TO DISPLAY.
.code
mov ax, #data ;INITIALIZA DATA SEGMENT.
mov ds, ax
mov cx, 12 ;DISPLAY THE 4 STRING 3 TIMES.
mov bl, 1 ;1 = DISPLAY STRING S1.
;2 = DISPLAY STRING S2.
;3 = DISPLAY STRING S3.
;4 = DISPLAY STRING S2.
mov ah, 9 ;NECESSARY TO DISPLAY STRINGS.
t1:
;BL TELLS WHAT TO DO.
cmp bl, 1
je string1 ;BL=1 : DISPLAY S1.
cmp bl, 2
je string2 ;BL=2 : DISPLAY S2.
cmp bl, 3
je string3 ;BL=3 : DISPLAY S3.
;string4: ;BL=4 : DISPLAY S2.
mov dx, offset s2
int 21h
jmp continue ;SKIP NEXT DISPLAYS.
string1:
mov dx, offset s1
int 21h
jmp continue ;SKIP NEXT DISPLAYS.
string2:
mov dx, offset s2
int 21h
jmp continue ;SKIP NEXT DISPLAYS.
string3:
mov dx, offset s3
int 21h
continue:
inc bl ;BL TELLS WHAT TO DO.
cmp bl, 4
jbe nextstring ;IF BL < 4
mov bl, 1 ;BL STARTS AGAIN.
nextstring:
loop t1
mov ax, 4c00h ;TERMINATE PROGRAM.
int 21h
I've got an assignment to make an assembly program which print 'a' to 'z' vertically line by line using stack, loop cx and dx.
Can anyone help me please.
This is program of printing a to z, but i dont have an idea how to use stack cx and dx in my program:
.data
l1c db 0ah,0dh,"S"
.code
main proc
mov ax #data
mov ds,ax
mov al,48
mov cx,10
d:
mov dl,al
mov ah,2
int 21h
call linechange
inc al
loop d
mov ah,4ch
int 21h
main endp
;Procedure
linechange proc
lea dx,l1c
mov ah,9
int 21h
ret
linechnage endp
end main
(this is the program which i made by my self)
I guess your teacher wanted to avoid a "clever" solution like:
.MODEL SMALL
.STACK 1000h
.DATA
smart_out db 'a',13,10,'b',13,10,'b',13,10,'c',13,10,'d',13,10,'e',13,10
db 'f',13,10,'g',13,10,'h',13,10,'i',13,10,'j',13,10,'k',13,10
db 'l',13,10,'m',13,10,'n',13,10,'o',13,10,'p',13,10,'q',13,10
db 'r',13,10,'s',13,10,'t',13,10,'u',13,10,'v',13,10,'w',13,10
db 'x',13,10,'y',13,10,'z',13,10,'$'
.CODE
main:
mov ax, #data
mov ds, ax
mov ah, 9
mov dx, OFFSET smart_out
int 21h
mov ax, 4C00h
int 21h
END main
You are supposed to output this with a LOOP (CX needed). In a loop you need to preserve at least AX and CX since you never know if a procedure like INT 21h will change it. A call to INT 21h / 9 fulfills the third condition since it needs a value in DX:
.MODEL SMALL
.STACK 1000h ; Reserve space for stack and initialize stack pointer
.DATA
l1c db 0dh, 0ah, '$' ; Dollar-sign!
.CODE
main PROC
mov ax, #data
mov ds, ax
mov al, 'a'
mov cx, 26
d:
push ax ; Store AX (AL is a part of AX)
push cx ; Store CX
mov dl, al
mov ah, 2
int 21h
mov ah, 9
mov dx, OFFSET l1c
int 21h
pop cx ; Restore CX & AX in reversed push-order
pop ax
inc al
loop d ; Loops until cx == 0
mov ah, 4ch
int 21h
main ENDP
END main