The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: scooter4483 on March 02, 2006, 09:26:36 PM

Title: upper case to lower case
Post by: scooter4483 on March 02, 2006, 09:26:36 PM
i searched the site and found some but not a lot of similar questions to mine.  Here is some of my code, it converts from lower case to upper case, but my a2 is not converting my lower case to upper case.  did i miswrite something.

Main PROC
    call ClrScr                    ;clears the screen
    mov edx, OFFSET String1       
    call WriteString               ;displays String1
    call Crlf                      ;carriage return line feed

    mov ecx, 99            ;the max # of char. stored in memory
    mov edx, OFFSET String3
    call ReadString         ;eax returns # of Char. read 
    call Crlf                      ;carriage return line feed
    call Crlf                      ;carriage return line feed

    mov edx, OFFSET String2
    call WriteString
    call Crlf
   
    mov edx, OFFSET String3

A0: mov al, [edx]       
    cmp al, 0           
    je Display_String
    cmp al, 'A'      ;from here it will convert from lower to uppercase
    jb A2
    cmp al, 'Z'
    ja A2
    add al, 'a'-'A'
    mov [edx], al

A2: cmp al, 'a'      ;A2 will change from uppercase to lowercase
    jb A1
    cmp al, 'z'
    ja A1
    add al, 'A'-'a'
    mov [edx], al

A1: inc edx
    jmp A0

Display_String: mov edx, OFFSET String3
      call WriteString
      call Crlf
      call Crlf
        exit

Main ENDP
Title: Re: upper case to lower case
Post by: scooter4483 on March 02, 2006, 09:53:46 PM
never mind.  all i needed was conveting the uppercase to lower case.  This is how i did it:

INCLUDE Irvine32.inc

.data

    String1 BYTE "Enter a string: ", 0
    String2 BYTE "Here is the processed result: ", 0
    String3 BYTE 100 dup(?)

;---------------------------------------------------
.code


Main PROC
    call ClrScr                                  ;clears the screen
    mov edx, OFFSET String1       
    call WriteString                          ;displays String1
    call Crlf                                     ;carriage return line feed

    mov ecx, 99                      ;the max # of char. stored in memory
    mov edx, OFFSET String3
    call ReadString         ;eax returns # of Char. read 
    call Crlf                                      ;carriage return line feed
    call Crlf                                      ;carriage return line feed

    mov edx, OFFSET String2
    call WriteString
    call Crlf
   
    mov edx, OFFSET String3

A0: mov al, [edx]       
    cmp al, 0           
    je Display_String
    cmp al, 'A'         ;upper to lower
    jb A1
    cmp al, 'Z'
    ja A1
    add al, 'a'-'A'
    mov [edx], al

A1: inc edx
    jmp A0

Display_String: mov edx, OFFSET String3
      call WriteString
      call Crlf
      call Crlf
        exit

Main ENDP

HERE IS MY NEXT QUESTION.  How do I read each letter from the user input so that it replaces the letter with 3 letters ahead.  For example,  if the user put in Hello, the result would be "khoor".  what is did was take the h and replaced it with h+3 which is k, and so on.  Thanks guys.
Title: Re: upper case to lower case
Post by: Mark Jones on March 02, 2006, 10:06:48 PM
Hi scooter. Changing bytes is very easy once you get the hang of it. Here's some commented snippets to get you thinking:


    mov ecx,offset szMyString                      ; ecx = offset of MyString
    mov al,byte ptr [ecx]                          ; get new byte at offset ecx into al
    inc ecx                                        ; point to next byte of szMyString
Title: Re: upper case to lower case
Post by: scooter4483 on March 03, 2006, 03:48:44 AM
thanks for the response, but i'm a little confused.  i cant relate that to moving the letters ahead by 3.  Is there any other hints or something?  thanks.
Title: Re: upper case to lower case
Post by: PBrennick on March 03, 2006, 06:06:26 AM
    mov ecx,offset szMyString                      ; ecx = offset of MyString
    mov al,byte ptr [ecx]                          ; get new byte at offset ecx into al
    add  al,3                                      ; bump it up 3 places
    mov byte ptr [ecx], al                         ; put it back
    inc ecx                                        ; point to next byte of szMyString


You might want to test the value in al to make sure it is a letter and has a value less than 'w' but that is up to you, the code will work.  Don't forget to handle uppercase, maybe convert all uppercase letters to lower.

