flat assembler
Message board for the users of flat assembler.

Index > Compiler Internals > [fasmg/fasm2]Predicted calm

Author
Thread Post new topic Reply to topic
m_stery



Joined: 08 Nov 2024
Posts: 9
m_stery 18 Mar 2026, 22:17
The predicted instruction has different local variables than the defined one?

Test just display number of call, but after definition its start from 0 again.
Code:
test    1
test    2
calminstruction test?! arg
        local   tmp,i
;       take    i,arg.i         ; Try remove comment
        take    i,i
        jyes    ready
        compute i,0
        ready:
        compute i,i+1
        arrange tmp,i:arg
        stringify       tmp
        display tmp bappend 10
;       take    arg.i,i         ; And this
end calminstruction     
test    3
test    4
    

Was it even intended to call macros before defining them using prediction?
Post 18 Mar 2026, 22:17
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8518
Location: Kraków, Poland
Tomasz Grysztar 19 Mar 2026, 05:53
The LOCAL command in CALM instruction initializes the variable with a new value. As the manual states it:
fasmg manual wrote:
... is initally assigned a defined but unusable value.
This phrasing is perhaps not sufficiently precise - it should be stressed that this initialization is what the LOCAL command does at the definition time of CALM instruction, which in your case is in the middle of the source.

This is why the effect disappears if you remove the LOCAL command (even though the variable may still be local, unless a global symbol with the same name is declared).

m_stery wrote:
Was it even intended to call macros before defining them using prediction?
Yes, it was one of the fundamental assumptions of fasmg architecture. What misled you here is the fact that the LOCAL command does something at the time of definition of instruction.

I could perhaps change it so that LOCAL would only make the unusable value when the symbol has no value to begin with. Let me try and test it, although I'm not sure if making the behavior even more complex is the right way.
Post 19 Mar 2026, 05:53
View user's profile Send private message Visit poster's website Reply with quote
m_stery



Joined: 08 Nov 2024
Posts: 9
m_stery 19 Mar 2026, 13:30
Tomasz Grysztar wrote:

I could perhaps change it so that LOCAL would only make the unusable value when the symbol has no value to begin with. Let me try and test it, although I'm not sure if making the behavior even more complex is the right way.


Leave it as it is. I was just testing what can and cannot be done. Basically nothing like local, or init, initsym from 'xcalm.inc' is executed until the instruction is defined

if the command 'local' did not delete the previous one ...

Code:
        
calminstruction test?
                local   i
                init    i,0     ;the 'i' has a value 0
                ...
                local   i       ;after this the 'i' has an unusable value
                ...
end calminstruction
    


BTW
Isn't the result always true, when using 'check defined/definite some_local_var', where some_local_var has the unusable value?
Post 19 Mar 2026, 13:30
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8518
Location: Kraków, Poland
Tomasz Grysztar 19 Mar 2026, 13:54
m_stery wrote:
Basically nothing like local, or init, initsym from 'xcalm.inc' is executed until the instruction is defined
The INIT/INITSYM macros are executed at the time when CALM instruction is defined. Only if such macros generate and assemble lines containing actual CALM commands, they can have something done at the run-time of CALM instruction.

To be even more precise, something like TAKE or COMPUTE is an ALM instruction that emits a CALM binary opcode into the compiled code of CALM macro. LOCAL is an ALM instruction that does not emit any CALM opcode, it only does something at the time of definition. Macros that you define in CALMINSTRUCTION namespace, like INIT/INITSYM are ALM instructions, evaluated at the time of definition. Such macros may in turn emit some instructions that generate CALM binary code, but INIT/INITSYM do no such thing.

I tried to describe this in detail in the auxiliary documentation, but maybe another reframing, like my attempt above, could be a good addition to the manual.

m_stery wrote:
Isn't the result always true, when using 'check defined/definite some_local_var', where some_local_var is the variable, defined by calminstruction's local?
When "some_local_var" is a symbolic variable (and CALM variables usually are), the DEFINED/DEFINITE do not check the status of this variable, but instead of the expression that sits inside the variable. For example if "arg" is variable holding an argument to the macro, then "if defined arg" checks the symbol name given by the argument. See also my recent post about it, plus the related thread.

