News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Runtime conditionals

Started by donkey, March 24, 2009, 11:15:42 AM

Previous topic - Next topic

donkey

Hi Jeremy,

That one's a keeper !
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

jorgon

QuoteAbout the only thing I can think of at the moment would be to detect if a previous CASE statement has been followed (and if it has, break out), saving the RET in each branch.

So removing the RET and adding calls to other areas of code, which might be done in practice, that would make the sequence:-

WndProc FRAME hWnd, uMsg, wParam, lParam
SWITCH [uMsg]
CASE WM COMMAND
     SWITCH [lParam]             ;switch the handle of thing sending message
     CASE 0                      ;do next if message is from a menu (zero)
           SWITCH W[wParam]      ;switch low word of wParam
           CASE MENU_1
           CALL DEALWITH_MENU1   ;code to deal with menu click with id of MENU_1
           CASE MENU_2
           CALL DEALWITH_MENU2   ;code to deal with menu click with id of MENU_2
           CASE                  ;or DEFAULT (menu selection not recognised)
           XOR EAX,EAX           ;return zero
           ENDSWITCH
     CASE                        ;or DEFAULT (message is not from a menu, but from a control)
           SWITCH W[wParam+2]    ;switch the command in the high-word of wParam
           CASE BN_CLICKED
           CALL DEALWITH_CLICKED ;code to deal with button clicked
           CASE BN_DBCLK
           CALL DEALWITH_DBCLK   ;code to deal with button double clicked
           CASE                  ;or DEFAULT (control command not recognised)
           XOR EAX,EAX           ;return zero
           ENDSWITCH
     ENDSWITCH
CASE WM_CREATE
     CALL DEALWITH_CREATE
ENDSWITCH
RET
ENDF


GoAsm might not require a new line after each CASE statement so this becomes:-

WndProc FRAME hWnd, uMsg, wParam, lParam
SWITCH [uMsg]
CASE WM COMMAND
     SWITCH [lParam]             ;switch the handle of thing sending message
     CASE 0                      ;do next if message is from a menu (zero)
           SWITCH W[wParam]      ;switch low word of wParam
           CASE MENU_1 CALL DEALWITH_MENU1   ;code to deal with menu click with id of MENU_1
           CASE MENU_2 CALL DEALWITH_MENU2   ;code to deal with menu click with id of MENU_2
           CASE                  ;or DEFAULT (menu selection not recognised)
           XOR EAX,EAX           ;return zero
           ENDSWITCH
     CASE                        ;or DEFAULT (message is not from a menu, but from a control)
           SWITCH W[wParam+2]    ;switch the command in the high-word of wParam
           CASE BN_CLICKED CALL DEALWITH_CLICKED ;code to deal with button clicked
           CASE BN_DBCLK CALL DEALWITH_DBCLK     ;code to deal with button double clicked
           CASE                  ;or DEFAULT (control command not recognised)
           XOR EAX,EAX           ;return zero
           ENDSWITCH
     ENDSWITCH
CASE WM_CREATE CALL DEALWITH_CREATE
ENDSWITCH
RET
ENDF


Or even:-

WndProc FRAME hWnd, uMsg, wParam, lParam
SWITCH [uMsg]
CASE WM COMMAND
     SWITCH [lParam]             ;switch the handle of thing sending message
     CASE 0                      ;do next if message is from a menu (zero)
           SWITCH W[wParam]      ;switch low word of wParam
           CASE MENU_1 DEALWITH_MENU1   ;code to deal with menu click with id of MENU_1
           CASE MENU_2 DEALWITH_MENU2   ;code to deal with menu click with id of MENU_2
           CASE                  ;or DEFAULT (menu selection not recognised)
           XOR EAX,EAX           ;return zero
           ENDSWITCH
     CASE                        ;or DEFAULT (message is not from a menu, but from a control)
           SWITCH W[wParam+2]    ;switch the command in the high-word of wParam
           CASE BN_CLICKED DEALWITH_CLICKED   ;code to deal with button clicked
           CASE BN_DBCLK   DEALWITH_DBCLK     ;code to deal with button double clicked
           CASE                  ;or DEFAULT (control command not recognised)
           XOR EAX,EAX           ;return zero
           ENDSWITCH
     ENDSWITCH
CASE WM_CREATE DEALWITH_CREATE
ENDSWITCH
RET
ENDF


Author of the "Go" tools (GoAsm, GoLink, GoRC, GoBug)

mitchi

This is how I would use it at home :
WndProc FRAME hWnd, uMsg, wParam, lParam