By the way, how do you plan to handle x,y and z?  Wrap around to a,b and c?  if so, if al is a letter greater than 'w' then instead of adding 3, subtract 23.

Sorry, several edits here as things occurred to me, have fun.

Paul
Title: Re: upper case to lower case
Post by: scooter4483 on March 03, 2006, 06:34:45 AM
where does this code go?  is it directly after my A0 like this

A0: mov al, [edx]       
    cmp al, 0           
    je Display_String
    cmp al, 'A'                  ;upper to lower
    jb A1
    cmp al, 'Z'
    ja A1
    add al, 'a'-'A'
    mov [edx], al

    mov ecx,offset szMyString                      ; ecx = offset of MyString
    mov al,byte ptr [ecx]                          ; get new byte at offset ecx into al
    add  al,3                                      ; bump it up 3 places
    mov byte ptr [ecx], al                         ; put it back
    inc ecx                                        ; point to next byte of szMyString


Title: Re: upper case to lower case
Post by: scooter4483 on March 03, 2006, 06:38:03 AM
in the code szMystring, should I make it:

Mystring BYTE "abcd...z"
Title: Re: upper case to lower case
Post by: scooter4483 on March 03, 2006, 06:56:01 AM
im more confused now than before.  Do I have to compare again or something as well?  Man, am i stressing right now.  :(
Title: Re: upper case to lower case
Post by: scooter4483 on March 03, 2006, 07:05:46 AM
So I did this:

A0: mov al, [edx]       
    cmp al, 0           
    je Display_String
    cmp al, 'A'                  ;upper to lower
    jb A1
    cmp al, 'Z'
    ja A1
    add al, 'a'-'A'
    mov [edx], al

    mov edx, OFFSET String3
    mov al, byte ptr [edx]
    sub al, 23
    mov byte ptr [edx], al
    inc edx

and im getting some weird answers:  When I input  'A' it returns 'J'.  It should make the letter lowercase and should return D.  What gives?  Thanks again and sorry for all my fuss.
Title: Re: upper case to lower case
Post by: Mark Jones on March 03, 2006, 09:20:01 AM
Quote from: scooter4483 on March 03, 2006, 07:05:46 AM
    mov edx, OFFSET String3
    mov al, byte ptr [edx]
    sub al, 23
    mov byte ptr [edx], al
    inc edx

... When I input  'A' it returns 'J'...

Hi Scooter, try not to stress, you're almost there.
Do you need case altering? If so, first make sure that it is working properly, THEN tackle the letter altering. Working with multiple unknowns is always much more difficult than working with one unknown. Simplify. :)
Here's some useful info.

41h-5Ah = uppercase letters.
61h-7Ah = lowercase letter. To convert upper to lower, add 20h (32d). To convert lower to upper, subtract 32.

Here's the routine I use in my Lib Search Tool to change case, somewhat simplified. Perhaps you can learn from it.


@@:                              ; this is an "anonymous jump label"
    mov al,byte ptr [ecx]        ; get byte from pointer ecx into al
    inc ecx                      ; point to next byte
    cmp al,"A"                   ; is our byte less than 41h?
    jl @F                        ; if so, skip that...
    cmp al,"z"                   ; or more than 7Ah?
    jg @F                        ; if so, don't change those either...
    cmp al,"Z"                   ; if it's less than 5Ah, convert to upper
    jle convupper
    cmp al,"a"                   ; if it's greater than 61h, convert to lower
    jge convlower
    jmp @F                       ; else jump out, not a letter
convlower:   
    sub al,32                    ; byte is converted to lowercase now
    jmp @F
convupper:
    add al,32                    ; byte is converted to upper
@@:                              ; case of byte in al is now reverse (but only if alphabetic!)


There are some interesting string examples in \masm32\help\ASMINTRO.HLP under "Working with Strings" and it covers exactly this. You are so very close to solving this by yourself Scooter, won't you try it tomorrow?
Title: Re: upper case to lower case
Post by: ChrisLeslie on March 03, 2006, 10:16:31 AM
This should convert to lowercase using high level syntax.

; #########################################################################

      .386
      .model flat, stdcall
      option casemap :none   ; case sensitive

; #########################################################################

      include \masm32\include\windows.inc
      include \masm32\include\masm32.inc
      include \masm32\include\user32.inc
      include \masm32\include\kernel32.inc
     
      includelib \masm32\lib\masm32.lib
      includelib \masm32\lib\user32.lib
      includelib \masm32\lib\kernel32.lib
     
      include \masm32\macros\macros.asm
   
      Main   PROTO

; #########################################################################

    .data
      Msg1        db "Type something: ",0
      Msg2        db "As lowercase: ",0
      Buff        db 80 dup(0)
      BuffUpper   db 80 dup(0),13,10,0

; #########################################################################

    .code

    start:
      invoke Main
      invoke ExitProcess,0

; #########################################################################

Main proc

    invoke StdOut,SADD("Upper/lower case test",13,10,13,10)
    invoke StdOut,ADDR Msg1
    invoke StdIn,ADDR Buff,LENGTHOF Buff
    invoke StdOut,ADDR Msg2
    mov esi,offset Buff
    mov edi,offset BuffUpper
    ;***********************
    .while(eax != 13)   
      lodsb
      .if(eax!=13)
        or eax,20h          ; this part does the conversion
      .endif
      stosb
    .endw
    ;***********************
    invoke StdOut,ADDR BuffUpper
    invoke StdOut,SADD(13,10)
    invoke StdOut,SADD("Press enter...")
    invoke StdIn,ADDR Buff,LENGTHOF Buff
   
    ret

Main endp

; #########################################################################

    end start


Hope that helps

Chris
Title: Re: upper case to lower case
Post by: Vortex on March 03, 2006, 10:45:55 AM
Scooter,

The masm32 packages comes with string handling functions like lcase and ucase , you should try them.
Title: Re: upper case to lower case
Post by: donkey on March 03, 2006, 01:08:01 PM
I use the incredibly inefficient table method, never timed it but I have always assumed that because there are no jumps or condition tests (except for the end of string) that it is faster, probably way off base though.

// Translation matrix for lower case conversion - 256 bytes
ALIGN 16
lcase:
db   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15
db  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
db  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47
db  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
db  64, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111
db 112,113,114,115,116,117,118,119,120,121,122, 91, 92, 93, 94, 95
db  96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111
db 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127
db 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143
db 144,145,146,147,148,149,150,151,152,153,154,155,156,156,158,159
db 160,161,162,163,164,165,166,167,168,169,170,171,172,173,173,175
db 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191
db 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207
db 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223
db 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239
db 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255


lea ebx,lcase
mov edi, [pString]
xor eax,eax
:
mov al, [edi]
xlatb
mov B[edi],al
add edi,1
or al, al
jnz <
ret
Title: Re: upper case to lower case
Post by: scooter4483 on March 03, 2006, 02:35:00 PM
thanks for the responses.  the code works, meaning it converts to lowercase if i take out the following code:

   mov ecx,offset szMyString                      ; ecx = offset of MyString
    mov al,byte ptr [ecx]                           ; get new byte at offset ecx into al
    sub al, 23                                            ; bump it up 3 places
    mov byte ptr [ecx], al                          ; put it back
    inc ecx                                               ; point to next byte of szMyString

but the code above im trying to use to figure out how to take the letters and move them over by 3.  is the syntax not matching up with the rest of my code or something?
Title: Re: upper case to lower case
Post by: PBrennick on March 03, 2006, 03:13:11 PM
scooter4483,
You need to replace sub al, 23 with add al, 3

Somehow, I must have confused you.  sub al, 23 is ONLY if al  is a lower case letter greater than 'w'

Do you understand this?  Let us resume with that question.  Any of us could give you a complete working example but this is a perfect learning experience for you.  You need to work on each of the most recent suggestions you get from any of us, try to go further and then ask us your next question if one comes up.  There is no need to get stressed out, everone here really wants to help you.  Stay calm and try to enjoy the moment, it will never come again because once you learn it, it isn't as much fun any more.  This is 'your' time.

Paul
Title: Re: upper case to lower case
Post by: scooter4483 on March 03, 2006, 03:20:44 PM
alright, i did some tweaking around and i thought i had it:

A0: mov al, [edx]       
    cmp al, 0           
    je Display_String
    cmp al, 'A'                            ;upper to lower
    jb A1
    cmp al, 'Z'
    ja A1
    add al, 'a'-'A'
    mov [edx], al

    mov edx, OFFSET String3
    mov al, byte ptr [edx]
    cmp al, 'w'                       ;comparing the pointer to w
    jg A2                              ;if the letter is greater than w, go to A2
    add al, 3                         ;otherwise add 3 to al

