flat assembler
Message board for the users of flat assembler.
 Home   FAQ   Search   Register 
 Profile   Log in to check your private messages   Log in 
flat assembler > Programming Language Design > [fasmg] Inline macros. Why not?

Goto page Previous  1, 2

Do you like the idea of inline macros?
Yes, I like
75%
 75%  [ 3 ]
No, I don't
0%
 0%  [ 0 ]
Don't care
25%
 25%  [ 1 ]
Total Votes : 4

Author
Thread Post new topic Reply to topic
VEG



Joined: 06 Feb 2013
Posts: 68
Location: Minsk, Belarus
I've fixed another bug with overwriting results when nesting was used. Also case-insensitive imacros (with "?" as postfix) are acceptable now. And new instruction "ipurge" was added, it purges an imacro Smile

Code:
macro imacro_preprocess resultnline&

        local buffer,preprocessed,inline,cursor

        define buffer line :
        define preprocessed :
        while 1
                match a <=? bpreprocessed buffer
                        redefine preprocessed a
                        redefine buffer b

                        match x =?ybuffer
                                redefine cursor x
                                redefine buffer y
                        else
                                err 'missing ?>'
                                break
                        end match

                        redefine inline :
                        while 1
                                match <=? dcursor
                                        match iinline
                                                redefine inline i <?
                                        end match
                                        redefine cursor d ?>
                                else match c <=? dcursor
                                        match iinline
                                                redefine inline i c <?
                                        end match
                                        redefine cursor d ?>
                                else match iinline cursor
                                        redefine inline i
                                        break
                                end match
                                match =?ybuffer
                                        redefine buffer y
                                else match x =?ybuffer
                                        match ccursor
                                                redefine cursor c x
                                        end match
                                        redefine buffer y
                                else
                                        err 'missing ?>'
                                        break
                                end match
                        end while

                        repeat 1n:resultn
                                resultn = resultn + 1
                                local result#n
                                match :command argsinline
                                        imacro_preprocess resultncommand#_imacro result#nargs
                                else match :commandinline
                                        imacro_preprocess resultncommand#_imacro result#n
                                end match
                                match textpreprocessed result#n
                                        redefine preprocessed text
                                end match
                        end repeat

                else match apreprocessed 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&

        local resultn
        resultn = 0
        imacro_preprocess resultnline

end macro

macro imacro line&
        local begin
        match iname=? argsline
                macro begin
                        esc macro iname#_imacro? resultargs
                end macro
        else match iname=?line
                macro begin
                        esc macro iname#_imacro? result
                end macro
        else match iname argsline
                macro begin
                        esc macro iname#_imacro resultargs
                end macro
        else match inameline
                macro begin
                        esc macro iname#_imacro result
                end macro
        end match
        begin
end macro

macro end?.imacro!
        esc end macro
end macro

macro ipurge iname
        purge iname#_imacro
end macro