SWITCH [uMsg]
CASE WM COMMAND 
     SWITCH [lParam]             ;switch the handle of thing sending message
     CASE 0                      ;do next if message is from a menu (zero)
           SWITCH W[wParam]      ;switch low word of wParam
            CASE MENU_1
            CALL DEALWITH_MENU1   ;code to deal with menu click with id of MENU_1
            CASE MENU_2
          CALL DEALWITH_MENU2   ;code to deal with menu click with id of MENU_2
            CASE                  ;or DEFAULT (menu selection not recognised)
            XOR EAX,EAX           ;return zero
           ENDSWITCH
     CASE                        ;or DEFAULT (message is not from a menu, but from a control)
           SWITCH W[wParam+2]    ;switch the command in the high-word of wParam
            CASE BN_CLICKED
            CALL DEALWITH_CLICKED ;code to deal with button clicked
            CASE BN_DBCLK
            CALL DEALWITH_DBCLK   ;code to deal with button double clicked
            CASE                  ;or DEFAULT (control command not recognised)
            XOR EAX,EAX           ;return zero
           ENDSWITCH
     ENDSWITCH
CASE WM_CREATE
     CALL DEALWITH_CREATE
ENDSWITCH
RET
ENDF


I just added indentation, being a fan of the switch in C.
By the way, a few questions : What happened to the break statement ? Do we have to specify it?
Also, are you planning to implement this with a jump table or with runtime conditionals ?

jorgon

Hi Mitchi

I tried to add identation using spaces, but obviously failed!  This time I will try "preformatted text".

I have two more questions.

Firstly, I've been concentrating on the returns from the SWITCH/CASE blocks, and I wonder if there is a weakness in the syntax because it is not clear when coming out of a nested SWITCH/CASE block where execution should continue.  Looking at the code below, the returns from the DEALWITH_MENU1 and DEALWITH_MENU2 calls are executed in line 18.  However, it is not obvious that the returns from the DEALWITH_CLICKED and DEALWITH_DBCLK calls could be executed in line 28 if desired, but in fact end up at the code label .zero because there is no code on line 28 there (only another ENDSWITCH).  Maybe I don't find this clear because I am not used to SWITCH/CASE.  Is it clear to the fans of SWITCH/CASE?  In line 9 on the CREATE message execution simply continues at the lable .zero.  This is more obvious to me since this is in the first SWITCH/CASE block.  I would propose that it is possible to manipulate the place where execution continues by using for example:-
ENDSWITCH >.zero
The second question is whether people like the enhancements to CASE, for example on lines 16 and 26 which provides a simple way to deal with the default case, and line 21 which can deal simply with a specified comparison. 

;
1.  SwitchWndProc FRAME hwnd,uMsg,wParam,lParam     ;establish stack frame and get parameters
2.  LOCAL hRgn
3.  ;
4.  SWITCH [uMsg]
5.  CASE WM_DESTROY
6.   PUSH [hRgn]
7.   CALL DeleteObject
8.    JMP >.def
9.  CASE WM_CREATE
10. CASE WM_COMMAND
11.   SWITCH W[wParam+2]    ;switch the high word of wParam
12.   CASE 0                ;do next if its a menu command
13.      SWITCH W[wParam]   ;switch the menu ids (in loword)
14.      CASE MENU_ID1 DEALWITH_MENU1
15.      CASE MENU_ID2 DEALWITH_MENU2
16.      CASE >.def         ;if menu id not processed, pass to system
17.      ENDSWITCH
18.      JNC >.zero         ;successful return from DEALWITH_MENU1/2
19.      CALL RECORD_ERROR
20.      JMP >.zero   
21.   CASE 1 >.def          ;if its an accelerator just pass message on to system
22.   CASE                  ;do next if its a notification code from a control
23.      SWITCH W[wParam]   ;switch the notification code (in loword)
24.      CASE BN_CLICKED DEALWITH_CLICKED
25.      CASE BN_DBCLK   DEALWITH_DBCLK
26.      CASE >.def         ;if notification code not processed, pass to system
27.      ENDSWITCH
28.   ENDSWITCH
29. CASE WM_PAINT DEALWITH_PAINT
30. ENDSWITCH
31. .zero:
32. XOR EAX,EAX
33. JMP >.exit
34. .def:
35. INVOKE DefWindowProcW,[hwnd],[uMsg],[wParam],[lParam]
36. .exit:
37. RET
38. ;
39. DEALWITH_MENU1:
40. RETN
41. ;
42. DEALWITH_MENU2:
43. RETN
44. ;
45. DEALWITH_CLICKED:
46. RETN
47. ;
48. DEALWITH_DBCLK:
49. RETN
50. ;
51. DEALWITH_PAINT:
52. RETN
53. ;
54. ENDF         ;finish this stack frame


