Hi Jeremy,
Lately I have been having a bit of a change of heart and would like to change my vote to YES for run-time conditionals (that is if you're still considering it), an implementation of IF / ELSEIF / ENDIF or alternatively SWITCH / CASE would be a nice feature to add to the overall package. I can't say how often I would use it but it would be nice to have the choice for some projects.
Edgar
I've long-since wished for the option of if/else/elseif/endif and switch/case/default/endsw. But alas, it's Jeremy's call. They could make large switch blocks (and WinProcs) much clearer though, for those of us whom opted to use them.
Nice idea Edgar. That would add a great potential to GoAsm.
I would consider this if GoAsm users were in favour, but what I have always disliked is the confusion in syntax between #IF and IF and similar conditionals which do two entirely different things (the former being an assemble-time conditional and the latter a run-time conditional). I already had #IF in my resource compiler (GoRC), and so I wanted also to use it in GoAsm. Hence IF could not be considered, because of the syntax confusion issue.
SWITCH/CASE may be a possibility. It might look like this:-
WndProc FRAME hWnd, uMsg, wParam, lParam
SWITCH uMsg
CASE PAINT:
XOR EAX,EAX
RET
BREAK
CASE CREATE:
XOR EBX,EBX
RET
BREAK
CASE DESTROY:
XOR ECX,ECX
RET
BREAK
ENDSWITCH
RET
ENDF
However, I am not sure if the BREAK is needed since RET could do the same thing, making this:-
WndProc FRAME hWnd, uMsg, wParam, lParam
SWITCH uMsg
CASE PAINT:
XOR EAX,EAX
RET
CASE CREATE:
XOR EBX,EBX
RET
CASE DESTROY:
XOR ECX,ECX
RET
ENDSWITCH
RET
ENDF
I agree about BREAK, I had originally had it in my post and edited it out since it seems to be a do-nothing command simply replacing the functionality of RET, For IF/ENDIF etc.. I can only see an advantage to run time conditionals for large blocks so SWITCH/CASE fits the bill much better anyway, it is no great loss not to have IF/ENDIF.
Edgar
Or else invent a true macro system and let the users create their own macros.
Is that hard to do ?
Quote from: mitchi on March 25, 2009, 12:06:27 AM
Or else invent a true macro system and let the users create their own macros.
Is that hard to do ?
The macro system is adequate in my opinion, macros are not something I am generally in favor of and I would hate to see GoAsm go the route of MASM and be polluted with hundreds of useless, poorly documented macros. For many snippets of MASM code I have seen there is not a single assembly mnemonic with the exception of MOV. I have replied to people who downloaded some older piece of code that was infested with macros and were in search of the macro include file just to be able to assemble it, in the end many are required to reverse engineer the macro just to use the code. Also they introduce bugs and the variety of the same macro introduces ambiguity into the code base
I have nothing against creating a more powerful macro engine for GoAsm, however I think that development should concentrate on intrinsic functionality and not follow the path of MASM which has become so winding that its hard to tell if your moving forward or not. The very few macros that I find useful in MASM are already part of GoAsm, in-line quoted strings and unicode to name 2.
Edgar
I would like to see IF/ELSEIF/ENDIF and SWITCH/CASE run-time conditionals made available to those that want to use them. I don't understand why IF/ELSEIF/ENDIF could not be considered because it is implemented in the resource compiler. How would that conflict with the assembler?
Hi Greg
QuoteI don't understand why IF/ELSEIF/ENDIF could not be considered because it is implemented in the resource compiler. How would that conflict with the assembler?
Sorry if I did not make this clear.
Conditional assembly using #IF,#ELSIF,#ENDIF etc. is in GoAsm and GoRC.
To have runtime conditionals using IF,ELSIF,ENDIF etc in GoAsm is potentially confusing because it is so like #IF,#ELSIF,#ENDIF etc.
Or are you saying that this is not potentially confusing?
Hi Jeremy,
In my modest opinion, adding the runtime conditionals IF,ELSIF and ENDIF would not lead to a confusion.
Jeremy,
I don't think it would be too confusing either. In MASM there is IF (conditional assembly) and .IF (conditional control flow) and it's not too confusing.
A lack of syntactical ambiguity is a feature I like about GoAsm, though in this case I don't see much problem with separating run-time and assemble-time conditionals. However, if it is an issue there are other keywords, IF is not the only conditional keyword that can be used in this case, WHERE from SQL comes to mind...
WHERE eax = 5
ELSEWHERE eax = 6
ENDWHERE
Very clear, readable and no ambiguity.
It would seem ideal, regardless of any chosen format, to clearly delineate which is which, and/or avoid doing what MASM did in terms of .if and if. Where some may see this as a fine delineation, I see this in terms of _ArgV and __Argv -- one tiny and easily-missed character difference. (Us programmers aren't getting any younger ya know... squint squint.)
Or better yet, would it be possible to just use one syntax for all conditionals? #if,#switch,#where, etc.
I'm not suggesting anything be "dumbed-down." Only that GoASM in particular, as Donkey says, has little syntaxical ambiguity as it is, and this is a great feature IMO.
If I could get confused by #IF or .IF ?
No way, There's just no way.
Quote from: donkey on March 25, 2009, 04:53:30 AM
Quote from: mitchi on March 25, 2009, 12:06:27 AM
Or else invent a true macro system and let the users create their own macros.
Is that hard to do ?
The macro system is adequate in my opinion, macros are not something I am generally in favor of and I would hate to see GoAsm go the route of MASM and be polluted with hundreds of useless, poorly documented macros. For many snippets of MASM code I have seen there is not a single assembly mnemonic with the exception of MOV. I have replied to people who downloaded some older piece of code that was infested with macros and were in search of the macro include file just to be able to assemble it, in the end many are required to reverse engineer the macro just to use the code. Also they introduce bugs and the variety of the same macro introduces ambiguity into the code base
I have nothing against creating a more powerful macro engine for GoAsm, however I think that development should concentrate on intrinsic functionality and not follow the path of MASM which has become so winding that its hard to tell if your moving forward or not. The very few macros that I find useful in MASM are already part of GoAsm, in-line quoted strings and unicode to name 2.
Edgar
A proper macro set to do serious work is the following :
Invoke
CCall (adds esp + Numparam*4). Very useful if you work with _cdecl a lot
if /else /elseif /endif.
Proc macros
with LOCAL, arguments and stuff.
Structure macros
switch(number)
case number:
break
case
case
case
Hi mitchi,
CCall (CInvoke) from macros.a in the header project, GoAsm already handles this fine. I wrote it but don't use it myself, useless macro in my opinion, I just wrote it for others who might like this sort of thing.
#IFNDEF CInvoke
// By Donkey
CInvoke(%Function,%0,%1,%2,%3,%4,%5,%6,%7,%8,%9) MACRO
#IF ARGCOUNT = 11
push %9
#ENDIF
#IF ARGCOUNT > 9
push %8
#ENDIF
#IF ARGCOUNT > 8
push %7
#ENDIF
#IF ARGCOUNT > 7
push %6
#ENDIF
#IF ARGCOUNT > 6
push %5
#ENDIF
#IF ARGCOUNT > 5
push %4
#ENDIF
#IF ARGCOUNT > 4
push %3
#ENDIF
#IF ARGCOUNT > 3
push %2
#ENDIF
#IF ARGCOUNT > 2
push %1
#ENDIF
#IF ARGCOUNT > 1
push %0
#ENDIF
call %Function
#IF ARGCOUNT = 11
add esp,40
#ENDIF
#IF ARGCOUNT = 10
add esp,36
#ENDIF
#IF ARGCOUNT = 9
add esp,32
#ENDIF
#IF ARGCOUNT = 8
add esp,28
#ENDIF
#IF ARGCOUNT = 7
add esp,24
#ENDIF
#IF ARGCOUNT = 6
add esp,20
#ENDIF
#IF ARGCOUNT = 5
add esp,16
#ENDIF
#IF ARGCOUNT = 4
add esp,12
#ENDIF
#IF ARGCOUNT = 3
add esp,8
#ENDIF
#IF ARGCOUNT = 2
add esp,4
#ENDIF
ENDM
#ENDIF
Hi Mitchi
QuoteIf I could get confused by #IF or .IF ?
No way, There's just no way.
How about this:-
WndProc FRAME hWnd, uMsg, wParam, lParam
.IF uMsg=WM_PAINT
PAINT:
#IF VERSION=1
CALL NORMAL_PAINT
RET
#ELSE
CALL SPECIAL_PAINT
RET
#ENDIF
.IF uMsg=WM_CREATE
CREATE:
#IF VERSION=1
CALL NORMAL_CREATE
RET
#ELSE
CALL SPECIAL_CREATE
RET
#ENDIF
.ENDIF
RET
ENDF
It's fine if you wrote it yourself, but try explaining it to your friend who wants to learn assembler.
Coding with compile-time conditionals inside your code is always going to be ugly...
It's ugly in C, it's ugly in MASM, it's ugly in every language :bg
There's nothing you can do about it.
Besides, these compile time conditionals, I never use them. I see them used in Cross-platform compilers and librairies but for personal projects I have never needed any of them.
Hi Mitchi
As you can see from Edgar's example, GoAsm handles macros with arguments, and code. You can include in the macro code procedures and stuff. And GoAsm handles data in macros. You can declare a structure in a GoAsm macro too but I have no idea why anyone would want to do this since a structure is a kind of macro already (a word is used which means something else).
Is this not sufficient macro support?
Well I don't really like to play with the macro creator. I've always prefered to use the standard macros offered by the language. I generally don't use macros when I code in ASM, except for if/else. They are very well adapted to some situations. I don't have to type a label and the code is clean to read.
I'll say it again, I would like GoAsm to have a standard if / else :bg
QuoteI'll say it again, I would like GoAsm to have a standard if / else
But Mitchi, on the assumption that it is the
functionality of a runtime if/else that you want then you would be just as happy with SWITCH/CASE.
Would you be just as happy with SWITCH/CASE?
If "no" please explain why not.
The only place where IF/ELSE would be more convenient is on one-shot compares. For example the following code is a bit difficult in GoAsm..
(from Help2 Viewer)
movzx eax,W[wParam]
// Process accelerators
cmp eax,ACL_COPY
jne >>
invoke GetFocus
mov ebx,eax
invoke GetClassName,eax,offset url,1024
invoke lstrcmp,offset url,offset IEWndClass
test eax,eax
jnz >.1
CoInvoke(pIWebBrowser2,IWebBrowser2.ExecWB,OLECMDID_COPY,OLECMDEXECOPT_DODEFAULT,NULL,NULL)
jmp >>.EXIT
.1
invoke SendMessage,ebx,WM_COPY,0,0
jmp >>.EXIT
:
cmp eax,ACL_ALL
jne >
invoke GetFocus
mov ebx,eax
invoke GetClassName,eax,offset url,1024
invoke lstrcmp,offset url,offset IEWndClass
test eax,eax
jnz >.2
CoInvoke(pIWebBrowser2,IWebBrowser2.ExecWB,OLECMDID_SELECTALL,OLECMDEXECOPT_DODEFAULT,NULL,NULL)
jmp >>.EXIT
.2
invoke SendMessage,ebx,EM_SETSEL,0,-1
jmp >>.EXIT
:
As you can see the .1 and .2 are needed because at some point I had decided I didn't need to worry about labeling every case and later found that I needed to insert some conditions inside each message handler. This is handled well enough using the numbered anonymous labels but SWITCH/CASE would not save any typing..
SWITCH eax
CASE ACL_COPY:
invoke GetFocus
mov ebx,eax
invoke GetClassName,eax,offset url,1024
invoke lstrcmp,offset url,offset IEWndClass
SWITCH eax
CASE 0
invoke SendMessage,ebx,WM_COPY,0,0
jmp >>.EXIT
ENDSWITCH
CoInvoke(pIWebBrowser2,IWebBrowser2.ExecWB,OLECMDID_COPY,OLECMDEXECOPT_DODEFAULT,NULL,NULL)
jmp >>.EXIT
CASE ACL_ALL:
...
It would be clearer to have a quicky comparison operator like WHERE in addition to SWITCH/CASE
SWITCH eax
CASE ACL_COPY:
invoke GetFocus
mov ebx,eax
invoke GetClassName,eax,offset url,1024
invoke lstrcmp,offset url,offset IEWndClass
WHERE eax <> 0
invoke SendMessage,ebx,WM_COPY,0,0
ELSEWHERE
CoInvoke(pIWebBrowser2,IWebBrowser2.ExecWB,OLECMDID_COPY,OLECMDEXECOPT_DODEFAULT,NULL,NULL)
ENDW
jmp >>.EXIT
CASE ACL_ALL:
...
As I said in a previous post, IF/ENDIF does not have to be the syntax, there is no good reason to follow MASM syntax and as you said at least one good reason not to. So scrap IF/ENDIF and implement WHERE/ENDW in its place for one-shot comparisons, it makes code a bit more readable and gives one more tool for the kit.
Edgar
I really don't understand why you guys don't believe in the power of if/else. Did you never program in C ? I really believe it's convenient but maybe it's because I have a HLL background.
Switch / case will be a great addition :cheekygreen: .
How is it going to be implemented ? Jump table + lookup table for not perfect case orders OR successive conditional jumps ?
Donkey :
I don't mind your WHERE syntax. It's not standard but it looks okay.
WHERE/ELSEW/ELSE/ENDW? Provides the same functionality as if/then/else and switch/case/default with a simpler usage in my opinion. Good eye Donkey. :U
What if it accepted both types of operands? Possible, not possible? Just postulating ideas.
To quote BogdanOntanu on why this is so important
"MACRO's and .IF .ELSEIF and INVOKE and STUCT's and PROCS with ARGS and LOCALS are of the essence for modern ASM development.
Without them ASM becomes a primitive language that can be used only for a few optimizations here and there.
With them ASM becomes a powerfully language that is well above HLL languages in both simplicity and speed of development and ease of code management. I speak from my own experience of developing huge application in ASM and comparing it with a life time of professional development in HLL.
Assemblers have become powerful when they did evolved into a "macro assembler". Removing such things as .IF / .ELSEIF from assemblers means returning to the 1970 era."
the lack of .IF, .ELSEIF etc is the only thing holding me back from using GoASM, overall it seems to be very well done and the nice 64bit support is exciting, but due to the size of my existing projects in MASM I can't convert over until you provide support for .if, .elseif etc... if for some reason you decide to never add support, then thats going to signifigantly deter people from using GoASM including myself. The WHERE syntax looks ugly imo, why does this have to be so difficult, .IF works great in MASM, it beautifies everything and theres no confusion.
Quote from: mitchi on March 27, 2009, 08:16:20 PM
I really don't understand why you guys don't believe in the power of if/else. Did you never program in C ? I really believe it's convenient but maybe it's because I have a HLL background.
I have never programmed in any language other than ASM, with the exception of wading through a bit of C once to write a small PDA utility.
QuoteSwitch / case will be a great addition :cheekygreen: .
I agree
QuoteDonkey :
I don't mind your WHERE syntax. It's not standard but it looks okay.
It neatly solves the syntax issue and borrows from SQL so the keyword is still familiar and LTR readable.
Quote from: donkey on March 28, 2009, 12:26:11 AM
Quote from: mitchi on March 27, 2009, 08:16:20 PM
I really don't understand why you guys don't believe in the power of if/else. Did you never program in C ? I really believe it's convenient but maybe it's because I have a HLL background.
I have never programmed in any language other than ASM, with the exception of wading through a bit of C once to write a small PDA utility.
QuoteSwitch / case will be a great addition :cheekygreen: .
I agree
QuoteDonkey :
I don't mind your WHERE syntax. It's not standard but it looks okay.
It neatly solves the syntax issue and borrows from SQL so the keyword is still familiar and LTR readable.
How old are you ? Pure asm programmers are getting rare. Everyone starts with HLL at school these days.
I'm 47 but I am not a programmer by trade and I did not take programming in university, its just a hobby for me. ASM was the first package I ran into when I was looking for a language for my hobby, actually ran across Hiro's forum and chatted with Iczelion a bit and was convinced it was the way to go, haven't regretted it since and I have rarely found anything that could not be done in assembly language.
Actually I guess I should note that I did sell 2 commercial applications written in GoAsm, one a database program and the other a data management program, however they were so narrowly targeted I don't think there would be more than 20 potential users world-wide. (The PDA C thingy was a component of the data management program).
Edgar
I would prefer IF over WHERE. I really don't see that it's a problem.
Quote from: Greg on March 28, 2009, 02:00:06 AM
I would prefer IF over WHERE. I really don't see that it's a problem.
Well, given that the potential confusion over IF is a concern of Jeremy's and that in reality there is no good reason to choose one over the other beside making it syntactically close to MASM, I prefer WHERE. Being close in syntax to MASM is not something that I see as necessary or desirable since I rarely even look at code from that assembler anymore. As well automating the translation of source from MASM to GoAsm would be the same task regardless of the actual keyword name. Though Jeremy's example of potential confusion might have been a bit far fetched in the main body of code, it is not so unthinkable in a macro or include file where compile-time and run-time conditionals will more than likely have to co-exist, having a distinct keyword for each is preferable IMO.
Having slept on this, I came up with this.
CMP? is clearly not a mnemonic since no mnemonic would ever have a question mark.
However because of the use of "CMP", to assembler programmers it has the feel of something done at run-time, rather than during assembly.
CMP? could come in two forms, as suggested by Mark, to provide the functionality demonstrated by Edgar.
CMP? single operand would work like SWITCH. It would seem obvious that if you CMP? something with nothing, the actual comparison might be coming later.
CMP? two operands carries out the comparison immediately, like Edgar's WHERE or like IF.
So in a WndProc:-
WndProc FRAME hWnd, uMsg, wParam, lParam
CMP? uMsg ;single operand version
WM_PAINT?
;code to achieve paint
RET
WM_CREATE?
;code to achieve create
RET
ENDCMP?
RET
ENDF
And the two operand version (borrowing from Edgar's example):-
ACL_COPY?
invoke GetFocus
mov ebx,eax
invoke GetClassName,eax,offset url,1024
invoke lstrcmp,offset url,offset IEWndClass
CMP? eax,0
invoke SendMessage,ebx,WM_COPY,0,0
CMP?X
CoInvoke(pIWebBrowser2,IWebBrowser2.ExecWB,OLECMDID_COPY,OLECMDEXECOPT_DODEFAULT,NULL,NULL)
ENDCMP?
jmp >>.EXIT
ACL_ALL?
...
Hi Jeremy,
Not sure about the others but I seriously find that syntax hard to read, SWITCH/CASE by itself would be preferable though it would be nice to have an IF analog as well.
Edgar
Quote from: donkey on March 28, 2009, 08:32:09 AM
Hi Jeremy,
Not sure about the others but I seriously find that syntax hard to read, SWITCH/CASE by itself would be preferable though it would be nice to have an IF analog as well.
Edgar
I agree 100% with Edgar.
Although I don't think IF/ELSEIF/ELSE/ENDIF were a problem (they are practically used in all programming languages together with #IF/#ELSEIF/#ELSE/#ENDIF), I personally vote for SWITCH/CASE/BREAK/DEFAULT/ENDSWITCH (or even better: both). I also think the existance of BREAK would be nice because it has an advantage over using a return sentence (RET). Using BREAK would make execution to jump immediately after the SWITCH/ENDSWITCH block, which can be very useful if you need to process the code being there.
Also, I think GoAsm should have an option in the command line to activate the use of SWITCH/CASE/BREAK/DEFAULT/ENDSWITCH and IF/ELSEIF/ELSE/ENDIF (if also implemented), so that GoAsm remains working great for users which prefer to program in the traditional way and it only would be able to compile those "high level" sentences if the mentioned option was specified.
Ramon
Hi Ramon
Do you mean that in this sequence ..
RTREQUESTS FRAME Param
SWITCH Param
CASE LOVE
XOR EAX,EAX
RET
CASE CONFLICT
XOR EBX,EBX
BREAK
CASE FRUSTRATION
XOR ECX,ECX
ENDSWITCH
INJURY:
RET
ENDF
LOVE does not result in INJURY, but CONFLICT and FRUSTRATION do?
i think .if & #if can be confusing for a person just learning (from my experience).
Thing is intrinsically, .if for runtime comparisons seems the most natural (and short, compared to other conditional terms), & I guess since its usage is prevalent in many languages..people can take to it more easily
Hi Jeremy,
Yes, that's what I mean (more or less):
SWITCH <AnyVariable>
CASE LOVE
MOV EAX, IDS_LOVE
BREAK
CASE FRUSTRATION
MOV EAX, IDS_FRUSTRATION
BREAK
CASE NOTHING /* or DEFAULT */
MOV EAX, IDS_NOTHING
ENDSWITCH
INVOKE LoadString, hInst, EAX, ADDR szBuffer, MAX_PATH
INVOKE SetWindowText, hWnd, ADDR szBuffer
...
...
XOR EAX, EAX
RET
Can you please consider just adding the .if, and the .switch or select case. No ones going to be confused with .if and #if, if they are they shouldn't be programming in ASM to begin with. It's part of my job to convince customers/companies as to why ASM is a sufficient language for projects to be written in and without .if, .elseif etc which provides easy to read code(thats similar to almost all other languages) then there's no way I could convince them.
CMP? eax,0
invoke SendMessage,ebx,WM_COPY,0,0
CMP?X
CoInvoke(pIWebBrowser2,IWebBrowser2.ExecWB,OLECMDID_COPY,OLECMDEXECOPT_DODEFAULT,NULL,NULL)
ENDCMP?
that makes my head want to explode, syntax wise that's not easy to read at all
.if eax==0
invoke SendMessage,ebx,WM_COPY,0,0
.elseif X==0
CoInvoke(pIWebBrowser2,IWebBrowser2.ExecWB,OLECMDID_COPY,OLECMDEXECOPT_DODEFAULT,NULL,NULL)
.endif
that looks a lot better, if you take a look at some of icezlions old larger size projects, he uses indention and .if's quite a bit, and the code looks beautiful.
Also a way you can IMO make .IF better than masm is to make the default checks signed, for masm it requires
.if sdword ptr val > -5
.endif
the signed stuff is kind of a gotcha they don't tell you about, and can mess up code fast if you don't realize its not being looked for.
The case for SWITCH/CASE/BREAK/DEFAULT/ENDSWITCH looks good, the rest somewhat iffy... for a cleaner look and consistency, I find that the IF/ELSEIF/ELSE/ENDIF without the leading period (as in MASM) would be better.
One way to perhaps limit the potential syntax confusion would be to allow the C-like preprocessor directives only in the traditional lower case (so we have #if vs IF). Although a preference of mine (yet still relatively common), I would even go a step further and suggest require having the higher level syntax in UPPER CASE. This would provide for more uniform looking code and most likely simplify syntax highlighting within editors too.
Well my 2 quid is that the .if/.else syntax is very familar, therefore it seems "right" to want the same thing in GoASM.
I can respect Jeremy's idea for CMP?. It has a certain low-level feel to it, but does seem a little "obtuse" for lack of a better word. Of course, this may simply be because it is not as familiar as .if/.else. Personally I dispise syntaxical elements (.foo, #bar, etc.) When code starts to look like C++, I want to set it on fire. :toothy
Perhaps... another idea could be to create the necessary logic to perform these conditionals, but leave their names undefined as default. (Read: people who don't care about conditionals don't have to change a thing.) To use .if/.else syntax, specify a file on the command-line which contains the equates for these functions. (i.e., the file contents: #DEFINE ___Z36773473 = .if etc.) That way, if someone wants the conditionals to be called .if/.else, it's only a matter of selecting the appropriate file from the command-line. Likewise, definition files can be made for #if/#else, WHILE/ELSEW, or anything else the user wants to call them.
Can anyone think of any other ideas?
Well, the consensus on IF is that it would be OK and the ambiguity is something that users are willing to deal with in order to have a more standard comparative operator. I am fine with that and will drop support for the WHERE syntax. It appears that the following sums up what everybody is asking for...
note that I have never used SWITCH/CASE so I am not completely familiar with it
SWITCH var
CASE value1
CASE value2
CASE nothing // not sure what this does ???
DEFAULT (or CASE DEFAULT)
ENDSWITCH
IF eax<>0
ELSEIF eax=1
ELSE
ENDIF
The leading period would hopelessly confuse some of my older code, since I tended to use .IF/.ELSE/.ENDIF as anonymous labels. Though it is not a great task to translate it, it would be easier for me if the leading period was left out completely. Forcing upper and lower case is something I don't like much but again is not a major issue with me, some minor editing in the headers project is the most I will have to do (I use case in some headers to distinguish DIID and IID so I can search faster - mshtml.h is a good example).
Edgar
QuoteCASE nothing // not sure what this does ???
Yes Edgard, you are right. In fact, I meant "any other case", so
DEFAULT is the right word.
On the other hand, if
IF/ELSEIF/ELSE/ENDIF is going to be implemented, I'm not sure whether the leading period should be added or not. A lot of people come from Masm programming and that syntax is very familiar.
I think IF (without the leading period) would be fine. I like the SWITCH/CASE/BREAK/DEFAULT/ENDSWITCH conditionals too.
IF without the leading period is fine ! (Even better) :dance:
Quote from: Mark Jones on March 28, 2009, 08:58:21 PM
another idea could be to create the necessary logic to perform these conditionals, but leave their names undefined as default. (Read: people who don't care about conditionals don't have to change a thing.) To use .if/.else syntax, specify a file on the command-line which contains the equates for these functions. (i.e., the file contents: #DEFINE ___Z36773473 = .if etc.) That way, if someone wants the conditionals to be called .if/.else, it's only a matter of selecting the appropriate file from the command-line. Likewise, definition files can be made for #if/#else, WHILE/ELSEW, or anything else the user wants to call them.
Jeremy,
Can you just do this please, that way everyone wins, and some don't lose. It goes without precident you'll go with what donkey wants over others because he has more backing and is a big part of this project. But using this let the user specify the directive idea above is perfect.
But then if someone doesn't care about runtime conditionals and is happy with cmp/jumps, He will never see the syntax confusion between #IF and IF (or .IF).
Although somewhat easier to stick with the more familiar syntax, as for another idea along the above lines of combining the two into something new, the shortest simplest syntax I can come with is COND/ON/ENDC (or possibly DO instead of ON, also no BREAK, implied with the switch-like functionality):
WndProc FRAME hWnd, uMsg, wParam, lParam
COND uMsg
ON WM_PAINT
;code to achieve paint
ON WM_CREATE
;code to achieve create
COND eax>3
;code if >3
ON eax>1
;code if >1
ON
;other/default
ENDC
ON
;other/default
ENDC
RET
ENDF
A lovely bit of lateral thinking, Wayne.
Switch and Cond seem cool, but isn't .If more powerful ? Because the coder can specify different expressions in each comparison ?
EDIT: OK, I'm trying to migrate a project from masm to Goasm and I'm looking at a huge nested IF structure, I give up ... :toothy
I have a question for all those runtime conditionals fans!
For the sake of argument, if GoAsm were to provide a SWITCH/CASE facility, how would the high and low message components in the COMMAND and NOTIFY messages best be handled?
For example,
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)
MOV EAX,[wParam]
SWITCH AX ;switch low word of wParam
CASE MENU_1
----- code to deal with menu click with id of ID MENU_1
RET
CASE MENU_2
----- code to deal with menu click with id of ID MENU_2
RET
CASE ;or DEFAULT (menu selection not recognised)
XOR EAX,EAX ;return zero
RET
ENDSWITCH
CASE ;or DEFAULT (message is not from a menu, but from a control)
MOV EAX,[wParam]
SHR EAX,16 ;get hiword (get the control's command)
SWITCH EAX ;or AX (switch the command)
CASE BN_CLICKED
----- code to deal with button clicked
RET
CASE BN_DBCLK
----- code to deal with button double clicked
RET
CASE ;or DEFAULT (control command not recognised)
XOR EAX,EAX ;return zero
RET
ENDSWITCH
ENDSWITCH
CASE WM_CREATE
XOR EAX,EAX
RET
ENDSWITCH
RET
ENDF
Alternatively ..
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 LW[wParam] ;switch low word of wParam
CASE MENU_1
----- code to deal with menu click with id of ID MENU_1
RET
CASE MENU_2
----- code to deal with menu click with id of ID MENU_2
RET
CASE ;or DEFAULT (menu selection not recognised)
XOR EAX,EAX ;return zero
RET
ENDSWITCH
CASE ;or DEFAULT (message is not from a menu, but from a control)
SWITCH HW[wParam] ;switch the command in the high-word of wParam
CASE BN_CLICKED
----- code to deal with button clicked
RET
CASE BN_DBCLK
----- code to deal with button double clicked
RET
CASE ;or DEFAULT (control command not recognised)
XOR EAX,EAX ;return zero
RET
ENDSWITCH
ENDSWITCH
CASE WM_CREATE
XOR EAX,EAX
RET
ENDSWITCH
RET
ENDF
In the above, the default switch size is a dword, and the "switch" reference to memory/local param/local data must be in square brackets to provide somewhere to put the switch size, and which also indicates in GoAsm syntax that it is being read from memory.
I think the first is better/simpler. Comparisons against high/low parts of parameters are too rare to make it so complex, right ? But both look cool.
:green2
The first does look simpler, but the second is far more powerful! Great idea Jeremy. In WndProcs, it is almost always necessary to split the hiword and loword, so this may not be all that uncommon in practice.
I vote for the second! Looks very well!
Ramon
Second is good!
I like the second one as well.
I vote for the second. It would help C programmers to look at assembler language with more familiar eyes.
Paulo H.
I prefer the second.
Oh thanks for the responses.
Actually I've got an even better suggestion ..
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
----- code to deal with menu click with id of ID MENU_1
RET
CASE MENU_2
----- code to deal with menu click with id of ID MENU_2
RET
CASE ;or DEFAULT (menu selection not recognised)
XOR EAX,EAX ;return zero
RET
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
----- code to deal with button clicked
RET
CASE BN_DBCLK
----- code to deal with button double clicked
RET
CASE ;or DEFAULT (control command not recognised)
XOR EAX,EAX ;return zero
RET
ENDSWITCH
ENDSWITCH
CASE WM_CREATE
XOR EAX,EAX
RET
ENDSWITCH
RET
ENDF
This has the advantage of not introducing a new "type" and the +2 as addressing the high word would be obvious to assembler programmers.
I like it.
That works too, this latest variant may seem a little unfamiliar to newcomers, but fits right in with the established GoASM syntax.
About 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.
Hi Jeremy,
That one's a keeper !
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
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 ?
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.
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.
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
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.
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?
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.
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?
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.
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
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...
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.
That's right Jeremy!
How is the progress with this feature ? :bg
I was just wondering the same thing. :U
I've put this on hold for the following reasons:-
1. Users seem to be developing a preprocessor to do this work so that they can use the syntax that they themselves prefer see http://www.masm32.com/board/index.php?topic=11180.0.
2. In my message of http://www.masm32.com/board/index.php?topic=11097.msg82753#msg82753 I identified a weakness in the proposed GoAsm syntax when it was put to practical use. This has not been answered. And I must say that looking at the code there, my personal view is that it merely confuses the switching further.
3. Only a limited number of people expressed a view about the preferred GoAsm syntax.
4. No clear consensus as to the GoAsm syntax has emerged in this debate.
We all have our personal preferences, and I give mine below (table window procedure). It can be adapted easily into a dialog procedure, and also for people who like to use FRAME...ENDF.
If anyone can come up with a working, practical syntax clearer than this which gets general support, then of course I would be willing to consider adding it to GoAsm.
The Tabular Window Procedure;******************** Window message table
; (in a real program this would deal with many more messages)
DATA
MESSAGES DD (ENDOF_MESSAGES-$-4)/8 ;=number to be done
DD 1h,CREATE,2h,DESTROY,0Fh,PAINT
ENDOF_MESSAGES: ;label used to work out how many messages
;******************************************
CODE
;
;********** this is a general window procedure which in an ordinary
;********** program deals with all messages sent to the window
GENERAL_WNDPROC: ;eax can be used to convey information to the call
PUSH EBP ;use ebp to avoid using eax which may hold information
MOV EBP,[ESP+10h] ;uMsg
MOV ECX,[EDX] ;get number of messages to do
ADD EDX,4 ;jump over size dword
L2:
DEC ECX
JS >L3
CMP [EDX+ECX*8],EBP ;see if its the correct message
JNZ L2 ;no
MOV EBP,ESP
PUSH ESP,EBX,EDI,ESI ;save registers as required by Windows
ADD EBP,4 ;allow for the extra call to here
;now [EBP+8]=hwnd, [EBP+0Ch]=uMsg, [EBP+10h]=wParam, [EBP+14h]=lParam,
CALL [EDX+ECX*8+4] ;call the correct procedure for the message
POP ESI,EDI,EBX,ESP
JNC >L4 ;nc=return value in eax - don't call DefWindowProc
L3:
PUSH [ESP+18h],[ESP+18h],[ESP+18h],[ESP+18h] ;allowing for change of ESP
CALL DefWindowProcW
L4:
POP EBP
RET
;
;*******************
CREATE: ;one of the few messages dealt with by this example
XOR EAX,EAX ;return zero to make window
RET
;
DESTROY: ;one of the few messages dealt with by this example
PUSH 0
CALL PostQuitMessage ;exit via the message loop
STC ;go to DefWindowProc too
RET
;
;******************* This is the actual window procedure
MyWndProc:
MOV EDX,ADDR MESSAGES ;give edx the list of messages to deal with
CALL GENERAL_WNDPROC ;call the generic message handler
RET 10h ;restore the stack as required by caller
;
@ Jeremy
You must have an integrated de-obfuscator chip in your brain :green2 When I look at your code sample I get lost in the "asm woods".
If it had some sort of if/elseif or switch/case to get rid of the labels and nice indentation, also in Radasm with syntax colour highliting, it would be the way I like to program, hehe !
QuoteYou must have an integrated de-obfuscator chip in your brain When I look at your code sample I get lost in the "asm woods".
You don't need to understad how GENERAL_WNDPROC works. That is the same in every program. A bit like a macro. You don't change it (unless you want to use the dialog procedure version). You just call it and it's there. If you concentrate on the table of messages, the window procedure, and the calls that are made to suit each message (these are the bits which you would change) you can see that the coding is very simple.
I know you still want the switches. Please give an example of the syntax and we can see if it really is better than the above.
If using 'familiar' syntax, perhaps best not to stray too far from that usage, as well as functioning. Some re-evaluating... C does not have ENDSWITCH, default: in C uses a colon, C#/J# require the break statement after case code, and with C/C++ the break statement is optional - when not used, after doing matching case code, execution falls through to test the remaining cases which, in our case, can cause a problem if a register is used for switch and then modified within the matched case code (with further register care required when nesting).
Continuing along the lines of 'familiar' yet similar syntax, SELECT...CASE from Visual Basic would seem more flexible with the added benefit of comparison operators (=, <>, <, <=, >, or >=) for near enough IF-like support (elseif equivalent requiring nested SELECT...CASE, register care still required when nesting):
SELECT eax
CASE 0
;
CASE 1 TO 4
;
CASE 5, 7, 9 TO 15, <100
;
CASE >=[MemCmp]
;
CASE ELSE
;
ENDSELECT
The above seems reasonable with some possible minor variations:
- I have omitted the Is keyword before comparison operators
- additional short form ENDSC, so as not to conflict with ENDS for ENDSTRUCT
- how about no EXIT SELECT, possibly due to .EXIT MASM directive, and really, if you can't jmp to a label, you shouldn't be using assembly language!
- the comparison operators bring in a bit of an unsigned (MASM default) vs. signed (HLL) conflict. Tempting to go the HLL route with this HLL syntax, otherwise we start to stray with something like
SELECT SIGNED eax or SCASE.
My personal preference would generally not involve the use of this higher level syntax. I do not find it better, especially in the case of a window procedure. Also, in contrast with HLL compilers which can attempt to optimise (ex. switch using tables), the code generated here will be 'basic' since the assembler programmer expects and retains control over register usage.
I believe that the standard IF/ELSEIF/ELSE/ENDIF blocks are the most intuitive to implement and they would get my vote. As for the syntax ambiguity, GoAsm uses a # (pound) prefix for any compile time conditionals and no prefix for runtime, that should stay the same. The rules governing valid comparisons should be the same as for the CMP instruction, this would eliminate the need for register appropriation. Multiple comparisons in a single line should be separated by boolean operators, for example
IF eax = 0 AND ecx < edx
ELSEIF [MemCmp] > edi OR [MemCmp] < 200
ELSE
ENDIF
This is not ambiguous, is english readable and most if not all GoAsm programmers are already familiar with the syntax.
I also vote for IF/ELSEIF/ELSE/ENDIF.
Ramon
Agreed. Let's get these PRONTO :bg
select/case and if/elseif look good to me :thumbu
Quote from: BlackVortex on May 17, 2009, 09:17:59 PM
select/case and if/elseif look good to me :thumbu
Hi Black Vortex,
Lets just agree on IF/ENDIF, SELECT CASE and later be done with macros or preprocessors or maybe even added at a later time. For now though we need a consensus...
Quote from: donkeyI believe that the standard IF/ELSEIF/ELSE/ENDIF blocks are the most intuitive to implement and they would get my vote.
The IF/ELSEIF/ELSE/ENDIF blocks would get my vote too.
Quote from: donkey on May 17, 2009, 09:20:56 PM
Lets just agree on IF/ENDIF, SELECT CASE and later be done with macros or preprocessors or maybe even added at a later time. For now though we need a consensus...
I agree with this block and this is my vote too.
Kind regards,
PauloH
This is all very well but no one has dealt with these issues:-
- The main areas of assembler code which may be regarded as requiring simplification is the callback procedure (window, dialog, enum, DLL entry etc.).
- The flow of execution in my practical example of this using switches in this message (http://www.masm32.com/board/index.php?topic=11097.msg82753#msg82753) is not easy to follow at all.
Again, it is not clear to me (yet) that adding these switches makes anything simpler and clearer (this is why GoAsm exists).
Maybe someone can produce a new syntax to handle these callbacks which is simpler and clearer than CMP and JMP or other methods such as the tabular window procedure I referred to earlier. If so, then I am happy to consider adding it to GoAsm, but without that it is pointless to do so and contrary to the principles behind GoAsm.
Well to you it may not seem necessary because you're used to code without them. But for someone like me with a C background, It's more natural to use this structure when I code and when I think of my code.
I think it's also very readable and you don't have to type a label that is used once.
Did that convince you? :green
No it doesn't.
Please give me a full window procedure example for me to look at.
Why are you always coming back to the Windows procedure? That's something you have to write once in your app.
IF/ELSE are used everywhere.
Ok well that's my first bullet point.
1. Is it true that switches might be useful everywhere?
2. If you give the answer "yes" please prove this by giving an example of a CMP JMP switch, compared with a high level switch so I can see whether it looks any better.
Here's an example of a couple of things from TBPaint. It is a block of nested IF/ENDIF comparisons involving EAX whose value is changing within the block making it impractical for SWITCH CASE, it contains just simple comparisons however there are many routines that contain multiple comparisons per IF operator however due to time constraints I did not translate them to GoAsm...
cmp D[SkipQuery],0
jne >>.ELSE
cmp eax,[imageX]
je >>.ELSE
invoke MsgBox,[hDlg],OFFSET szDiffSize,NULL,MB_OKCANCEL,IDI_WARNING
cmp eax,IDOK
jne >
invoke ResetSize,[bmp.bmHeight],[bmp.bmHeight]
jmp >>.ENDBLOCK
:
invoke DeleteObject, [hBmp]
mov eax,-1
ret
.ELSE
invoke ResetSize, [bmp.bmHeight], [bmp.bmHeight]
.ENDBLOCK
mov eax,bmp.bmHeight
.IF SkipQuery == FALSE
.IF eax != imageX
invoke MsgBox,hDlg,OFFSET szDiffSize,NULL,MB_OKCANCEL,IDI_WARNING
.IF eax == IDOK
invoke ResetSize,bmp.bmHeight,bmp.bmHeight
.ELSE
invoke DeleteObject,hBmp
mov eax,-1
ret
.ENDIF
.ENDIF
.ELSE
invoke ResetSize,bmp.bmHeight,bmp.bmHeight
.ENDIF
The MASM code with the IF/ENDIF blocks is much easier to read and the purpose and destinations of the jumps are more evident. This is not in a window procedure, it is part of a large procedure that contains many such switches some much more complex than this one.
Note that this translation was done on the fly and isn't tested so I'm not sure its accurate.
Quote from: jorgon on May 18, 2009, 04:13:52 PM
Ok well that's my first bullet point.
1. Is it true that switches might be useful everywhere?
2. If you give the answer "yes" please prove this by giving an example of a CMP JMP switch, compared with a high level switch so I can see whether it looks any better.
1. Well yes they are used everywhere. Whenever you need IF/ELSEIF/ELSE/ LOGIC in your code you can use them. It's common programming logic and these blocks add more readability. Even if you don't believe this, you'll just have to trust me on that :D
2. I'll just use Donkey's answer :green
By the way, in the way that GoAsm was programmed, is adding IF/ELSEIF/ELSE/ a difficult task?
Yeah, if/elseif is very useful and simplifies coding, improves readability without taking away any of asm's power and flexibility. Sometimes I've looked at masm's results in a disassembler and the produced assembly looks fine.
Also, some of us are here because ml64 sucks bad (no invoke,no if/elseif anymore !) and we need a good winAPI-oriented assembler for the 64bit future, like goasm.
I've checked all(?) other 64bit capable assemblers and I didn't like their syntax or they are too OS-abstract.
What about this?
MyWndProc FRAME hWnd, uMsg, wParam, lParam
IF uMsg == WM_CREATE
;Write code here
ELSEIF uMsg == WM_COMMAND
;Write code here
ELSEIF uMsg == WM_DESTROY
;Write code here
ENDIF
INVOKE DefWindowProc, hWnd, uMsg, wParam, lParam
RET
ENDF
All messages might have a RET sentence for no further processing. If not, the 'DeWindowProc' function would be called instead.
Jeremy, first let me say that I love GoASM. It is powerful and concise. However, while the "raw-ness" of coding conditional jumps by hand sometimes provides additional flexibility or capability, I find modifying large conditional blocks to be very unweildy. Take something like this for instance:
Tab1Proc FRAME hWin,uMsg,wParam,lParam
mov eax,d[uMsg]
cmp eax,WM_INITDIALOG
jne >>.WM_CREATE
; Put code in here....................
jmp >>.EXIT
.WM_CREATE
cmp eax,WM_CREATE
jne >>.WM_COMMAND
;
jmp >>.EXIT
.WM_COMMAND
cmp eax,WM_COMMAND
jne >>.WM_DESTROY
;
jmp >>.EXIT
.WM_DESTROY
cmp eax,WM_DESTROY
jne >>.DEFAULT
;
.DEFAULT
mov eax,FALSE
ret
.EXIT
mov eax,TRUE
ret
ENDF
Now say one wanted to add another "switch" to this, in the middle somewhere, for say WM_PAINT. The current process requires defining a new local jump ".LABEL", renaming the previous jump destination to this new label, creating the new conditon test code, and creating the code to jump to the next label. Move this block out-of-order or make a mistake in any jump targets and presto: a hard-to-spot bug. Often, if the order has to be completely changed, it is simpler and faster just to code a new WndProc rather than try to fixup all the jumps.
I can't speak for anyone else, but when I'm juggling a hundred other things in my head during program creation, it sure would be simpler and shorter to type something like this:
Tab1Proc FRAME hWin,uMsg,wParam,lParam
switch d[uMsg]
case WM_INITDIALOG
; Put code in here....................
case WM_CREATE
;
; whoa, we need to process paint messages now! new condition here:
case WM_PAINT
;
case WM_COMMAND
;
case WM_DESTROY
;
default
mov eax,FALSE
ret
endsw
mov eax,TRUE
ret
ENDF
Although, I do agree that conditionals have a limited application---mostly in window procedures, but they also could be very handy in code such as this (http://www.masm32.com/board/index.php?topic=1891.msg58065#msg58065) for rapid development. A ton of conditionals are used in that code and it really helps to speed up development. After the code is working, then care can be taken to optimize specific jumps, if necessary. I would wager that the vast majority of us know not to use HLL-conditionals in a speed-critical algorithm.
Alas, on the other hand, I agree that GoASM should not be turned into Turbo-Basic-On-Crack. :P However again, as long as any conditional syntax remained completely optional and transparent, then the die-hard tape-punchers out there should remain happily indifferent, or at least not moan very much. :bg
Ok I do see that GoAsm would be improved by the addition of both IF/ELSE/ENDIF and SWITCH/CASE.
My concern about IF/ELSE/ENDIF being confused with #IF/#ELSE/#ENDIF has been dispelled by this debate. I was also hoping that one syntax form might replace both IF/ELSE/ENDIF and SWITCH/CASE, or that we might find a better syntax but despite your efforts this didn't happen.
Having switched my view, I'm on the case, but give me a while and in the end it will be done (sorry, puns intended).
This is good, While my preprocessor seems to work well and gives the flexibility of changing the syntax when you like, the extra temp files generated is kind of annoying, and it'll be nice to have this support built right in.
Quote from: jorgon on May 24, 2009, 07:12:42 AM
Having switched my view, I'm on the case, but give me a while and in the end it will be done (sorry, puns intended).
Ambitious program! On [condition] Gosub proc1, proc2... ok, that one I understood. But what is done? ExitProcess?
:wink
/me dances around
:boohoo: :cheekygreen:
Quote from: jorgon on May 24, 2009, 07:12:42 AM
My concern about IF/ELSE/ENDIF being confused with #IF/#ELSE/#ENDIF has been dispelled by this debate. I was also hoping that one syntax form might replace both IF/ELSE/ENDIF and SWITCH/CASE, or that we might find a better syntax but despite your efforts this didn't happen.
Perhaps like (I believe Donkey) had said earlier, the simpler syntax is always easier to understand. I commend you on trying to find one unifying solution however. Since the header syntax is close to C's, it seems logical that the assemble-time variants would be prefixed by #'s i.e. #IF/#ELSE/#ENDIF/#SWITCH/#CASE etc. As for the run-time conditional syntax, that is still open to interpretation. The base functionality is the same regardless of what the instructions are called (IF==SWITCH, ELSEIF==CASE, ENDIF==ENDSW, etc.) :bg
With IF confusion dispelled, between the two I would lean towards IF/ELSEIF/ELSE/ENDIF which has a slightly lower level feel to it (unsigned comparisons as the default... IFS/ELSEIFS/ELSE/ENDIF for signed?). With higher level language CASE variations and without the more advanced compiler-like output (giving functionality similar to IF) I would say that CASE does not fit in as well.
The repetition in Ramon Sala's IF/ELSE/ENDIF WndProc example a bit earlier stood out... in another unifying attempt, instead of the longer ELSEIF expecting a full expression, how about also having a shorter ELIF with just a VALUE, compared as in the initial IF (or possible previous longer ELSEIF):
MyWndProc FRAME hWnd, uMsg, wParam, lParam
mov eax,[uMsg]
IF eax == WM_CREATE
;Write code here
ELIF WM_COMMAND
;Write code here
ELIF WM_DESTROY
;Write code here
ENDIF
INVOKE DefWindowProc, hWnd, uMsg, wParam, lParam
RET
ENDF
the operators can be chosen for signed/unsigned
the if...endif can remain uniform
Quote from: wjr on May 26, 2009, 12:09:56 AM
instead of the longer ELSEIF expecting a full expression, how about also having a shorter ELIF with just a VALUE, compared as in the initial IF (or possible previous longer ELSEIF):
Masm doesn't distinguish between full expressions and "just a value":
.if eax==123
print chr$("Masm32 is simpler than you thought, right?"), 13, 10
.elseif WM_COMMAND
print chr$("Yeah, that's true ;-", 41), 13, 10
.endif
Any progress ?
I have wet dreams about win7 64bit + 64bit programming + runtime conditionals
Hoping this gets implemented soon, trying to further my learning after the Bill Aitken's tutorials and am having trouble with tutorials that use conditionals so am stalling til than.
I know I've been away for a while, mostly due to school but also because the bulk of my work lately has been centered around GNU/Linux. As most of you might remember I've never really been a fan of the if/endif style coding myself (even though NASM32 has always supported it). But what I think would be much more interesting for GoASM in the line of a conditional system would be a built-in wrapper for call-table comparison using SWITCH/CASE or SELECT/OPTION. For example:
SELECT [uMsg]
OPTION WM_CREATE, OnCreate
OPTION WM_PAINT, OnPaint
OPTION WM_CHAR, OnChar
DEFAULT OnUnknown
ENDSELECT
...
OnCreate:
...
OnPaint:
...
OnChar:
...
OnUnknown:
...
Then have it expand to something like this:
CONST SECTION
GENERATED_TABLE_NAME:
DD WM_CREATE, OnCreate
DD WM_PAINT, OnPaint
DD WM_CHAR, OnChar
CODE SECTION
PUSH Eax, Ecx, Edx
MOV Eax, [uMsg]
MOV Ecx, SIZEOF GENERATED_TABLE_NAME / 8
MOV Edx, ADDR GENERATED_TABLE_NAME
:
DEC Ecx
JS >
CMP [Edx + Ecx * 8], Eax
JNE <
CALL [Edx + Ecx * 8 + 4]
JNC >.TEMP_ENDSWITCH
:
CALL OnUnknown
.TEMP_ENDSWITCH:
POP Edx, Ecx, Eax
...
OnCreate:
...
OnPaint:
...
OnChar:
...
OnUnknown:
...
I used the generic WM_* handler in the above example, but I actually use this style of call-table comparison a lot since it expands better to larger numbers of comparisons than your basic CMP/Jcc. For simple If/Else/Endif is it really so hard to use CMP/Jcc style comparisons? I personally think if you were to create an internal directive for doing comparison's it should probably be something like the above where the user of the directive is likely to be preforming a mass number of comparisons and the directives would not only increase basic readability but improve the output code performance. That's just my two cents. :)
Regards,
Bryant Keller
Quote from: Yusuf on July 25, 2009, 10:48:42 PM
Hoping this gets implemented soon, trying to further my learning after the Bill Aitken's tutorials and am having trouble with tutorials that use conditionals so am stalling til than.
From my own experience, I confirm that the lack of if/else is a real difficulty at first. But later you find the way to do without, and now I am rather reluctant to use them (to my own surprise).
I personally would recommend to start learning assembly without all those obfuscating facilities, even only to understand how all this is done in reality, what actually is behind ifs and elses.
I always disassemble my exes to see how the runtime conditionals (in masm), the frames/procs, the invokes etc get implemented. Also, I like looking at the imports, the header and linker-related stuff.
i only use conditionals for library functions
i used to use them so code could be assembled for different memory models
well - don't need that anymore with 32-bit code - lol
i have a hard time reading some code because of all the if thens
it looks too much like a C program, which is something i try to avoid
when you write it yourself, you get to choose how it is structured so that
the cases that occur most often go through the least amount of branching
Quote from: dedndave on July 26, 2009, 11:53:24 PM
i have a hard time reading some code because of all the if thens
it looks too much like a C program
Errm ? It doesn't look like C, it looks like Masm, you know, the macro assembler ! :wink
cmp,test and jcc look like disassembly :bdg
lol - it's cool - i work my way through it
usually, i only need to understand a small portion, and i only need it once
i am just old-school (i think that means the same as stubborn, right ?)
i think we all tend to resist change and our preference leans toward the first-learned
well, at least i am not writing ML code in hex - lol
Quote from: BlackVortex on July 28, 2009, 01:16:24 PM
Quote from: dedndave on July 26, 2009, 11:53:24 PM
i have a hard time reading some code because of all the if thens
it looks too much like a C program
Errm ? It doesn't look like C, it looks like Masm, you know, the macro assembler ! :wink
Can't help it but to me all this if/else and while and repeat and switch/case stuff looks like good ol' BASIC ::)
lol - i remember Basic - - - version 3 i think i had
i still have ms basic compiler v 1.0 in the drawer - lol
this machine has no floppy drives - dang
hafta fire up one of my old machines
i don't even know wth you are talking about with "switch/case stuff" :lol
Quote from: dedndave on July 28, 2009, 03:18:24 PM
i don't even know wth you are talking about with "switch/case stuff" :lol
Masm:
SWITCH uMsg
CASE WM_COMMAND
mov ecx, lParam
CASE WM_WINDOWPOSCHANGED
mov ecx, 123
ENDSW
GfaBasic:
SWITCH MENU(0)
CASE 1001
DoStuff
CASE whatever
DoOtherStuff
ENDSWITCH
it looks like Greek, to me, bro :eek
must have something to do with cases - lol
http://en.wikipedia.org/wiki/Switch_statement
Quote from: MichaelW on July 28, 2009, 06:47:59 PM
http://en.wikipedia.org/wiki/Switch_statement
Strange how many times they have to repeat that language X does not "support" fall-through behaviour. It would have been easier to say that only a handful of C dialects are infected with this horrible disease...