A2: sub al, 23                      ;subtract 23 if greater than w
    mov [edx], al                   ;put al back into the edx pointer

A1: inc edx
    jmp A0

Am I close, any suggestions?
Title: Re: upper case to lower case
Post by: PBrennick on March 03, 2006, 03:55:23 PM
scooter4483,

Try this next:

    mov edx, OFFSET String3      ; Point to the string
A0: mov al, byte ptr [edx]       ; Get a character or next character
    cmp al, 0                    ; End of string?
    je Display_String            ; Go show it if yes
    cmp al, 'A'                  ; Check for lower boundary
    jb A1                        ; Jump if not a letter
    cmp al, 'Z'                  ; Uppercase?
    ja A3                        ; Go check for lower, if no
    or al, 20h                   ; Convert to lowercase
    mov byte ptr [edx], al       ; Store it
A3: cmp al, 'w'                  ; Compare character for upper bounds, first check
    jg A2                        ; Jump if possible upper bounds error
    cmp al, 'a'                  ; Check for lowercase
    jb A1                        ; Jump if not a letter
    add al, 3                    ; Otherwise add 3 to al
    mov byte ptr [edx], al       ; Store it
    jmp A1                       ; Done with this character
A2: cmp al, 'z'                  ; Compare character for upper bounds, second check
    ja, A1                       ; Jump if not a letter
    sub al, 23                   ; Otherwise do a wraparound
    mov byte ptr [edx], al       ; Store it
A1: inc edx                      ; Point to next character
    jmp A0                       ; Go get it
Display_String:                  ; You go from here and tell me how your are doing ...


This is untested but looks correct, you try it and tell me.

Paul

Title: Re: upper case to lower case
Post by: scooter4483 on March 03, 2006, 05:35:10 PM
i got the following error when i tried that code:

test.asm<48> : error A2008:  syntax error: ,

You just added a comma in A2, but I fixed it.  Paul, you are my new hero.  The things you did with that code, i just understood after seeing my TA.  I was doing something similar and here are the things she made me realize.  My changing of the letters would only work if I have capital letters.  I was missing the connection that if the letters are lower case then they have to also do the changing of the letters.  that the first thing i was missing.  Im not familiar with the 'byte ptr' code cuz the teacher did not go in depth in that part.  i love this site and i do understand what you are doing.  i'm still trying to understand the jump if above/below statemetents.  I know that my code is looking between A-Z  with the ja and jb.  You used the or statement which just adds, meaning it searches its lowercase letters which is 20h ahead, correct?  The way i did it, was it wrong with the add al, 'a'-'A'?

Overall, I would like to thank you all for the help and encouragement.  I'm sorry I failed you guys in not figuring it out.  But im glad i figured out the last program.  Thanks again. guys.
Title: Re: upper case to lower case
Post by: PBrennick on March 03, 2006, 06:02:32 PM
scooter4483,
Thank you for your nice words, they mean a lot.  I see my error in the ja line, how the heck did I miss that!  But you fixed it!  Your add al, 'a'-'A' is functionally correct but the or command does a better and faster job (it sets the flags in a more meaningful way).  If I was only interested in the flags and not changing the actual value using tst would even be better.  Remember that and play with it until you understand it.  Also, about changing jg to ja, this is good programming practice that can prevent hard to detect errors in your future coding.  Make it a habit to only use jg and jl when dealing with signed numbers.  ja and jb is for unsigned numbers which is something that would not create an error in todays code (using jg, I mean) but if any of the computations happened to be greater than 7Fh jg would fail because those are negative numbers if you are testing the sign which is what jg and jl does, remember that and play with it until you understand it.  When using jg, 80h-0FFh is actually less than 0-7Fh!

And above all, do a lot of coding and have a lot of fun.  Say hi to your teacher from me, just before retiring I taught assembly and related classes (Introduction to Computers 101 and Introduction to Computer Programming 101) in a college in New York (Suffern).

Paul
Title: Re: upper case to lower case
Post by: PBrennick on March 03, 2006, 06:37:22 PM
scooter4483,
One more thing, about 'byte ptr' this is another good programming practice.  When assembling, masm pays no attention to the brackets any more so you can, again, get errors if you are not careful.  byte ptr makes sure that the register is an address and not a value so consider it a form of indirect addressing and use it always.

Paul
Title: Re: upper case to lower case
Post by: Mark Jones on March 03, 2006, 07:57:15 PM
Hey Scooter, glad you got it figured out! Not so bad once understand it, hmm? :)
Paul certainly knows his stuff so listen to him, k? :toothy See \masm32\help\ASMINTRO.HLP under "Addressing and Pointers" for more help with pointers and addressing.
Since you expressed some interest, here is a little more info for you. Come back to it later if needed, don't want to overwhelm ya.

Flags register - this is a special register of the processor which contains a number of bit-flags, indicating such things as zero, carry, parity, etc. Most instructions cause updates to occur to the flag register seamlessly as they execute.

JG,JA,JLE... these are conditional jumps. There are lots of 'em. They all look at the flags register internally and jump based on simple logic. JG jumps if the value is GREATER only, JA jumps if the value is ABOVE only, JLE jumps if the value is LESS or EQUAL, etc. Paul explained when to use certain ones. Take this for example:


szCopyMJ1 proc  uses esi edi  szDest:DWORD,szSource:DWORD
    mov esi,szSource                ; szSource is already an offset
    mov edi,szDest                  ; szDest too
@@:
    mov al,byte ptr[esi]            ; fetch a byte
    inc esi                         ; increment source pointer
    mov byte ptr[edi],al            ; put byte
    inc edi                         ; increment dest pointer
    test al,al                      ; null?
    jnz @B                          ; loop if not
    ret
szCopyMJ1 endp


This code loads string offsets into ESI and EDI, then copies bytes from ESI to EDI. But how does it know when to stop? Answer: the TEST function sets the flags register. When TEST AL,AL returns zero (that is, when AL is zero), the Zero Flag is set. The JNZ @B tests the zero flag to see if it is set - and if NOT, code execution jumps back to the previous @@:. JNZ stands for "Jump If Not Zero" so it does exactly that - loops until a zero is found, then falls through to the RET. Note that the zero IS copied before returning - that is a requirement for valid ANSI strings. Incidentally, CMP AL,0 does the same thing as TEST AL,AL. The TEST is often used for testing for zero because it is usually faster than CMP.) Note however that TEST AL,2 is not the same as CMP AL,2.

Carry is another very useful flag. Imagine you want to count to 1000 using only AL and CL. Is that even possible? Sure! When you increment AL from FFh to 00h, the carry flag will be set. Now if you monitor the carry flag, it is possible to then increment CL, effectively allowing you to count up to 65535. That's not a very large number, but if you apply this logic to EAX and CL, suddenly you can count up to 1,099,511,627,775! Your prof will likely have an excercise on this later, so I won't go into too much detail yet. :bg

The above is a PROC - a procedure, which is MASM32 syntax for a type-defined function call. To define this function, a PROTO statement is utilized, normally at the beginning of the file:


    szCopyMJ1    PROTO   :DWORD,:DWORD


This tells MASM that there is a function prototype called szCopyMJ1 which is passed two dword-sized parameters. Then the function can be called using MASM32 INVOKE syntax:


    szCopyMJ1    PROTO   :DWORD,:DWORD
.data
    myString     db  "Hello world!",0
    myBuffer     db  12 dup(0)
.code
    invoke szCopyMJ1,addr myBuffer,addr myString   ; string is copied to myBuffer
    invoke MessageBox,0,addr myBuffer,0,MB_OK      ; show copied string


This is basically how most functions are done in assembly. :)

Note, in the PROC line it says "uses ESI EDI". What does that mean? That's a handy way to preserve registers. What's that? Well if your Prof hasn't already said so, there are some registers which you must not modify. ESI and EDI are two of them. Windows expects the values in ESI and EDI to be the same after your program exits. If they are not, windows might crash! But ESI and EDI are useable, as long as you put the original values back when you're done. That's exactly what "uses esi edi" does in the PROC line - it preserves ESI and EDI so you can use them in your code. It is the equivalent to this:


    push esi
    push edi
; all the other code here
    pop edi
    pop esi


PUSH and POP are commands which save data to a circular buffer. That is, FIRST IN - LAST OUT. All you need to know about it now is that the above works every time to save and restore ESI and EDI.

