I am not sure its useful but it does work OK.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \masm32\include64\masm64rt.inc
mi MACRO a1,a2,a3,a4,a5,a6,a7,a8,a9,a0
a1
a2
a3
a4
a5
a6
a7
a8
a9
a0
ENDM
close MACRO exitcode:=<0>
mov rcx, exitcode
call ExitProcess
ENDM
.code
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
entry_point proc
mi <mov rax, 1>,<add rax, 2>,<sub rax, 3>,waitkey,close,ret
entry_point endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end
Basic style:
include \Masm32\MasmBasic\Res\JBasic.inc ; download (http://masm32.com/board/index.php?topic=94.0)
mijj MACRO args:VARARG
Local isL, isR, isFlag, argsLen
isR=0
isFlag=1
While isFlag
isL=isR+1
isR INSTR isL, <args>, <:>
ife isR
isR=@SizeStr(<args>)+1
isFlag=0
endif
@SubStr(<args>, isL, isR-isL)
ENDM
ENDM
Init
PrintLine Chr$("This code was assembled with ", @AsmUsed$(1), " in ", jbit$, "-bit format")
mijj mov rax, 100:add rax, 30:sub rax, 7: <Inkey Str$("rax=%i", rax)>
EndOfCode
Output:
This code was assembled with ml64 in 64-bit format
rax=123
Problem with both versions is the premature expansion of macros - therefore <brackets> around the macros.
Hi, hutch--!
This is macro from the article "Как писать на MASM в строчку (http://arhive.xaker.name/threads/10430/?q=)" (How to write on MASM in single line) of Svet(R)off 2001 from site ASSEMBLER.RU
Google translating article into English (https://translate.google.ru/translate?sl=ru&tl=en&js=y&prev=_t&hl=ru&ie=UTF-8&u=http%3A%2F%2Farhive.xaker.name%2Fthreads%2F10430%2F%3Fq%3D&edit-text=)
(http://www.cyberforum.ru/images/smilies/smile3.gif)
With a little more effort, this one works OK.
[[t]
; *************************************************************************
; -------------------------------------------------------------------------
multiple_instruction MACRO args:VARARG
LOCAL arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg0,cntr,flag
cntr = 1 ;; counter determined which buffer is being written to
flag = 0 ;; flag starts as clear
arg1 equ <>
arg2 equ <>
arg3 equ <>
arg4 equ <>
arg5 equ <>
arg6 equ <>
arg7 equ <>
arg8 equ <>
arg9 equ <>
arg0 equ <>
;; ---------------------------------
FORC char,<args>
IFIDN <char>,<:> ;; test if char is the ":" delimiter
IF flag eq 0
cntr = cntr + 1 ;; only increment the counter if the flag is clear
ENDIF
flag = 1 ;; set the flag so you only get 1 increment of cntr
goto over
ENDIF
flag = 0 ;; clear the flag when the next char is not a space
IF cntr eq 1
arg1 CATSTR arg1,<char> ;;
ELSEIF cntr eq 2
arg2 CATSTR arg2,<char> ;;
ELSEIF cntr eq 3
arg3 CATSTR arg3,<char> ;;
ELSEIF cntr eq 4
arg4 CATSTR arg4,<char> ;;
ELSEIF cntr eq 5
arg5 CATSTR arg5,<char> ;;
ELSEIF cntr eq 6
arg6 CATSTR arg6,<char> ;;
ELSEIF cntr eq 7
arg7 CATSTR arg7,<char> ;;
ELSEIF cntr eq 8
arg8 CATSTR arg8,<char> ;;
ELSEIF cntr eq 9
arg9 CATSTR arg9,<char> ;;
ELSEIF cntr eq 10
arg0 CATSTR arg0,<char> ;;
ELSEIF cntr eq 11
% echo *********************************************
% echo ERROR : too many arguments, 10 argument limit
% echo *********************************************
.err <too many arguments>
goto over
ENDIF
:over
ENDM
;; ---------------------------------
arg1
arg2
arg3
arg4
arg5
arg6
arg7
arg8
arg9
arg0
ENDM
; --------------------------------
mi MACRO args:VARARG
multiple_instruction args
ENDM
; -------------------------------------------------------------------------
; *************************************************************************
[/tt]
Looks like this in use.
mi \
mov rax,1 : add rax,1 : sub rax,3 : xor rax,rax
mi waitkey : fn ExitProcess,0 : ret
Quote from: Mikl__ on October 09, 2016, 01:09:59 PMGoogle translating article into English (https://translate.google.ru/translate?sl=ru&tl=en&js=y&prev=_t&hl=ru&ie=UTF-8&u=http%3A%2F%2Farhive.xaker.name%2Fthreads%2F10430%2F%3Fq%3D&edit-text=)
QuoteAssembler - the greatest language, the king of languages, virtually devoid of shortcomings worthy of people's love and worship
Absolutely :t
mi mov rax, 100:add rax, 30:sub rax, 7: <Print Str$("version Hutch...\t rax=%i\n", rax)>
mijj mov rax, 100:add rax, 30:sub rax, 7: <Print Str$("version JJ... \t rax=%i\n", rax)>
Output:
version Hutch... rax=1
version JJ... rax=123
(expected: 123; assembled with ml64 in 64-bit format)
Can't see, though, why yours shouldn't work - it looks ok ::)
A look in the *.lst file:
FORC char,<mov rax,100:add rax,30:sub rax,7: Print offset s$buffer>
??0104 INSTR ??0100, <mov rax,100:add rax,30:sub rax,7: Print Str$("version JJ: \t rax=%i\n", rax)>, <"> ;
So the FORC version gets expanded (offset...), the other one is still Str$(...).
Attached a new version, baptised mulComs, builds with ML/ML64, HJWasm and AsmC.
This works now:
mi mov rax, 100:add rax, 30:sub rax, 7: <Print Str$("version Hutch...\t rax=%i\n", rax)>
mulComs mov rax, 100:add rax, 30:sub rax, 7: <Print Str$("version JJ: \t rax=%i\n", rax)>
P.S.: Try
version Hutch: instead of
version Hutch...
I have tracked down at this end what is happening and I have seen it before, the "conout" macro that I test with is being filled out before the "mi" macro is being executed so it misses the result of previous instructions.
Indeed:
Quote from: jj2007 on October 09, 2016, 12:50:41 PM
Problem with both versions is the premature expansion of macros - therefore <brackets> around the macros.
Question is why your
mi doesn't work with my Print Str$(), despite the brackets, while mine does. My guess is that the FORC is the problem.
This shows the problem.
Arg count = 4
mov r15,100
add r15,30
sub r15,7
add r15,r15
Arg count = 3
conout "Result = ",??0025,??0001
waitkey
fn __imp_ExitProcess,0
From being in the FORC loop, macros and other operators are being expanded before the parent macro is run.
It seems so. My version avoids CATSTR, and therefore expansion:
mulComs MACRO args:VARARG
Local isL, isR, isFlag, argsLen, isQ
isR=0
isFlag=1
While isFlag
isL=isR+1
isQ INSTR isL, <args>, <"> ; xxx : Print "Hello: a problem" : xxx
isR INSTR isL, <args>, <:>
if isQ and isQ lt isR
isQ INSTR isQ+1, <args>, <">
isR INSTR isQ, <args>, <:>
endif
ife isR
isR=@SizeStr(<args>)+1
isFlag=0
endif
@SubStr(<args>, isL, isR-isL)
ENDM
ENDM
I put this line at the front of the main macro before either the FORC loop and any instance of CATSTR and still got this.
% echo Args = args
and get this output,
Args = conout "Result = ",??0025,??0001 : waitkey : fn __imp_ExitProcess,0
It does not appear to be a problem with macros that have static parameter or an API call but it prevents an embedded macro from getting results in the same calling macro before it.
After wasting some hours, I cannot find a format of passing a macro inside another macro that does not expand the embedded macro unless it is contained in a string so I have put it aside at the moment. I can get this to work correctly as it isolates macro expansion by placing such a macro on its own line. This restricts the use to non accumulated arguments.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \masm32\include64\masm64rt.inc
.code
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
entry_point proc
mi mov rax, 100 : sub rax, 75 : shl rax, 2
conout "Result = ",str$(rax),lf
mi waitkey : invoke ExitProcess,0 : ret
entry_point endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end
May have a play with it later but have more important things to do.
file which is mentioned in the article of
Svet(R)off "How to write on MASM in single line"
QuoteWishes to enjoy a new kind of source code and learn some style ideas can click here
Wow! It is 400-th message on the forum, it is necessary to celebrate it - I will go to pour himself some vodka from a samovar, feed the bear and play the balalaika (http://www.kolobok.us/smiles/personal/russian.gif)
Mikl__, :t
Quote from: Mikl__ on October 10, 2016, 01:47:44 PMfile which is mentioned in the article of Svet(R)off "How to write on MASM in single line"
Wow, he has a multiple instructions macro called "@", and puts the comments in front:
List_DX_Modes PROC
@<;Clear variables>,<mov modes_buffer,0>,<mov modes_number,0>
@<;Create list modes buffer>,<invoke GlobalAlloc,GPTR,MODES_BUFFER_SIZE>,<or eax,eax>,<jz bad>,<mov modes_buffer,eax>
@<;Create a DirectDraw object>,<invoke DirectDrawCreate,NULL,offset(lpDD),NULL>,<cmp eax,DD_OK>,<jne bad>
Reminds me of the old, old times when I had to keep a certain fat BASIC source below 16384 lines, for technical reasons :icon_mrgreen:
In the meantime, I added my version as
mcs (=
multiple
command
s) to the MB package, for use with (32-bit) MasmBasic and the dual 32-/64-bit JBasic variant; tested with all "our" assemblers here. More here (http://masm32.com/board/index.php?topic=94.msg60949#msg60949).
The problem is for the design I was after that I wanted to keep it simple, just have a " : " between each component and for static content it works fine, what beats embedded dependent content is the characteristic of the macro engine to expand nested macros before the parent macro is called which defeats sequential dependent components. The form I have got is usable and simple but dependent procedure calls or macros must be put on a separate line to get the previous data.
mi \
mov rax, 100 : add rax, 300 : shl rax, 1
This works fine and is simple notation, as soon as it gets cluttered with notation, it loses any advantage it has.
Here is a simple test that shows that it works OK calling a procedure which can process inline content. It seems that its only a problem with inline macros that are embedded in a parent macro.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \masm32\include64\masm64rt.inc
.code
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
entry_point proc
LOCAL var :QWORD
mi \
mov rax, 100 : add rax, 100 : shl rax, 1 : mov var, rax : fn showit,var
conout str$(var)," inline macro",lf
waitkey
invoke ExitProcess,0
ret
entry_point endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
showit proc var:QWORD
conout str$(var)," showit proc",lf
ret
showit endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end
Quote from: hutch-- on October 10, 2016, 08:55:06 PMIt seems that its only a problem with inline macros that are embedded in a parent macro.
More precisely, function() macros, i.e. those that return something, get expanded in the moment when they are being passed as an argument, like e.g. Hex$() below. But even those can be kept on one line, provided they are <passed as strings>:
include \masm32\MasmBasic\MasmBasic.inc
Init
Dim PtrSSE() As DWORD
For_ ct=0 To 99 ; 100 aligned pointers
mcs Alloc16 Rand(10000) : mov PtrSSE(ct), eax : <Print Hex$(al), " ">
Next
EndOfCode
Question is if users read the manual:
- mcs allows to put several commands on one line, separated by a colon as in Basic
- if macros depend on previous commands, like e.g. Str$(...), <put them in brackets>
Problem is it does not work.
LOCAL var :QWORD
mi \
mov rax, 100 : add rax, 100 : shl rax, 1 : mov var, rax : fn showit,var
conout str$(var)," inline macro",lf
xor rax, rax
mi \
mov rax, 100 : <conout str$(rax)," this fails",lf,lf>
waitkey
invoke ExitProcess,0
ret
Output is as follows.
400 showit proc
400 inline macro
0 this fails
It also fails on every variation of angle brackets.
Here is a further variation that still fails, it appears that ML64 always expands embedded macros before their parent macro.
mtst MACRO arg:VARARG
% echo arg
ENDM
.............
mtst mov rax, 100 : <conout str$(rax)>
mtst <mov rax, 100 : conout str$(rax)>
mtst mov rax, 100 : conout <str$(rax)>
All fail due to prior expansion.
I've made some ugly and complicated tests with your mi macro, and it seems the FORC is really the problem. Mine works fine with <conout str$(rax)>, apparently because <args> gets expanded only step by step, i.e. in @SubStr ::)
mcs MACRO args:VARARG ; part of the MasmBasic package
Local isL, isR, isQ
isR=0
While 1
isL=isR+1
isQ INSTR isL, <args>, <"> ; xx : Print "Hello: a problem" : xx
isR INSTR isL, <args>, <:>
if isQ and isQ lt isR
isQ INSTR isQ+1, <args>, <">
isR INSTR isQ, <args>, <:>
endif
if isR
@SubStr(<args>, isL, isR-isL)
else
@SubStr(<args>, isL)
EXITM
endif
ENDM
ENDM
Of course, you are welcome to use my code in your include files. Over time, I have taken so many ideas from your includes that it is a pleasure to give something back :icon14:
An option is to delay the expansion by using wrappers for the function like macros. The result of an function like macro is no further expanded.
include \masm32\include\masm32rt.inc
mi TEXTEQU <__delay()>
__delay_expansion = 0
__delay macro
__delay_expansion = 1
EXITM <_mi>
endm
_mi macro args:VARARG
_mi_cmd TEXTEQU <args>
_mi_size SIZESTR <args>
_mi_pos = 1
_mi_colon_pos INSTR <args>,<:>
WHILE _mi_colon_pos NE 0
_mi_cmd SUBSTR <args>,_mi_pos, _mi_colon_pos - _mi_pos
__delay_expansion = 0
% &_mi_cmd
__delay_expansion = 1
_mi_pos = _mi_colon_pos + 1
_mi_colon_pos INSTR _mi_pos,<args>,<:>
ENDM
IF _mi_pos LE _mi_size
_mi_cmd SUBSTR <args>,_mi_pos
__delay_expansion = 0
% &_mi_cmd
__delay_expansion = 1
ENDIF
__delay_expansion = 0
endm
myStr$ macro arg
IFE __delay_expansion
EXITM str$(arg)
ELSE
EXITM <str$(arg)>
ENDIF
endm
myCmd$ macro arg
IFE __delay_expansion
EXITM cmd$(arg)
ELSE
EXITM <cmd$(arg)>
ENDIF
endm
.code
main proc
mi mov eax,123 : fn MessageBox,0,myStr$(eax),0,0 : mov eax, myCmd$(0)
exit
main endp
end main
pro: no further syntax elements needed to control expansion
con: all function likes macros must be changed
Thanks guys, you both have some interesting ideas, the problem for what my target was is notational simplicity, it was originally targeted at purely mnemonics where you could bundle a sequence of uninteresting mnemonics onto one line to reduce clutter something like this.
NOSTACKFRAME
.szLen proc
mi mov rax, rcx : sub rax, 1
lbl:
mi add rax, 1 : movzx r10, BYTE PTR [rax] : test r10, r10 : jnz lbl
lbl1:
mi sub rax, rcx : ret
.szLen endp
STACKFRAME
Here is a variation.
mi NOSTACKFRAME : .szLen proc : mov rax, rcx : sub rax, 1
lbl:
mi add rax, 1 : movzx r10, BYTE PTR [rax] : test r10, r10 : jnz lbl
lbl1:
mi sub rax, rcx : ret : .szLen endp : STACKFRAME
It will also handle function/API calls and simple non dependent macro statements but will not handle result dependent embedded macros.
Calling a procedure directly works fine but the general approach is clunky and fails in terms of simplicity.
xor rax, rax
mi mov rax, 100 : fn .str$,rax : conout rax," this works as a proc",lf
I slightly tweaked the original macro to take different delimiters then made a set of wrappers with multiple variations.
.mi MACRO args:VARARG ;; multiple instructions
.multiple_instruction :,args
ENDM
.ma MACRO args:VARARG ;; multiple arguments
.multiple_instruction #,args
ENDM
.mn MACRO args:VARARG ;; alternate multiple arguments
.multiple_instruction ~,args
ENDM
.m MACRO args:VARARG ;; alternate multiple arguments
.multiple_instruction ^,args
ENDM
Using any of the alternatives allows you to use labels so you can produce nightmares like this.
; NOSTACKFRAME
;
; szLen proc
;
; ; rcx = address of string
;
; mov rax, rcx
; sub rax, 1
; lbl:
; REPEAT 3
; add rax, 1
; movzx r10, BYTE PTR [rax]
; test r10, r10
; jz lbl1
; ENDM
;
; add rax, 1
; movzx r10, BYTE PTR [rax]
; test r10, r10
; jnz lbl
;
; lbl1:
; sub rax, rcx
;
; ret
;
; szLen endp
;
; STACKFRAME
.ma NOSTACKFRAME # .szLen proc # mov rax,rcx # sub rax,1 # lbl:
REPEAT 3
.ma add rax,1 # movzx r10, BYTE PTR [rax] # test r10,r10 # jz lbl1
ENDM
.ma add rax,1 # movzx r10, BYTE PTR [rax] # test r10,r10
.ma jnz lbl # lbl1: # sub rax,rcx # ret # .szLen endp # STACKFRAME
Quote from: hutch-- on October 11, 2016, 11:18:03 AMUsing any of the alternatives allows you to use labels so you can produce nightmares like this.
Different, but on par with slickhuh.asm :badgrin: