Internal Strings .



The Macro Parser manages 100 internal Data storages (128 bytes each) where you can store what you want, under a text form, with, for example:


[MacroName1 | ... | &3=Some#1 | ...]


If MacroName1 is invoked with:


MacroName1 Where


... The Macro parser will store 'SomeWhere'  in 'internal_Data_3. If this Evocation of 'MacroName' is followed, for example, by


[MacroName2 | nop | mov D$&3 0 | nop | ...]


... evocation of:


MacroName2 


... will be unfolded as:


Nop | mov D$SomeWhere 0 | nop | ...


The order of Declarations in source has no importance. All this is based on the order of Evocations .


The Internal Data are never zeroed, just overwritten as the Macro Evocations come out, in the source order. The effective order is not the Declarations order but the Evocations order. To clear an internal Data:


[ClearIntern3 | &3= | ...]

 

ClearIntern3


These internal Data and nested Declarations with substitutes are useful for HLL style developments, for building  full HLL- like syntaxes with advanced features (Proc / Arguments / Local / Structures / Uses / EndP).



The Macro Parser Internal storages are from &1 to &99.


&0 is reserved to provide meaningless automatic Labels when declaring Data in Macros.


Example:


[Argh: 'Aaarrrghhh!!!!....', 0]


[MessageBox | {&0=#2} | {&1call 'USER32.MessageBoxA' &NULL, &0, #1, &MB_SYSTEMMODAL__&MB_OK]


... to be called, for example, by:


MessageBox  Argh , 


                        'Oh! No, please!!! not that again!... I want to sleep now!'


The internal replacement Labels are in the form of 'ZZZZZZZZ' / 'ZZZZZZZY' / ... Each time an evocation requires an '&0:' declaration, the Parser decreases the trailing characters and performs the substitutions. Each time a Macro evocation requires an '&0' Label evocation, it uses this substitute.


You cannot use '&0' to store anything on your own, like you do with other 99 internal storages.


Limitation: you can only use the Automatic Labels one by one. That is, you create one Automatic Label with the '&0:' declaration, and you can use it (Evocation) as many times as you like, but you cannot make use of two different Automatic Labels, in one Declaration.


Note that this limitation does not make it impossible to have as many meaningless automatic Labels as you really want: You can, of course, nest the macros. Example:


[MessageBox | {&0: #2 0} | MessageBoxTitle #1

 call 'USER32.MessageBoxA' &NULL, &0,  eax, &MB_SYSTEMMODAL__&MB_OK]


[MessageBoxTitle | {&0: #1 0} | mov eax &0]


MessageBox 'Application Base',  '

   This file is not a Demo. It is a 'StartUp'

   Base You can use to develop your own work.   '



Examples of '&' usages


For/Next Loops


It is a well known organization encountered in all Basic Sources. Here is how to build a Macro for this, with very few limitations (only the number of available characters for local Labels):



[For | push ecx | &4=#5 | &5=1 | &5=#7>L | mov D$#1 #3 | &6=#1 | &7=0 |  &6_&7: | push &4 | push &5]


[Next  | pop ecx | add D$#1 ecx | pop ecx | cmp D$#1 ecx | &6=#1 | &7=0 |  jbe &6_&7<< | pop ecx]

[Negxt | pop ecx | sub D$#1 ecx | pop ecx | cmp D$#1 ecx |  &6=#1 | &7=0 |  jae &6_&7<<  | pop ecx]


; I use a, b, c,... instead of i, j, k, ... because 'i' is  usually for If and friends.

;

; Note: Uses ecx and the Stack internally.


[a: 0    b: 0    c: 0    d: 0    e: 0    f: 0]


; To be used, for example as:


    For a = 1 to 5

        hexprint D$a            ; shows 1 / 2 / 3 / 4 / 5

    Next a


    For a = 1 to 5, Step 2

        hexprint D$a            ; Shows 1 / 3 / 5


        For b = 1 to 2

            hexprint D$b        ; shows 1 / 2 // 1 / 2 // 1 / 2


            For c = 0400 to 0100, Step 0100

                hexprint D$c    ; shows 0400 / 0300 / 0200 / 0100 // ....

            Negxt c


         ; (Negxt is the Negative Stepping form).


        Next b


    Next a


Note, that in:


[For | ...  ]


' | &5=1 | &5=#7>L | ' This is a bit tricky, and may be difficult to understand:


In 'For b = 1 to 2', for example, there is nothing on the line for '&5=#7>L '. So it does nothing and &5 is simply set to 1. In 'For a = 1 to 5, Step 2', '&5=#7>L ' does its job; this is to say, only stores 2 in &5. 'To' and 'Step' keywords are fully dummy representations only and are there only for the visual comfort of the user!  '#7>L ' is used instead of  '&5=#7', just to allow no parameters. This is the most tricky point.



Multi-If


I recommend, for If and friends the use of Macros beginning with points (the one given in the BaseX.exe files). They greatly increase readibility and, so forth, to prevent the many usual organization errors. Another point is that, having too many nested If structures, gives unreadabe and difficult to maintain sources. Your If chunks should be limited to 3 of 4 nested levels. If this is not enough, reorganize with a call to another Routine, even if the internal logic of the source would not require this; or mix with other statements (Select_Case / ...)


But if you really want a true HLL-like If statement, this is possible too. Example with 10 nested Levels:


[.If | cmp #1 #3 | jn#2 I0>>]

[..If | cmp #1 #3 | jn#2 I1>>]

[...If | cmp #1 #3 | jn#2 I2>>]

[....If | cmp #1 #3 | jn#2 I3>>]

[.....If | cmp #1 #3 | jn#2 I4>>]

[......If | cmp #1 #3 | jn#2 J0>>]

[.......If | cmp #1 #3 | jn#2 J1>>]

[........If | cmp #1 #3 | jn#2 J2>>]

[.........If | cmp #1 #3 | jn#2 J3>>]

[..........If | cmp #1 #3 | jn#2 J4>>]


[.Else_If | jmp I5>> | I0: | cmp #1 #3 | jn#2 I0>>]

[..Else_If | jmp I6>> | I1: | cmp #1 #3 | jn#2 I1>>]

[...Else_If | jmp I7>> | I2: | cmp #1 #3 | jn#2 I2>>]

[....Else_If | jmp I8>> | I3: | cmp #1 #3 | jn#2 I3>>]

[.....Else_If | jmp I9>> | I4: | cmp #1 #3 | jn#2 I4>>]

[......Else_If | jmp J5>> | J0: | cmp #1 #3 | jn#2 J0>>]

[.......Else_If | jmp J6>> | J1: | cmp #1 #3 | jn#2 J1>>]

[........Else_If | jmp J7>> | J2: | cmp #1 #3 | jn#2 J2>>]

[.........Else_If | jmp J8>> | J3: | cmp #1 #3 | jn#2 J3>>]

[..........Else_If | jmp J9>> | J4: | cmp #1 #3 | jn#2 J4>>]


[.Else | Jmp I5>> | I0:]

[..Else | Jmp I6>> | I1:]

[...Else | Jmp I7>> | I2:]

[....Else | Jmp I8>> | I3:]

[.....Else | Jmp I9>> | I4:]

[......Else | Jmp J5>> | J0:]

[.......Else | Jmp J6>> | J1:]

[........Else | Jmp J7>> | J2:]

[.........Else | Jmp J8>> | J3:]

[..........Else | Jmp J9>> | J4:]


[.End_If | I0: | I5:]

[..End_If | I1: | I6:]

[...End_If | I2: | I7:]

[....End_If | I3: | I8:]

[.....End_If | I4: | I9:]

[......End_If | j0: | j5:]

[.......End_If | j1: | j6:]

[........End_If | j2: | j7:]

[.........End_If | j3: | j8:]

[..........End_If | j4: | j9:]


[If | &6=&6. | &6If #1>L]

[Else_If | &6Else_If #1>L]

[Else | &6Else]

[End_If | &6End_If | &6=&6!]



mov eax 1, ebx 2, ecx 33


If eax = 1

    hexprint 01

    If ebx = 1

        Hexprint 0101

    Else_If ebx = 2

        Hexprint 0102

        If ecx = 3

           hexprint 010203

        Else

            hexprint 07777

        End_If

    End_If

End_If



In '| &6=&6. |',  we simply add a point to the sixth storage. In '| &6=&6!]' , we simply retrieve a point from it.


The limit is only due to the number of available Characters for local Labels * 5 (!!!). Here, 10 nested levels; this is to say, in my opinion, too much.



General considerations about '&'


'&' is a very powerful and unique feature of RosAsm Macros Parser. It allows you to build organizations that would be fully impossible with another Assembler Macros Parser. As this feature is strictly limited to 9 storages, do not spoil them with few use managements. Try to write your Macros in a way that allow them to run with as few '&x' as possible.


You are responsible for the management of these storages. Pay attention to not reusing an already in use storage. Each time you want a new one, verify carefully that is is not used by another Macro. This kind of error is difficult to point out when done. The 'Proc' Macros I provide use 3 storages, upper 'For' uses 2 and 'Multi If' only 1.


As a side note, give consideration to the fact, that true low level conditional Jumps will always be much more powerful and flexible than any HLL Macros set ever will.


 In the more complex cases, do not be afraid of a little bit of Spaghetti Style. Spaghetti style is not death, as long as it remains confined to a very short scope, in the code flow, and as long as you clearly master what is going on (The art of programming...).


~~~~~~~