Hope that's interesting and I didn't confuse you too much. Have fun!
Title: Re: upper case to lower case
Post by: zooba on March 03, 2006, 10:14:12 PM
Quote from: PBrennick on March 03, 2006, 06:37:22 PM
When assembling, masm pays no attention to the brackets any more so you can, again, get errors if you are not careful.  byte ptr makes sure that the register is an address and not a value so consider it a form of indirect addressing and use it always.

Unless I've misunderstood you, I don't believe this is true:

    .data
        dwTemp DWORD 0

    .code

Main PROC
    ConsoleInit
   
    mov eax, OFFSET dwTemp
    mov DWORD PTR eax, 1
   
    Print "eax = %d\ndwTemp = %d\n", eax, dwTemp
   
       
    CPause
    ret
Main ENDP


The output:

eax = 1
dwTemp = 0


So MASM does pay attention to the brackets, otherwise the value of dwTemp would have changed to 1.

I do agree though, that it is a good habit to get into. At least until you're comfortable with how MASM interprets it.

Cheers,

Zooba
Title: Re: upper case to lower case
Post by: Mark Jones on March 03, 2006, 11:38:48 PM
The whole "brackets and ptr" thing is an unnecessary complexity simply because brackets are ignored in all but one case. That makes a newcomer's experience with brackets highly ambiguous. One could say that "Brackets signify the CONTENTS of" such as "mov al,[myVal]", which does take the value of myVal and move it into AL. But it also does the same thing without the brackets. So why doesn't it give an error for trying to move the DWORD-sized offset of myVal into AL? How confusing, really.

I fully believe MASM should yell and moan about spurious brackets instead of ignoring them, so as to restrict our use of them. Anyways yes, in my limited and very confused experience, brackets are required to access memory contents when used after PTR.

<rant>
Not like PTR shouldn't already do what brackets do... sheesh PTR does stand for POINTER! ::) Yeah, eliminate brackets altogether, yeah... Hmm, ask Pelle to eliminate brackets, hmm..... :bg
</rant>
Title: Re: upper case to lower case
Post by: zooba on March 03, 2006, 11:58:45 PM
'Brackets and ptr' is unnecessary in all but one case. That case being where the assembler can't figure out how much memory you're referring to:

mov [esi], al       ; fine because MASM knows that AL is 8-bits
mov [esi], dwNumber ; fine because MASM knows that dwNumber is a DWORD
mov [esi], 3        ; no good because 3 could be anywhere upwards of 2-bits

mov WORD PTR [esi], 3   ; these are identical and both indicate
mov [esi], WORD PTR 3   ; that we're discussing WORDs here
Title: Re: upper case to lower case
Post by: PBrennick on March 04, 2006, 05:03:58 AM
Mark is correct, you need to use the brackets only after byte ptr and word ptr and is used for indirect addressing as I explained.  That was what I was trying to say and my example shows the 'proper' use.  Otherwise masm has problems understanding that there used to be a difference between esi and [esi] for example.  Zooba, your code does not even show the point we are making so, yes, you have misunderstood us.  If you need to see examples of the point we are making look at the source codes for the masm32 library, Hutch uses the same method for the same reason and this topic was beaten to death many moons ago on this forum, IIRC.  Please, lets not confuse our friend who is just learning.  The example code I gave him is correct as written (except for one spurious comma) so it does not need to be discussed at this point any longer.

Paul
Title: Re: upper case to lower case
Post by: zooba on March 04, 2006, 07:19:00 AM
I spent time looking for the 'beating-to-death' of this issue and thought I'd post the links I found.

http://www.old.masmforum.com/viewtopic.php?t=4699
http://www.old.masmforum.com/viewtopic.php?t=409
Title: Re: upper case to lower case
Post by: PBrennick on March 04, 2006, 12:37:39 PM
Zooba,
Thank you for the help.  I did not think to search the old forum.  I could not remember when it happened, looks like it was longer into the past than I thought.  I think it says it well, though, and Tedd says what I said, just use them and use them always.  It makes your code more readable, also.

Again, thank you for the help.
Paul
Title: Re: upper case to lower case
Post by: Mark Jones on March 04, 2006, 06:01:10 PM
Tenkey's post at the bottom of  http://www.old.masmforum.com/viewtopic.php?t=4699  is very interesting. Perhaps we should make that into a BRACKETS.HLP file. :lol