To answer your questions Mitchi, the break statement seems to have disappeared.  Is it any use in the above scenario (or any other scenario)?
As for the implementation of all this, it seems to me it is best done by a jump table created after each ENDSWITCH.

Author of the "Go" tools (GoAsm, GoLink, GoRC, GoBug)

mitchi

OK I see. If you are going to use a jump table, you might want to see how Visual C++ handles unordered CASES

Example of ordered cases :
CASE 0
CASE 1
CASE 3
CASE 4

(Very easy to make a jump table for)

Example of unordered cases:
CASE 0
CASE 100
CASE 230
CASE 314

I wrote a text that shows how Visual C++ deals with this (an additional lookup table is used)
http://mitchi.u7n.org/the-switch.html
move to the "Not-perfect case orders" section at the end.

BlackVortex

What happened ?  I don't understand anything in the last code sample Jeremy posted. And what's with all the labels again ?    :naughty:

Or are those optional for "empty" cases ? As usual, too much talk overcomplicates things.    :toothy

jorgon

Mitchi

Interesting article, thanks for that.

Actually I think it would be easier to use a compare/jump block of instructions for example

CMP XXXX,aaaa
JZ zzzz
CMP XXXX,bbbb
JZ zzzz


One reason is that GoAsm doesn't have the luxory of using registers easily in the code construct, because the user might be using them to hold information.

Author of the "Go" tools (GoAsm, GoLink, GoRC, GoBug)

jorgon

Hi BlackVortex

QuoteWhat happened ?  I don't understand anything in the last code sample Jeremy posted. And what's with all the labels again ?   
Or are those optional for "empty" cases ? As usual, too much talk overcomplicates things.

What is your preferred SWITCH/CASE source coding for that WndProc?

Author of the "Go" tools (GoAsm, GoLink, GoRC, GoBug)

BlackVortex

Quote from: jorgon on April 05, 2009, 07:40:48 AM
Hi BlackVortex

QuoteWhat happened ?  I don't understand anything in the last code sample Jeremy posted. And what's with all the labels again ?   
Or are those optional for "empty" cases ? As usual, too much talk overcomplicates things.

What is your preferred SWITCH/CASE source coding for that WndProc?


Something like your example in the last page (reply #49 of this thread).  Actually anything that doesn't have labels/jumps ! Just standard (nested if needed) hll constructs.

jorgon

Yes, but in an ordinary window procedure you will have to call DefWindowProc with the messages that are not dealt with in your window procedure and also with some of those which are dealt with.  How would your preferred syntax deal with whether or not to call DefWindowProc?

Author of the "Go" tools (GoAsm, GoLink, GoRC, GoBug)

BlackVortex

Quote from: jorgon on April 05, 2009, 01:21:52 PM
Yes, but in an ordinary window procedure you will have to call DefWindowProc with the messages that are not dealt with in your window procedure and also with some of those which are dealt with.  How would your preferred syntax deal with whether or not to call DefWindowProc?


Hmmm, now that I look at it again, I just got disheartened by the different menu-handling proc you created. I would put those inside the switch/case and I'd make one call/proc for the invoke DefWindowProc.

Roger

Hi All,

Why is it that as soon as a simple assembler appears, there follows incessant demands for it to be spoilt by adding unnecessary high level constructs?

GoAsm is different to Masm. Thus if Masm has a particular favorite method, use it, don't try to change GoAsm into a Masm clone and ruin it for everyone else.

If in the end you want the advantages of GoAsm but cannot live without some specific syntactic quirk then write a pre-processor which takes your obfuscated outpourings and converts them into basic assembler mnemonics that everyone and his assembler can understand. This way GoAsm can retain its elegance and simplicity.

GoAsm isn't broken - it doesn't need fixing.

Regards Roger

Mark Jones

No, it doesn't need fixing Roger. I sort-of agree, at least with the part about others wanting to make it into a MASM clone. GoASM is fine the way it is, and should not be made to work like MASM just for the sake of "compatibility." Still, adding the option of such basic HLL-like features as switch/case is useful to many people, simply for the fact that it greatly tidies up code. (The RadASM IDE also supports code-folding, so conditional branches can be "folded" to make the listing even more brief.)

But alas, how would such an addition affect you? If its use is optional...
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

BlackVortex

What do you mean, Roger, we're trying to turn this into a masm clone ?  Any solution for runtime conditional stuff is fine, noone said it has to be similar to masm.


Ramon Sala

Greetings from Catalonia