imacro concat first*,rest*&
        result = string first
        iterate srest
                result = string result + (sshl (((bsr result - 1shr 3 + 1shl 3)
        end iterate
end imacro

imacro tohex number*,digits:8
        virtual at 0
                repeat digits
                        digit = ((numbershr ((%%-%shl 2)) and 0Fh
                        if digit < 10
                                db '0'+digit
                        else
                                db 'A'+digit-10
                        end if
                end repeat
                load result:$ from 0
        end virtual
end imacro



And a new problem Sad It seems that "macro ?" doesn't process lines inside other macros Sad
It works:

Code:
display <? concat '0x', <? tohex 12345 ?>, 10 ?>

It doesn't work:

Code:
macro test
        display <? concat '0x', <? tohex 12345 ?>, 10 ?>
end macro
test


Code:
flat assembler  version g.htee8
imacro.asm [157]:
        test
macro ? [4macro imacro_preprocess [73macro execute [1macro test [1]:
        display <? concat '0x', <? tohex 12345 ?>, 10 ?>
Processeddisplay <? concat '0x', <? tohex 12345 ?>, 10 ?>
Errorinvalid expression.

My guess was that it is because of conditional/unconditional execution. I've tried to add "!" to the "macro ?" and "macro imacro_preprocess", and it seems that it goes into an endless loop as the result.


Last edited by VEG on 01 Jun 2017, 09:35; edited 1 time in total
Post 01 Jun 2017, 09:05
View user's profile Send private message Visit poster's website Reply with quote
VEG



Joined: 06 Feb 2013
Posts: 68
Location: Minsk, Belarus
It seems that "macro ?!" also doesn't preprocess lines inside macros:

Code:
macro ?! line&
        display `line10
        line
end macro

macro test
        db 0
end macro

Outputs:

Code:
flat assembler  version g.htee8

macro test



1 pass0 bytes.


And this variant:

Code:
macro ?! line&
        display `line10
        line
end macro

macro test
        db 0
end macro
db 1
test

Outputs something crazy:

Code:
flat assembler  version g.htee8

macro test
db 1
test
db 0
end macro

1 pass2 bytes.

When I remove ! from the "macro ?", output is more logical (but without macros at all):

Code:
flat assembler  version g.htee8
db 1
test

1 pass2 bytes.


Was it done to avoid preprocessing of "macro ?" itself? How does "macro ?!" work? Maybe it will be ok to pass macros bodies to the "macro ?!" at least. It will be ok to ignore just "macro ?" or "macro ?!" bodies themselves for avoiding of preprocessing of own code.
Post 01 Jun 2017, 09:21
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6436
Location: Kraków, Poland

VEG wrote:
How does "macro ?!" work?

This one intercept absolutely every line with no exception. It is only really useful when you need to process the syntax completely on your own (possibly inside a section of code, because you can "purge ?" later).
Post 01 Jun 2017, 09:46
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6436
Location: Kraków, Poland

VEG wrote:
And a new problem Sad It seems that "macro ?" doesn't process lines inside other macros Sad
It works:

Code:
display <? concat '0x', <? tohex 12345 ?>, 10 ?>

It doesn't work:

Code:
macro test
        display <? concat '0x', <? tohex 12345 ?>, 10 ?>
end macro
test


Code:
flat assembler  version g.htee8
imacro.asm [157]:
        test
macro ? [4macro imacro_preprocess [73macro execute [1macro test [1]:
        display <? concat '0x', <? tohex 12345 ?>, 10 ?>
Processeddisplay <? concat '0x', <? tohex 12345 ?>, 10 ?>
Errorinvalid expression.

My guess was that it is because of conditional/unconditional execution. I've tried to add "!" to the "macro ?" and "macro imacro_preprocess", and it seems that it goes into an endless loop as the result.

It does not work because "imacro_preprocess" processes the line "test", but it is no longer processed inside the "test" macro itself. To handle this you need to define "test" in such way that "imacro_preprocess" would get called for the lines inside "test" too. There is a couple of ways to do that.

First, you could simply make the "test" macro unconditional:

Code:
macro test!
        display <? concat '0x', <? tohex 12345 ?>, 10 ?
end macro 
test



Second, you could define the macro with an analogous interceptor inside:

Code:
macro test
        macro ? line&
                ; ...
        end macro
        display <? concat '0x', <? tohex 12345 ?>, 10 ?>
        purge ?
end macro 
test

Post 01 Jun 2017, 09:59
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6436
Location: Kraków, Poland
I remade your sample to show how some of the things may be done differently. I think that use of the namespace is simpler that the name suffix. I also added a "pmacro" variant which can be used to define macro that has preprocessing done for its line. We cannot safely do it for every macro, because applying this universally would also affect out own macros while they need to stay "low level".

Code:
macro imacro_preprocess line&
        local buffer,preprocessed,inline,cursor 
        define buffer line :
        define preprocessed : 
        while 1 
                match a <=? bpreprocessed buffer 
                        redefine preprocessed a 
                        redefine buffer b 

                        match x =?ybuffer 
                                redefine cursor x 
                                redefine buffer y 
                        else 
                                err 'missing ?>' 
                                break 
                        end match 
                        redefine inline : 
                        while 1 
                                match <=? dcursor 
                                        match iinline 
                                                redefine inline i <? 
                                        end match 
                                        redefine cursor d ?
                                else match c <=? dcursor 
                                        match iinline 
                                                redefine inline i c <? 
                                        end match 
                                        redefine cursor d ?
                                else match iinline cursor 
                                        redefine inline i 
                                        break 
                                end match 
                                match =?ybuffer 
                                        redefine buffer y 
                                else match x =?ybuffer 
                                        match ccursor 
                                                redefine cursor c x 
                                        end match 
                                        redefine buffer y 
                                else 
                                        err 'missing ?>' 
                                        break 
                                end match 
                        end while 
                        match :commandinline 
                                imacro_preprocess imacro.command
                                match textpreprocessed $result 
                                        redefine preprocessed text 
                                end match 
                        end match 
                else match apreprocessed buffer 
                        redefine preprocessed a 
                        break 
                end match 
        end while 
        match :command:, preprocessed
                command
        end match
end macro 

macro ? line
        imacro_preprocess line
end macro

define imacro

macro imacro! definition&
        esc macro imacro.definition
end macro

macro end?.imacro! 
        esc end macro  
end macro  

macro ipurge? iname
        purge imacro.iname
end macro

macro pmacro! definition&
        esc macro definition
                macro ? line&
                        imacro_preprocess line
                end macro
end macro

macro end?.pmacro?!
                purge ?
        esc end macro
end macro

macro ppurge? pname
        purge pname
end macro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

imacro concat first*,rest*&
        local result
        result = string first 
        iterate srest 
                result = string result + (sshl (((bsr result - 1shr 3 + 1shl 3
        end iterate
        redefine $result result
end imacro 

imacro tohex number*,digits:8
        local result
        virtual at 0 
                repeat digits 
                        digit = ((numbershr ((%%-%shl 2)) and 0Fh 
                        if digit < 10 
                                db '0'+digit 
                        else 
                                db 'A'+digit-10 
                        end if 
                end repeat 
                load result:$ from 0 
        end virtual
        redefine $result result
end imacro

pmacro test
        display <? concat '0x', <? tohex 12345 ?>, 10 ?
end pmacro
test

Post 01 Jun 2017, 11:05
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6436
Location: Kraków, Poland
Another side note: this (excerpt from your macro) does not work like you probably expected it to:

Code:
local result#n 
match :command argsinline 
        imacro_preprocess resultncommand#_imacro result#nargs

The LOCAL directive defines a parameter (just like it did in fasm 1) so it works similarly to how the macro parameters work. It means that it is only replaced when a token with such name is encountered, so it would replace "result0" but not "result#0". What you should do it in this case is to just use this one:

Code:
local result

at startup, and then every "result#n" is going to become local, because "result" will be replaced with a symbol in local namespace and attaching additional suffix to it will create an additional symbol in local namespace. If this feels like a undocumented feature, you can use "result.value#n" instead - this defines "value#n" symbol in the namespace of "result" symbol, which is local, so everything then is local.
Post 01 Jun 2017, 11:19
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6436
Location: Kraków, Poland

VEG wrote:
Tomasz Grysztar, oh, nice idea! I haven't thought about this use case. It seems that my variant also works with symbolic variables.

What I had in mind there was to allow these inline macros to work like a true preprocessing, for example:

Code:
imacro d mode
        if mode = 16
                $result equ dw
        else
                $result equ dd
        end if
end imacro

<? d 16 ?> -1

Post 01 Jun 2017, 12:04
View user's profile Send private message Visit poster's website Reply with quote
VEG



Joined: 06 Feb 2013
Posts: 68
Location: Minsk, Belarus
Thank you for your examples.


Tomasz Grysztar wrote:
I think that use of the namespace is simpler that the name suffix.


I had used suffix because I thought that it will help to honor current namespace. But it doesn't. Also it doesn't allow to call <? nsname.mname 1,2,3 ?> at all because match gets just the first piece before the dot, so it needs an improvement which will collect all pieces of name with dots. I just thought that it would be nice to preserve behavior of standard macros. It is not a frequent use case of course, so I'll try to do it later.
Post 01 Jun 2017, 13:16
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6436
Location: Kraków, Poland

VEG wrote:
I had used suffix because I thought that it will help to honor current namespace. But it doesn't. Currently, it doesn't allow to call <? nsname.mname 1,2,3 ?> at all because match gets just the first piece before the dot, so it needs an improvement which will collect all pieces of name with dots. I just thought that it would be nice to preserve behavior of standard macros. It is not a frequent use case of course, so I'll try to do it later.

Try matching at the separating space:

Code:
        match inameargsline
                esc macro iname#_imacro resultargs

And perhaps even use a sub-namespace instead of a suffix?

Code:
        match inameargsline
                esc macro iname.imacro resultargs

Post 01 Jun 2017, 13:45
View user's profile Send private message Visit poster's website Reply with quote
VEG



Joined: 06 Feb 2013
Posts: 68
Location: Minsk, Belarus

Quote:
Try matching at the separating space:

Nice, I like this simple solution. I think that I had seen it somewhere in the examples, but haven't noticed how useful it could be and forgot about it.

Quote:
And perhaps even use a sub-namespace instead of a suffix?

But an inline macro name can coincide with a real namespace, and it will define an "imacro" macro inside. It seems that "_imacro" postfix doesn't have any visible drawbacks. Maybe it looks not so beautiful (especially in error messages). But it is not a native solution. We don't have a separate class for inline macros, so we need some thing for differentiation. Actually, first thing that I had tried was the "imacro." prefix, because it looks like the most beautiful and simple solution for a general case. And then I remembered about namespaces...

About pmacro. If "macro" instruction will be redefined after enabling the "macro ?" and defining the imacro_preprocess macros, maybe it will not affect them? Hm... Maybe it will be better to redefine the "macro" instruction, but add some flag which will disable preprocessing inside current macro. Or add an "llmacro" (low-level macro) instruction for special cases. It worth to think how to make it better Smile
Post 01 Jun 2017, 15:25
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6436
Location: Kraków, Poland

VEG wrote:
About pmacro. If "macro" instruction will be redefined after enabling the "macro ?" and defining the imacro_preprocess macros, maybe it will not affect them?

One of the problems is that even the "imacro" needs to use the "macro" internally.
Post 01 Jun 2017, 15:56
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6436
Location: Kraków, Poland
As a curiosity: it also might be possible to redefine "macro" locally by embedding the area of source in a child namespace while using the "macro" instruction from the outer namespace when needed. But this is a very very tricky and fragile construction:

Code:
define original_macro macro

namespace embedded
postpone
        end namespace
end postpone

match _macrooriginal_macro
        _macro macro?! definition&
                _macro end?.macro?!
                        purge ?
                        esc end macro
                        purge end?.macro?
                end macro
                esc _macro definition
                esc esc _macro ? line&
                        imacro_preprocess line
                esc esc end macro
        end macro
end match

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

macro test
        display <? concat '0x', <? tohex 12345 ?>, 10 ?>
end macro

test

Post 01 Jun 2017, 16:17
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6436
Location: Kraków, Poland
Scrap the above, it actually works much better if there is a proxy macro for END too:

Code:
define original_macro macro
define original_end end

namespace embedded
postpone
        end namespace
end postpone

define end?

match _macro:_endoriginal_macro:original_end
        iterate directivemacro,struc,virtual,namespace,if,match,rmatch,rawmatch,while,repeat,iterate,rept,irp,irpv,postpone
                _macro end?.directive?!
                       esc  _end directive
                _end macro
        end iterate
        _macro end?! directive
                end?.directive
        _end macro
        _macro macro?! definition&
                esc _macro definition
                _macro ? line&
                        imacro_preprocess line
                _end macro
        _end macro
        _macro end?.macro?!
                purge ?
                esc _end macro
        _end macro
end match

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

macro test
        display <? concat '0x', <? tohex 12345 ?>, 10 ?>
end macro

test

This one is less tricky (the double ESC that previous one had to use is something that should not have to happen normally) and it works correctly even with nested macros.

Note that to allow "imacro" definitions to be processed correctly in the embedded namespace you have to make them use the original MACRO and END directives in the same way.
Post 01 Jun 2017, 18:59
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page Previous  1, 2

< Last Thread | Next Thread >

Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001-2005 phpBB Group.

Main index   Download   Documentation   Examples   Message board
Copyright © 2004-2016, Tomasz Grysztar.