BTW, for an interesting example of something that is only possible thanks to a forward-referenced macro, see my fasmg-specific quine.
Post 19 Mar 2026, 13:54
View user's profile Send private message Visit poster's website Reply with quote
m_stery



Joined: 08 Nov 2024
Posts: 9
m_stery 20 Mar 2026, 01:08
It's written exactly in the documentation.
"A symbol made local is initally assigned a defined but unusable value. "
BTW: This is in the flat assembler g User Manual (line 2153 perhaps?) "initally" -> "initially"

But I assumed wrongly:
*CALM command 'local' would not overwrite an already valid value, and it does
*CALM command 'take' would remove 'unusable', when it is not used as the value of another symbol. If no value to remove so nothing removed

This CALMINSTRUCTION does what I wanted
Code:
test    1       ;Output:        1:1
test    2       ;Output:        2:2
calminstruction test?! arg
        local   i,tmp
        take    ,i                      
        jyes    ready
        compute i,0             
        take    ,i                      
        take    i,i                     
        jyes    ready
        compute i,0             
        ready:
        compute i,i+1
        arrange tmp,arg:i
        stringify       tmp
        display tmp bappend 10
        compute tmp,i           
        take    i,tmp                   
end calminstruction
test    3       ;Output:        3:3
test    4       ;Output:        4:4
    

So the question is, can I initialize the variables before definition and return the last value after definition
That was the original (useless) idea
Post 20 Mar 2026, 01:08
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8518
Location: Kraków, Poland
Tomasz Grysztar 20 Mar 2026, 07:23
As I mentioned before, you could remove LOCAL and rely on implicit localness (when no global symbol with such name exists, a local one is used anyway), although this is only practical when you use a rarer name.

However, you could also make use of a symbol in a dedicated namespace controlled by you, something like:
Code:
test    1
test    2

define LINK test

namespace testing

        define i        ; force i to be in the "testing" namespace

        match test, LINK        ; define instruction with global name
                calminstruction test?! arg
                        local   tmp
                        take    i,i
                        jyes    ready
                        compute i,0
                        ready:
                        compute i,i+1
                        arrange tmp,i:arg
                        stringify       tmp
                        display tmp bappend 10
                end calminstruction
        end match

        restore i       ; after the definition is completed, we can bring back previous value (if any)

end namespace

test    3
test    4    
or another, perhaps simpler, approach:
Code:
test    1
test    2

namespace testing
        define LINK i
end namespace

match i, testing.LINK   ; get "i" with context of the "testing" namespace

        define i        ; force i to be in the "testing" namespace

        calminstruction test?! arg
                local   tmp
                take    i,i
                jyes    ready
                compute i,0
                ready:
                compute i,i+1
                arrange tmp,i:arg
                stringify       tmp
                display tmp bappend 10
        end calminstruction

        restore i       ; after the definition is completed, we can bring back previous value (if any)

end match

test    3
test    4    
In general you're better off taking full control of your specialized symbols.

While experimenting with various solutions, I discovered that PUBLISH does not follow the standard "symbol is defined" code path (and because of that INIT does not enforce symbol localness). I think I should correct it, since it is likely to be a relic of early CALM design iterations, but I need to do more tests to see if it would break anything.
Post 20 Mar 2026, 07:23
View user's profile Send private message Visit poster's website Reply with quote
m_stery



Joined: 08 Nov 2024
Posts: 9
m_stery 20 Mar 2026, 21:49
Thank you very much. I realize that I have often made very similar mistakes and did not see them. But now I finally see it more clearly and I thank you very much.

I prefer to hide private variables in a macro rather than have them in global scope. I pass the frontend via an argument

Code:
macro   init_test name*
        local   i

        calminstruction name?! 
        
        ...
        
        end calminstruction
        purge init_test
end macro
    
Post 20 Mar 2026, 21:49
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8518
Location: Kraków, Poland
Tomasz Grysztar 20 Mar 2026, 21:53
Excellent solution!
Post 20 Mar 2026, 21:53
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-2026, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.