flat assembler
Message board for the users of flat assembler.
Index
> Programming Language Design > [fasmg] Inline macros. Why not? Goto page 1, 2, 3 Next |
Do you like the idea of inline macros? | |||||||||||||||||||||
|
|||||||||||||||||||||
Total Votes : 10 |
Author |
|
zhak 30 May 2017, 15:37
allowing a macro to return a result of some inner calculations could be a nice feature
|
|||
30 May 2017, 15:37 |
|
Tomasz Grysztar 30 May 2017, 15:40
VEG wrote: I've read somewhere here that Tomasz Grysztar doesn't like the idea of inline macros. But why? Maybe because it can add some ambiguity or it seems not easy to implement? Or it has some drawbacks? Of course it is possible to emulate inline macros by pre-processing all lines with "macro ?". I don't know whether this is viable - it would be slow, of course, bo so are many other macro-based solutions in fasmg. And the syntax you proposed would be quite easy to detect and pre-process with MATCH in the "macro ?" handler. |
|||
30 May 2017, 15:40 |
|
Tomasz Grysztar 30 May 2017, 15:41
zhak wrote: allowing a macro to return a result of some inner calculations could be a nice feature |
|||
30 May 2017, 15:41 |
|
Tomasz Grysztar 30 May 2017, 16:45
Just because I simply cannot resist writing some interesting macros for fasmg, I implemented the pre-processor using "macro ?" that I mentioned above. It uses the syntax with "<?" and "?>" markers that you suggested:
Code: macro preprocess_and_execute line& local buffer,preprocessed,inline,cursor define buffer line : define preprocessed : while 1 match a <=? b, preprocessed buffer redefine preprocessed a redefine buffer b match x =?> y, buffer redefine cursor x redefine buffer y else err 'missing ?>' break end match redefine inline : while 1 match <=? d, cursor match i, inline redefine inline i <? end match redefine cursor d ?> else match c <=? d, cursor match i, inline redefine inline i c <? end match redefine cursor d ?> else match i, inline cursor redefine inline i break end match match =?> y, buffer redefine buffer y else match x =?> y, buffer match c, cursor redefine cursor c x end match redefine buffer y else err 'missing ?>' break end match end while match :command, inline preprocess_and_execute command match text, preprocessed $result redefine preprocessed text end match end match else match a, preprocessed buffer redefine preprocessed a break end match end while match :command:, preprocessed command end match end macro macro ? line& preprocess_and_execute line end macro A simple example how it works: Code: macro low value $result = value and 0FFFFh end macro macro high value $result = value shr 16 end macro include '8086.inc' address = 12345678h mov ax,<? low address ?> mov dx,<? high address ?> |
|||
30 May 2017, 16:45 |
|
VEG 30 May 2017, 17:17
Tomasz Grysztar, you're crazy (in a good sense) =)
I've tested how it affects time of assembly. In my situation it is +33% of time (4 seconds instead of 3). It seems that I can live with it. Thank you very much. It is really a must have feature for me. IMHO, 1 line = 1 macroinstruction is good for instructions which actually emit some bytes to output. But if some instruction just makes some work with variables, like conversion from int to string or just merging some strings into one variable, and doesn't emit anything, and this data will be used just as an argument of the next instruction which will emit some code, it looks not good and actually makes the code more cluttered. Also I think I'll add some kind of prefix for these inline macro, just to avoid possible intersection with general macros. I'll add the "imacro" macros which will define such kind of inline macros with names like "imacro.usermacroname", and I'll add to the <? ?> handler automatic addition of the "imacro.", so it still will be possible to write <? usermacroname ?>, and it will not prevent a programmer from creation and using a normal (not inline) macro with the same name if it will be required. |
|||
30 May 2017, 17:17 |
|
Tomasz Grysztar 30 May 2017, 18:20
VEG wrote: Tomasz Grysztar, you're crazy (in a good sense) =) |
|||
30 May 2017, 18:20 |
|
VEG 31 May 2017, 18:05
It seems that I completely misunderstand FASMG macros I thought that it will be the easiest one, but it doesn't work. It has to work line a normal macro, but with adding of the _imacro postfix for an inline macro name. (I've decided to use postfix because in this case it will take into account namespaces).
Code: macro imacro line& match iname args, line esc macro iname#_imacro args else match iname, line esc macro iname#_imacro end match end macro macro end?.imacro esc end macro end macro imacro low value $result = value and 0FFFFh end imacro Code: flat assembler version g.ht7g2 imacro.asm [94]: imacro low value macro ? [1] macro imacro_preprocess [63] macro imacro [1]: match iname args, line Error: missing end directive. The preprocess macro which uses inline macros with _imacro postfix: Code: macro imacro_preprocess line& local buffer,preprocessed,inline,cursor define buffer line : define preprocessed : while 1 match a <=? b, preprocessed buffer redefine preprocessed a redefine buffer b match x =?> y, buffer redefine cursor x redefine buffer y ; dd <? ?> ; catches this error ; dd <? sub 2, <? ?> ?> ; doesn't catch it ; else match =?> y, buffer ; err 'empty <? ?>' ; break else err 'missing ?>' break end match redefine inline : while 1 match <=? d, cursor match i, inline redefine inline i <? end match redefine cursor d ?> else match c <=? d, cursor match i, inline redefine inline i c <? end match redefine cursor d ?> else match i, inline cursor redefine inline i break end match match =?> y, buffer redefine buffer y else match x =?> y, buffer match c, cursor redefine cursor c x end match redefine buffer y else err 'missing ?>' break end match end while match :command, inline match inst args, command imacro_preprocess inst#_imacro args else match inst, command imacro_preprocess inst#_imacro end match match text, preprocessed $result redefine preprocessed text end match end match else match a, preprocessed buffer redefine preprocessed a break end match end while match :command:, preprocessed command end match end macro macro ? line& imacro_preprocess line end macro Last edited by VEG on 31 May 2017, 18:09; edited 2 times in total |
|||
31 May 2017, 18:05 |
|
Tomasz Grysztar 31 May 2017, 18:08
When you start the nested macro, END MATCH becomes part of the inner macro and the original block remains unclosed.
You may find this article helpful: https://board.flatassembler.net/topic.php?t=19496 |
|||
31 May 2017, 18:08 |
|
Tomasz Grysztar 31 May 2017, 18:16
I modified your sample to show how you can get it working:
Code: macro imacro line& local begin match iname args, line macro begin esc macro iname#_imacro args end macro else match iname, line macro begin esc macro iname#_imacro end macro end match begin end macro macro end?.imacro! esc end macro end macro imacro low value $result = value and 0FFFFh end imacro |
|||
31 May 2017, 18:16 |
|
VEG 31 May 2017, 18:34
Oh, nice trick with the "begin" local macro. But it seems that it has some conflicts with the preprocessing macro:
Code: macro imacro_preprocess line& local buffer,preprocessed,inline,cursor define buffer line : define preprocessed : while 1 match a <=? b, preprocessed buffer redefine preprocessed a redefine buffer b match x =?> y, buffer redefine cursor x redefine buffer y ; dd <? ?> ; catches this error ; dd <? sub 2, <? ?> ?> ; doesn't catch it ; else match =?> y, buffer ; err 'empty <? ?>' ; break else err 'missing ?>' break end match redefine inline : while 1 match <=? d, cursor match i, inline redefine inline i <? end match redefine cursor d ?> else match c <=? d, cursor match i, inline redefine inline i c <? end match redefine cursor d ?> else match i, inline cursor redefine inline i break end match match =?> y, buffer redefine buffer y else match x =?> y, buffer match c, cursor redefine cursor c x end match redefine buffer y else err 'missing ?>' break end match end while match :command, inline match inst args, command imacro_preprocess inst#_imacro args else match inst, command imacro_preprocess inst#_imacro end match match text, preprocessed $result redefine preprocessed text end match end match else match a, preprocessed buffer redefine preprocessed a break end match end while match :command:, preprocessed command end match end macro macro ? line& imacro_preprocess line end macro macro imacro line& local begin match iname args, line macro begin esc macro iname#_imacro args end macro else match iname, line macro begin esc macro iname#_imacro end macro end match begin end macro macro end?.imacro! esc end macro end macro imacro low value $result = value and 0FFFFh end imacro Code: flat assembler version g.ht7g2 imacro.asm [102]: imacro low value macro ? [1] macro imacro_preprocess [64]: match :command:, preprocessed Error: missing end directive. |
|||
31 May 2017, 18:34 |
|
VEG 31 May 2017, 18:37
I've replaced this:
Code: match :command:, preprocessed command end match end macro Code: local execute match :command:, preprocessed macro execute command end macro end match execute end macro |
|||
31 May 2017, 18:37 |
|
Tomasz Grysztar 31 May 2017, 18:47
You may need to make all things unconditional otherwise the "macro ?" jumps in in wrong places:
Code: macro imacro! line& match iname args, line macro begin_imacro! esc macro iname#_imacro args end macro else match iname, line macro begin_imacro! esc macro iname#_imacro end macro end match begin_imacro end macro macro end?.imacro! esc end macro purge begin_imacro end macro |
|||
31 May 2017, 18:47 |
|
VEG 31 May 2017, 19:26
But the "macro ?" is supposed to not affect any code without <? ?>. Is this fix ok for such purpose?
I've just read why unconditional macros could be required (and it is understandable). But it seems that the FASMG Manual says nothing about unconditional ESC (and LOCAL). Or you're talking about stuff from this topic? |
|||
31 May 2017, 19:26 |
|
Tomasz Grysztar 31 May 2017, 19:34
VEG wrote: But the "macro ?" is supposed to not affect any code without <? ?>. Is this fix ok for such purpose? VEG wrote: I've just read why unconditional macros could be required (and it is understandable). But it seems that the FASMG Manual says nothing about unconditional ESC (and LOCAL). Or you're talking about stuff from this topic? |
|||
31 May 2017, 19:34 |
|
VEG 01 Jun 2017, 06:00
A critical bug:
Code: address = 12345678h dw <? low address ?>,<? high address ?> I'm trying to resolve it like this: Code: macro imacro_preprocess line& local buffer,preprocessed,inline,cursor,resultn resultn = 0 define buffer line : define preprocessed : while 1 match a <=? b, preprocessed buffer redefine preprocessed a redefine buffer b match x =?> y, buffer redefine cursor x redefine buffer y else err 'missing ?>' break end match redefine inline : while 1 match <=? d, cursor match i, inline redefine inline i <? end match redefine cursor d ?> else match c <=? d, cursor match i, inline redefine inline i c <? end match redefine cursor d ?> else match i, inline cursor redefine inline i break end match match =?> y, buffer redefine buffer y else match x =?> y, buffer match c, cursor redefine cursor c x end match redefine buffer y else err 'missing ?>' break end match end while local result#resultn match :command args, inline imacro_preprocess command#_imacro result#resultn, args else match :command, inline imacro_preprocess command#_imacro result#resultn else err 'should not be here' end match match text, preprocessed result#resultn redefine preprocessed text end match resultn = resultn + 1 else match a, preprocessed buffer redefine preprocessed a break end match end while local execute match :command:, preprocessed macro execute command end macro end match execute end macro macro ? line& imacro_preprocess line end macro macro imacro line& local begin match iname args, line macro begin esc macro iname#_imacro result, args end macro else match iname, line macro begin esc macro iname#_imacro result end macro end match begin end macro macro end?.imacro! esc end macro end macro imacro low value result = value and 0FFFFh end imacro imacro high value result = value shr 16 end imacro address = 12345678h dw <? low address ?>,<? high address ?> address = 11223344h dw <? low address ?>,<? high address ?> I've changed the code a bit. Now the result variable isn't a global variable, it is a local variable which is passed as the first argument for an imacro, and the imacro sets a value to this variable. Also I'm using just "result" as a name of the result variable, like it is in good old Pascal/Delphi An idea. Maybe it will be very convenient to allow another variant of label which will generate a new local variable every time when this instruction is executed. Like when "newlocal temp" will be used inside a loop, this "temp" variable will be new every iteration of this loop. It will make such code much simpler. It will be possible to use just "local result", and every iteration this "result" will be a new local variable. Last edited by VEG on 01 Jun 2017, 06:38; edited 3 times in total |
|||
01 Jun 2017, 06:00 |
|
VEG 01 Jun 2017, 06:07
I've used such trick:
Code: repeat 1, n:resultn local result#n result reequ result#n end repeat The whole code: Code: macro imacro_preprocess line& local buffer,preprocessed,inline,cursor,result,resultn resultn = 0 define buffer line : define preprocessed : while 1 match a <=? b, preprocessed buffer redefine preprocessed a redefine buffer b match x =?> y, buffer redefine cursor x redefine buffer y else err 'missing ?>' break end match redefine inline : while 1 match <=? d, cursor match i, inline redefine inline i <? end match redefine cursor d ?> else match c <=? d, cursor match i, inline redefine inline i c <? end match redefine cursor d ?> else match i, inline cursor redefine inline i break end match match =?> y, buffer redefine buffer y else match x =?> y, buffer match c, cursor redefine cursor c x end match redefine buffer y else err 'missing ?>' break end match end while repeat 1, n:resultn local result#n result reequ result#n end repeat match :command args, inline imacro_preprocess command#_imacro result, args else match :command, inline imacro_preprocess command#_imacro result end match match text, preprocessed result redefine preprocessed text end match resultn = resultn + 1 else match a, preprocessed buffer redefine preprocessed a break end match end while local execute match :command:, preprocessed macro execute command end macro end match execute end macro macro ? line& imacro_preprocess line end macro macro imacro line& local begin match iname args, line macro begin esc macro iname#_imacro result, args end macro else match iname, line macro begin esc macro iname#_imacro result end macro end match begin end macro macro end?.imacro! esc end macro end macro imacro low value result = value and 0FFFFh end imacro imacro high value result = value shr 16 end imacro address = 12345678h dw <? low address ?>,<? high address ?> address = 11223344h dw <? low address ?>,<? high address ?> |
|||
01 Jun 2017, 06:07 |
|
VEG 01 Jun 2017, 06:26
Ok, I've fixed it. I moved the whole block which uses the "result" variable into the "repeat" block, and now I'm using it like result#n, and it works.
So, working version without the bug: Code: macro imacro_preprocess line& local buffer,preprocessed,inline,cursor,resultn resultn = 0 define buffer line : define preprocessed : while 1 match a <=? b, preprocessed buffer redefine preprocessed a redefine buffer b match x =?> y, buffer redefine cursor x redefine buffer y else err 'missing ?>' break end match redefine inline : while 1 match <=? d, cursor match i, inline redefine inline i <? end match redefine cursor d ?> else match c <=? d, cursor match i, inline redefine inline i c <? end match redefine cursor d ?> else match i, inline cursor redefine inline i break end match match =?> y, buffer redefine buffer y else match x =?> y, buffer match c, cursor redefine cursor c x end match redefine buffer y else err 'missing ?>' break end match end while repeat 1, n:resultn local result#n match :command args, inline imacro_preprocess command#_imacro result#n, args else match :command, inline imacro_preprocess command#_imacro result#n end match ; if ~ defined result#n ; err 'result is undefined' ; end if match text, preprocessed result#n redefine preprocessed text end match end repeat resultn = resultn + 1 else match a, preprocessed buffer redefine preprocessed a break end match end while local execute match :command:, preprocessed macro execute command end macro end match execute end macro macro ? line& imacro_preprocess line end macro macro imacro line& local begin match iname args, line macro begin esc macro iname#_imacro result, args end macro else match iname, line macro begin esc macro iname#_imacro result end macro end match begin end macro macro end?.imacro! esc end macro end macro imacro low value result = value and 0FFFFh end imacro imacro high value result = value shr 16 end imacro address = 12345678h dw <? low address ?>,<? high address ?> address = 11223344h dw <? low address ?>,<? high address ?> UPD. Now I understand why an alias will not work. It's just because this code will remember the name of an alias: Code: match text, preprocessed result
redefine preprocessed text
end match Last edited by VEG on 01 Jun 2017, 06:44; edited 2 times in total |
|||
01 Jun 2017, 06:26 |
|
Tomasz Grysztar 01 Jun 2017, 06:41
VEG wrote: A critical bug: So the only good way to use that original macro is in fact to define $result symbolically: Code: imacro low value local x x = value and 0FFFFh $result equ x end imacro imacro high value local x x = value shr 16 $result equ x end imacro Code: imacro var number if number = 0 $result equ edx else local offset offset = number*4 $result equ dword [ebp+offset] end if end imacro inc <? var 0 ?> inc <? var 1 ?> |
|||
01 Jun 2017, 06:41 |
|
VEG 01 Jun 2017, 07:21
Tomasz Grysztar, oh, nice idea! I haven't thought about this use case. It seems that my variant also works with symbolic variables.
Thank you so much. It was really one of features I was dreaming for. I'll write a bunch of useful inline macros and publish them. |
|||
01 Jun 2017, 07:21 |
|
Goto page 1, 2, 3 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.