Megatokio/zasm

Adding value interpretation brackets in macros

Closed this issue · 11 comments

In order to achieve higher level macro automation, having value evaluation escape characters would be nice. I'm already in the process of implementing the feature. To give you an example of what I try to achieve, I'll add my test source files to this issue.

Int the following files, I'm trying to interpret the resulting value between '{' and '}'

callstack.z80.txt
test_callstack.z80.txt

This is a simplified example:

_STACK_SIZE     DEFL    0
_PARAM_COUNT_0  DEFL    0

                MACRO   _PUSH_STACK &cnt
                IF ({&cnt} > 0)
_PARAM_COUNT_{&cnt} DEFL _PARAM_COUNT_{&cnt-1}
_PARAM_COUNT_{&cnt-1} DEFL 0
                _PUSH_STACK {&cnt-1}
                ENDIF 
                ENDM

; _STACK_SIZE is expected to be inremented somewhere else ad to be used as the _PUSH_STACK initial parameter.
; Calling _PUSH_STACK 1 should expand the macro source like this:

                IF (1 > 0)
_PARAM_COUNT_1 DEFL _PARAM_COUNT_0
_PARAM_COUNT_1 DEFL 0
                _SHIFT_STACK 0
                ENDIF 

Mabe there is caveats that I don't see yet in doing so, especially with recursive macros. There may be other consideration that should be taken as well. I did not do a thorough code analysis but I did just enough to have a good idea how to implement this feature.

Any suggestion is welcome.

Created the pull request #4 that implement this feature.

hi, the current source changes have some problems:
this way { .. } is handled exactly like ( .. ) in all expressions.
there should be no change to function value(..),
instead in asmMacroCall() after finding '{' call value() and on return call expect('}') and also test that the returned value.is_valid().
to my surprise "PARAM_COUNT-1" is a valid label name (at least in a DEFL definition)
i think just {..} for the text replacement expression is to ambiguous (though not yet, as { and } is not used at all up to now). most script languages which do similar things prepend a special char to the '{'. '$' is probably out, but evtl. '@' or any better suggestion?
please put the test file in Test/Z80/ and the resuting output file in Test/Z80/original. please combine the source into a single file and it must be named "*.asm"
nested macros: {..} will shurely be evaluated in the outermost macro. if evaluation inside a nested macro makes a difference to evaluation in the outermost macro and if this is required (for you) then a way to go could be to nest {} and test for it in evaluation, e.g. @{{...}} becomes to @{...} in outermost macro resolution and is evaluated and replaced in nested macros.

Hi @Megatokio, I'll try to implement your suggestions as much as I can. new pull request coming soon...

I'm not sure I understand your last statement about @{{...}}. I'll leave that suggestion out of my implementation for now.

Ok, to interpret the @ character correctly, it must become a word: "@{". Means that I have to get into the interpreter more complex code to do my things.

Changed macro interpretation from @{...} to @(...) it is way easier like this.

Sadly this feature won't help me for my objective since macro world is unaware of the assembly compilation at all (that is now obvisous to me). I will do a pull request and you will be able to see what I mean in the EXP subroutine. The macro level call stack still think it is at LEVEL 0 while it becomes LEVEL 1 (calling EXP in turns calls MUL).

The feature is useful in the context where a macro function calls another macro function when you want to pass label content by value instead of textually.

hi formix, i reviewed your code and don't fully understand what you try to do, though the final intent is clear.
yes, macros do a stupid text replacment unaware of code flow or program logic.
normally a text replacement is worse than value evaluation, because text replacement can only be done in pass 1. but for generating label names it is useful, e.g. if a macro contains labels and is used more than once. (local .. endlocal inside macro would be handy.)
At many places where you use your suggested textual replacement you could simply use the value instead, e.g. line 85: LD &reg, (IY+@(&idx*2)) or *LD &reg,(IY+(&idx)2) would probably have the same effect.

the code for zasm still has that chande to function value() itself and no test for .is_valid() which is required to prevent use of not-yet-defined/evaluated labels.
thinking over it i'd now prefer {..} as you first suggested.
i'll fix and add the changes today and use your test files for checking.

btw. 'literal' only 1 't' and push hl;ret can be replaced with jp (hl).
Kio !

hi, i fixed and merged the feature in another merge request.
version 4.2.6 now supports '{..}' replacement in macros.
i thought it would be easier this way.

Ok good, the code is simpler using {} and it still make sense (like python's string interpolation).

About my test code, you are right about the example you give. Te real advantage of that is when doing recursive calls like that:

macro CLEAN_PARAM &paramCount
  CALL _POP
  IF &paramCount > 1
    CLEAN_PARAM {&paramCount - 1}
  ENDIF

I will update the callstack.asm code tomorrow with my actual "production" code. I think it is cleaner ans easier to understand.

thanks!

hi, i hope you could solve your goal with this new feature.
if there is still a problem feel free to reopen the issue.
thanks&greetings :-)

It fixes my issue. Thanks for your help on this!