Assembly code snippets
Details
Title | .switch / .case / .endswitch |
---|---|
Author | QvasiModo |
Submitted by: | QvasiModo |
Date added: | 2003-08-04 20:36:39 |
Date modified: | 2003-08-04 20:36:39 |
Comments
This is another example on how to implement switch macros using the built-it masm macros .if/.elseif/.endif.
Snippet
;this macros are for switch/case support (similar to C)
; mov eax,uMsg
; .switch eax
; .case WM_COMMAND
; (...)
; .break
; .case WM_NOTIFY
; (...)
; .break
; .default
; (...)
; .endswitch
; .switch {register or variable}
.switch macro regname:req
ifndef SwitchNesting
SwitchNesting = 1
else
SwitchNesting = SwitchNesting + 1
endif
@CatStr ( <SwitchRegister_>, %SwitchNesting ) textequ <®name&>
@CatStr ( <SwitchFirstCase_>, %SwitchNesting ) = 1
@CatStr ( <SwitchLastCase_>, %SwitchNesting ) = 0
@CatStr ( <SwitchNeedDefault_>, %SwitchNesting ) = 0
.repeat
endm
; .case {value 1}, [value 2], (...), [value n]
.case macro var:vararg
local value,isfirst,cond
ifndef SwitchNesting
.err <.case cannot be outside of a .switch/.endswitch block.>
exitm
endif
if SwitchNesting lt 1
.err <Bad .switch/.endswitch block.>
exitm
endif
ife @CatStr ( <SwitchLastCase_>, %SwitchNesting )
ife @CatStr ( <SwitchFirstCase_>, %SwitchNesting )
.endif
else
@CatStr ( <SwitchFirstCase_>, %SwitchNesting ) = 0
endif
isfirst = 1
for value, <var>
if isfirst ne 0
cond catstr <( SwitchRegister_>, %SwitchNesting, < == &value& )>
isfirst = 0
else
cond textequ @CatStr ( %cond, < || ( SwitchRegister_>, %SwitchNesting, < == >, <&value&>, < )> )
endif
endm
if isfirst eq 0
.if cond
endif
else
.err <.case cannot follow .default.>
endif
endm
; .between {min 1}, {max 1}, [min 2], [max 2], (...), [min n], [max n]
; values must always be given in pairs
.between macro var:vararg
local value,isfirst,iseven,cond,cond2
ifndef SwitchNesting
.err <.between cannot be outside of a .switch/.endswitch block.>
exitm
endif
if SwitchNesting lt 1
.err <Bad .switch/.endswitch block.>
exitm
endif
ife @CatStr ( <SwitchLastCase_>, %SwitchNesting )
ife @CatStr ( <SwitchFirstCase_>, %SwitchNesting )
.endif
else
@CatStr ( <SwitchFirstCase_>, %SwitchNesting ) = 0
endif
isfirst = 1
iseven = 1
for value, <var>
if isfirst ne 0
;( ( reg >= value )
cond catstr <( ( SwitchRegister_>, %SwitchNesting, < !>= &value& )>
isfirst = 0
else
if iseven eq 1
; || ( ( reg >= value )
cond2 catstr <cond>, < || ( ( SwitchRegister_>, %SwitchNesting, < !>= &value& )>
cond textequ cond2
else
; && ( reg <= value ) )
cond2 catstr <cond>, < && ( SwitchRegister_>, %SwitchNesting, < !<= &value& ) )>
cond textequ cond2
endif
endif
iseven = -iseven
endm
if isfirst eq 0
.if cond
endif
else
.err <.between cannot follow .default.>
endif
endm
; .caseif {condition}
; The condition must be a text literal to be passed to the .if macro.
; Remember to escape angle brackets with an exclamation point.
.caseif macro cond:req
ifndef SwitchNesting
.err <.caseif cannot be outside of a .switch/.endswitch block.>
exitm
endif
if SwitchNesting lt 1
.err <Bad .switch/.endswitch block.>
exitm
endif
ife @CatStr ( <SwitchLastCase_>, %SwitchNesting )
ife @CatStr ( <SwitchFirstCase_>, %SwitchNesting )
.endif
else
@CatStr ( <SwitchFirstCase_>, %SwitchNesting ) = 0
endif
.if cond
else
.err <.caseif cannot follow .default.>
endif
endm
.default macro
ifndef SwitchNesting
.err <.default cannot be outside of a .switch/.endswitch block.>
exitm
endif
if SwitchNesting lt 1
.err <Bad .switch/.endswitch block.>
exitm
endif
ifndef SwitchCount
SwitchCount = 0
endif
ife @CatStr ( <SwitchLastCase_>, %SwitchNesting )
ife @CatStr ( <SwitchFirstCase_>, %SwitchNesting )
.endif
else
.err <There should be at least one .case before .default.>
endif
@CatStr ( <SwitchLastCase_>, %SwitchNesting ) = 1
else
.err <There cannot be more that one .default in a .switch/.endswitch block.>
endif
@CatStr ( <SwitchNeedDefault_>, %SwitchNesting ) = 0
@CatStr ( <SwitchLastCase_>, %SwitchNesting ) = 1
@CatStr ( <SwitchDefault_>, %SwitchCount, <:> )
SwitchCount = SwitchCount + 1
endm
.breakdef macro
ifndef SwitchNesting
.err <.breakdef cannot be outside of a .switch/.endswitch block.>
exitm
endif
if SwitchNesting lt 1
.err <Bad .switch/.endswitch block.>
exitm
endif
ifndef SwitchCount
SwitchCount = 0
endif
@CatStr ( <SwitchNeedDefault_>, %SwitchNesting ) = 1
jmp @CatStr ( <SwitchDefault_>, %SwitchCount )
endm
.endswitch macro
if SwitchNesting lt 1
.err <Bad .switch/.endswitch block.>
exitm
endif
ife @CatStr ( <SwitchFirstCase_>, %SwitchNesting )
ife @CatStr ( <SwitchLastCase_>, %SwitchNesting )
.endif
endif
else
.err <Empty .switch/.endswitch block?>
endif
if @CatStr ( <SwitchNeedDefault_>, %SwitchNesting ) ne 0
.err <Unmatched .breakdef, could branch to unexpected location!>
endif
.until TRUE
SwitchNesting = SwitchNesting - 1
if SwitchNesting lt 0
.err <Bad .switch/.endswitch block.>
endif
endm
; mov eax,uMsg
; .switch eax
; .case WM_COMMAND
; (...)
; .break
; .case WM_NOTIFY
; (...)
; .break
; .default
; (...)
; .endswitch
; .switch {register or variable}
.switch macro regname:req
ifndef SwitchNesting
SwitchNesting = 1
else
SwitchNesting = SwitchNesting + 1
endif
@CatStr ( <SwitchRegister_>, %SwitchNesting ) textequ <®name&>
@CatStr ( <SwitchFirstCase_>, %SwitchNesting ) = 1
@CatStr ( <SwitchLastCase_>, %SwitchNesting ) = 0
@CatStr ( <SwitchNeedDefault_>, %SwitchNesting ) = 0
.repeat
endm
; .case {value 1}, [value 2], (...), [value n]
.case macro var:vararg
local value,isfirst,cond
ifndef SwitchNesting
.err <.case cannot be outside of a .switch/.endswitch block.>
exitm
endif
if SwitchNesting lt 1
.err <Bad .switch/.endswitch block.>
exitm
endif
ife @CatStr ( <SwitchLastCase_>, %SwitchNesting )
ife @CatStr ( <SwitchFirstCase_>, %SwitchNesting )
.endif
else
@CatStr ( <SwitchFirstCase_>, %SwitchNesting ) = 0
endif
isfirst = 1
for value, <var>
if isfirst ne 0
cond catstr <( SwitchRegister_>, %SwitchNesting, < == &value& )>
isfirst = 0
else
cond textequ @CatStr ( %cond, < || ( SwitchRegister_>, %SwitchNesting, < == >, <&value&>, < )> )
endif
endm
if isfirst eq 0
.if cond
endif
else
.err <.case cannot follow .default.>
endif
endm
; .between {min 1}, {max 1}, [min 2], [max 2], (...), [min n], [max n]
; values must always be given in pairs
.between macro var:vararg
local value,isfirst,iseven,cond,cond2
ifndef SwitchNesting
.err <.between cannot be outside of a .switch/.endswitch block.>
exitm
endif
if SwitchNesting lt 1
.err <Bad .switch/.endswitch block.>
exitm
endif
ife @CatStr ( <SwitchLastCase_>, %SwitchNesting )
ife @CatStr ( <SwitchFirstCase_>, %SwitchNesting )
.endif
else
@CatStr ( <SwitchFirstCase_>, %SwitchNesting ) = 0
endif
isfirst = 1
iseven = 1
for value, <var>
if isfirst ne 0
;( ( reg >= value )
cond catstr <( ( SwitchRegister_>, %SwitchNesting, < !>= &value& )>
isfirst = 0
else
if iseven eq 1
; || ( ( reg >= value )
cond2 catstr <cond>, < || ( ( SwitchRegister_>, %SwitchNesting, < !>= &value& )>
cond textequ cond2
else
; && ( reg <= value ) )
cond2 catstr <cond>, < && ( SwitchRegister_>, %SwitchNesting, < !<= &value& ) )>
cond textequ cond2
endif
endif
iseven = -iseven
endm
if isfirst eq 0
.if cond
endif
else
.err <.between cannot follow .default.>
endif
endm
; .caseif {condition}
; The condition must be a text literal to be passed to the .if macro.
; Remember to escape angle brackets with an exclamation point.
.caseif macro cond:req
ifndef SwitchNesting
.err <.caseif cannot be outside of a .switch/.endswitch block.>
exitm
endif
if SwitchNesting lt 1
.err <Bad .switch/.endswitch block.>
exitm
endif
ife @CatStr ( <SwitchLastCase_>, %SwitchNesting )
ife @CatStr ( <SwitchFirstCase_>, %SwitchNesting )
.endif
else
@CatStr ( <SwitchFirstCase_>, %SwitchNesting ) = 0
endif
.if cond
else
.err <.caseif cannot follow .default.>
endif
endm
.default macro
ifndef SwitchNesting
.err <.default cannot be outside of a .switch/.endswitch block.>
exitm
endif
if SwitchNesting lt 1
.err <Bad .switch/.endswitch block.>
exitm
endif
ifndef SwitchCount
SwitchCount = 0
endif
ife @CatStr ( <SwitchLastCase_>, %SwitchNesting )
ife @CatStr ( <SwitchFirstCase_>, %SwitchNesting )
.endif
else
.err <There should be at least one .case before .default.>
endif
@CatStr ( <SwitchLastCase_>, %SwitchNesting ) = 1
else
.err <There cannot be more that one .default in a .switch/.endswitch block.>
endif
@CatStr ( <SwitchNeedDefault_>, %SwitchNesting ) = 0
@CatStr ( <SwitchLastCase_>, %SwitchNesting ) = 1
@CatStr ( <SwitchDefault_>, %SwitchCount, <:> )
SwitchCount = SwitchCount + 1
endm
.breakdef macro
ifndef SwitchNesting
.err <.breakdef cannot be outside of a .switch/.endswitch block.>
exitm
endif
if SwitchNesting lt 1
.err <Bad .switch/.endswitch block.>
exitm
endif
ifndef SwitchCount
SwitchCount = 0
endif
@CatStr ( <SwitchNeedDefault_>, %SwitchNesting ) = 1
jmp @CatStr ( <SwitchDefault_>, %SwitchCount )
endm
.endswitch macro
if SwitchNesting lt 1
.err <Bad .switch/.endswitch block.>
exitm
endif
ife @CatStr ( <SwitchFirstCase_>, %SwitchNesting )
ife @CatStr ( <SwitchLastCase_>, %SwitchNesting )
.endif
endif
else
.err <Empty .switch/.endswitch block?>
endif
if @CatStr ( <SwitchNeedDefault_>, %SwitchNesting ) ne 0
.err <Unmatched .breakdef, could branch to unexpected location!>
endif
.until TRUE
SwitchNesting = SwitchNesting - 1
if SwitchNesting lt 0
.err <Bad .switch/.endswitch block.>
endif
endm