flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > [solved] Macro ?! / esc instruction

Author
Thread Post new topic Reply to topic
MaoKo



Joined: 07 May 2019
Posts: 100
Location: Paris/French
MaoKo 08 May 2019, 01:08
Hello Tomasz. I have a problem with the macro ? and esc instruction. In the macro body the line& is put inside a macro invoker to avoid some break of nesting level. In the basis case I don't understand why this not work with both esc and just "line":
Code:
macro ?! line&
  macro invoker
    esc line
  end macro
  invoker
  purge invoker
end macro
macro _test
end macro
    

The above macro invoker seem pretty useless but with some test/match before about line, it's very useful.
My goal is to declare successfully the macro _test without any error about missing end.
Also I don't understand why this code seem to be an infinite loop on my system:
Code:
struc ?!
  local _
  _expand
end struc
macro _expand?
  macro ?! line&
    line
  end macro
end macro
x
x
    

Without "local _" there is not infinite loop witch is pretty weird.
Have a good day Smile


Last edited by MaoKo on 07 Oct 2019, 02:35; edited 1 time in total
Post 08 May 2019, 01:08
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8356
Location: Kraków, Poland
Tomasz Grysztar 08 May 2019, 09:09
Once you started the macro definition, it is not possible to define or call the "invoker" macro, because these lines then become part of the body of the macro that is being defined. When you are using a strong interceptor ("macro ?!") you cannot simply let all lines pass through, you have to process the syntax manually. It might look for example like this:
Code:
define macroBuilder?
macroBuilder.ACTIVE = 0

macro macroBuilder? declaration&
        macro macroBuilder?.definition
                esc macro declaration
        end macro
        macroBuilder?.ACTIVE = 1
end macro

macro macroBuilder?.line? content&
        macro macroBuilder?.definition
                macroBuilder?.definition
                content
        end macro
end macro

macro macroBuilder?.end?
        macroBuilder?.definition
        esc end macro
        macroBuilder?.ACTIVE = 0
end macro

macro lineInvoker? ln&
        ln
end macro

macro ?! ln&
        match =macro? declaration, ln
                macroBuilder declaration
        else match =end? =macro?, ln
                macroBuilder.end
        else if macroBuilder?.ACTIVE
                macroBuilder.line ln
        else
                lineInvoker ln
        end if
end macro


macro _test msg:'OK!'
        display msg
end macro

_test    
________________________________________________________________________________

Important note: the "lineInvoker" as an additional layer of encapsulation is really needed here. If you just let "line" be placed into your main macro, it would lead to situations like:
Code:
else
        ln
end if    
becoming:
Code:
else
        macro _test
end if    
And because fasmg keeps track of nesting, it then sees END IF as being part of a macro so it does not close the ELSE block, which messes up everything - even though the ELSE part might not have been evaluated at all.
Keep in mind that ESC would not help here, since it would be processed out at the time when the outer macro is defined, therefore it would not make any difference.
________________________________________________________________________________

Alternatively, you may try disabling your preprocessor for the duration of macro definition:
Code:
macro Preprocessor_ON
        macro ?! line&
                macro invoker
                       esc line
                end macro
                match =macro? declaration, line
                        Preprocessor_OFF
                        macro end?.macro?!
                                esc end macro
                                purge end?.macro?
                                Preprocessor_ON
                        end macro
                end match
                invoker
        end macro
end macro

macro Preprocessor_OFF
        purge ?
end macro

Preprocessor_ON


macro _test msg:'OK!'
        display msg
end macro

_test    
Post 08 May 2019, 09:09
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8356
Location: Kraków, Poland
Tomasz Grysztar 08 May 2019, 09:55
MaoKo wrote:
Also I don't understand why this code seem to be an infinite loop on my system (...) Without "local _" there is not infinite loop witch is pretty weird.
The line does not have to be LOCAL at all, even an empty line placed there causes the loop. Moreover, there needs to be another line after the second "x" - if you remove the line break and make second "x" the last line of source, the problem also does not show up:
Code:
struc ?!

  _expand
end struc
macro _expand?
  macro ?! line&
    line
  end macro
end macro
x
x
    
First, you define an unconditional label interceptor. This catches any lines that starts with a symbol identifier which is not a known instruction (so can be a label). Note that it has no arguments, so would cause an error if enountered a line containing a label followed by anything more. But what is the most important here is that it is unconditional, so it is evaluated no matter what. And while the lines starting with MACRO or END are known instructions, so they do not invoke the label interceptor, the "line" line does. So you end up having a macro defined this way:
Code:
macro _expand?
  macro ?! line&
 
  _expand
  end macro
end macro    
Now let's analyze what happens when the "x" lines are processed, step by step:
  • First "x" is not a known instruction, so it calls the label interceptor, which in turn executes "_expand" macro.
  • Interceptor "macro ?!" gets defined (with body containing a call to "_expand"), let's call it interceptor 1.Processing of first "x" ends.
  • The second "x" is now intercepted by "macro ?!", which calls the "_expand" macro.
  • Additional "macro ?!" is defined on top of the previous one (let's call it interceptor 2), the processing of second "x" ends.
  • The empty line that follows is caught by the interceptor 1. It start executing its lines.
  • Now the body of that macro starts with another empty line. This one is caught by interceptor 2.
  • Interceptor 2 executes "_expand" and defines interceptor 3 on top of the existing ones.
  • We now proceed to the second line of interceptor 1, this one is "_expand". It is caught by interceptor 3.
  • The first (empty) line of interceptor 3 is caught by interceptor 2. It executes "_expand" and defines interceptor 4.
  • The "_expand" line of interceptor 3 is now caught by interceptor 4.
  • The first (empty) line of interceptor 4 is caught by interceptor 2. It executes "_expand" and defines interceptor 5.
  • The "_expand" line of interceptor 4 is now caught by interceptor 5.
  • The first (empty) line of interceptor 5 is caught by interceptor 2. It executes "_expand" and defines interceptor 6.
  • And so on...
You can observe this by adding an "-r" switch in the command line. No matter what number you choose for the limit, it is going to be "_expand" call that first reaches the nesting limit:
Code:
C:\asm\fasmglab>fasmg a.asm -r8
flat assembler  version g.ije6q
a.asm [12]:

macro ? [2] macro ? [2] macro ? [2] macro ? [2] macro ? [1] macro ? [2] macro _expand [3]:
        _expand
Processed: _expand
Error: exceeded the maximum allowed depth of stack.

C:\asm\fasmglab>fasmg a.asm -r9
flat assembler  version g.ije6q
a.asm [12]:

macro ? [2] macro ? [2] macro ? [2] macro ? [2] macro ? [2] macro ? [1] macro ? [2] macro _expand [3]:
        _expand
Processed: _expand
Error: exceeded the maximum allowed depth of stack.

C:\asm\fasmglab>fasmg a.asm -r10
flat assembler  version g.ije6q
a.asm [12]:

macro ? [2] macro ? [2] macro ? [2] macro ? [2] macro ? [2] macro ? [2] macro ? [1] macro ? [2] macro _expand [3]:
        _expand
Processed: _expand
Error: exceeded the maximum allowed depth of stack.    
Note how "_expand" is called by a second line of a macro that intercepted the first line of another interceptor - this is consistent with the step-by-step explanation above.

Applying unconditional interceptors globally is like playing with fire, please use them carefully and sparingly.
Post 08 May 2019, 09:55
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:  


< 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


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.