Thanks for searching for that Zooba.
Title: Re: upper case to lower case
Post by: zooba on March 05, 2006, 01:24:06 AM
To briefly summarise the findings of those two posts I posted above:

When you define a variable, MASM gives you the brackets for free. This makes using them similar to C (ie. the name accesses the contents. In some assemblers the name accesses the address). For example:

.data
    dwValue DWORD 0
    ; dwValue EQU [00403000h]

.code
    mov dwValue, 1
    ; mov [00403000h], 1


Note that the commented code above won't actually work, since MASM does not support dereferencing of a constant (for good reason IMO).

Once the assembler sees a set of brackets, it knows it's dealing with an address (since to access the contents of the variable it needs to use the address) and so whether or not the rest of the expression is in brackets is irrelevant. However, more bracketed expressions will be treated as addition:

mov dwValue+1, 1
; mov [00403001h], 1

mov dwValue[1], 1
; mov [00403001h], 1


Multiple sets of brackets around an expression achieves nothing, since they are treated as additions with zero:

mov [dwValue], 1
; mov [[00403000h]], 1


Including a variable in an effective address (bracketed expression) uses the address rather than the value (because the extra brackets are treated as an addition):

mov [eax+dwValue], 1
; mov [eax+[00403000h]], 1


MASM stores type information for variables, so when it encounters dwValue it knows that it is dealing with a DWORD. The PTR directive is similar to a type-cast, in that it overrides any other type information. Remember, dwValue came with brackets for free, so they don't need to be included again.

mov dwValue, 1
; mov DWORD PTR [00403000h], 00000001h

mov BYTE PTR dwValue, 1
; mov  BYTE PTR [00403000h], 01h


Multiple type-casts are valid but the right-most overrides all others:

mov DWORD PTR [eax] + BYTE PTR [ecx], 1
; mov BYTE PTR [eax+ecx], 1


Registers and variables are different animals. Variables have an address and value. Registers have a value but no address. A register can be used as a pointer, dereferencing it's contents, while a variable cannot:

mov eax, OFFSET dwValue
; mov eax, 00403000h

mov DWORD PTR [eax], 1
; mov DWORD PTR [00403000h], 1


Note that DWORD PTR must be included in this case; since we are no longer using the variable directly, MASM no longer knows how big it is. Also, since we don't get the brackets for free with a register, they need to be included.

Hopefully this clears up some MASM inconsistencies and better explains how it interprets what we're telling it :bg

Cheers,

Zooba :U
Title: Re: upper case to lower case
Post by: PBrennick on March 05, 2006, 01:21:21 PM
Zooba,

Very nicely done.  You are a very thorough person and a good speaker.  I think that our new users should save this portion of the thread as a webpage for future referencing and hopefully Hutch will include this information in one of his excellent help files in the future.  :U

Paul
Title: Re: upper case to lower case
Post by: Mark Jones on March 05, 2006, 06:49:36 PM
If someone's gonna make this into a help file, please include TenKey's info:

Quote from: Ten-Key, old MASM forum Dec 01, 2004
The bracket notation is a legacy from the original Intel assemblers for the 8086 processors.

The brackets are used for only one purpose - to indicate that a register is being used for addressing. Everything else inside the brackets is used as-is, without any form of adjustments or indirection.

The whole thing would make a lot more sense if you were restricted to writing address operands in these forms only:

mov eax,address_expression
mov eax,address_expression[ecx]
mov eax,address_expression[ecx*4]
mov eax,address_expression[ecx+edx]
mov eax,address_expression[ecx+edx*4]
mov eax,constant_expression[ecx]
mov eax,constant_expression[ecx*4]
mov eax,constant_expression[ecx+edx]
mov eax,constant_expression[ecx+edx*4]
mov eax,[ecx]
mov eax,[ecx*4]
mov eax,[ecx+edx]
mov eax,[ecx+edx*4]

That should cover all possible addressing modes. *4 can be replaced by *1, *2, or *8. You can replace ECX and EDX with any other register. Exceptions: ESP cannot be multiplied, ESP cannot be added to ESP.

The assembler can handle these forms of address_expression:

segment_register:constant_expression
label_name
$
address_expression + constant_expression
address_expression - constant_expression
address_expression.field_name
address_expression.struct_name.field_name

(MASM 6 changed operator precedence - earlier versions allowed -5[EBP], but MASM 6 wants (-5)[EBP] or [EBP-5].)