flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > [fasmg] Trying to make sense of defined/definite/eqtype:

Author
Thread Post new topic Reply to topic
bitRAKE



Joined: 21 Jul 2003
Posts: 4161
Location: vpcmpistri
bitRAKE 26 Feb 2025, 23:10
In the past I've created some small tables I thought were missing from the manual - just a dense refresher of organized concepts. Whether you’re working with forward references, blank symbols, or numeric constants, the following cheat sheet explains fasmg's behavior in one place - with code.
Code:
; Some things to note:
;       + variable symbols are different based on where they are defined
;               - similar to forward symbols if already defined
;               - similar to undefined symbols if not defined, yet
;       + blank symbols are special case(s) (that depth will catch you!)
;       + defined symbols resolve to their values
;         (regardless if they are forward/variable symbols)
;       + floats can be compared to integers
;
;       absent          ; symbol not present, by design

; This can NOT be forward referenced:
; (It doesn't matter because there is no code above.)
        restore vary
        define vary blank

iterate TYPE,\
        absent,\        ; ~defined, ~definite
        vfwd,\          ; ~defined, ~definite, forward variable same as absent
        blank,\         ; defined, special case
        here,\          ; defined, forward resolves to blank value
        vary,\          ; defined, variable resolves to blank value
        1,-1,0,\        ; definite
        reg+2,\         ; defined, ~definite
        '',\            ; definite
        0.0,0.1,-3.2    ; definite


        display 10,`TYPE,9
        if defined TYPE
                display ' defined,'

                ; blank special cases
                match ,TYPE
                        display ' blank'
                else
                        match temp,TYPE ; special case, deref blanks
                        match ,temp
                                display ' blank+'
                        else
                                ; note: blanks can be nested deep
                                ; (we stop early, assuming all symbols resolve to non-blank)

                                if definite TYPE
                                        display ' definite, '

                                        if TYPE eqtype ''
                                                display 'string'
                                        else if TYPE eqtype 0 ; algebraic
                                                display 'algebraic, '
                                                if TYPE relativeto 0
                                                        display 'integer, '
                                                        if TYPE > 0
                                                                display 'positive'
                                                        else if TYPE < 0
                                                                display 'negative'
                                                        else if TYPE = 0
                                                                display 'zero'
                                                        else
                                                                display 'ERROR'
                                                        end if
                                                else
                                                        display 'unknown',10
                                                end if
                                        else if TYPE eqtype 0.0 ; float
                                                display 'float, '
                                                if TYPE > 0
                                                        display 'positive'
                                                else if TYPE < 0
                                                        display 'negative'
                                                else if TYPE = 0
                                                        display 'zero'
                                                else
                                                        display 'ERROR'
                                                end if
                                        else
                                                display 'unknown',10
                                        end if
                                else
                                        display '~definite, algebraic, linear polynomial'
                                end if
                        end match
                        end match
                end match
        else
                display '~defined'
        end if
end iterate

; These can all be forward referenced, above:
        define blank            ; blank
        define here blank       ; present and defined, but resulting in blank

        element reg             ; algebraic term

; This can NOT be forward referenced, code above doesn't "see" it:
        restore vfwd
        define vfwd blank    
... and the output:
Code:
absent  ~defined
vfwd    ~defined
blank    defined, blank
here     defined, blank+
vary     defined, blank+
1        defined, definite, algebraic, integer, positive
-1       defined, definite, algebraic, integer, negative
0        defined, definite, algebraic, integer, zero
reg+2    defined,~definite, algebraic, linear polynomial
''       defined, definite, string
0.0      defined, definite, float, zero
0.1      defined, definite, float, positive
-3.2     defined, definite, float, negative    
... just another perspective. I've literally been caught by all the nuance in my work, several times, each. Very Happy

_________________
¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup
Post 26 Feb 2025, 23:10
View user's profile Send private message Visit poster's website Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4161
Location: vpcmpistri
bitRAKE 27 Feb 2025, 01:50
So, how do we use this information?

If there is some complex interaction in syntax we can think in terms of where things need to be in the code, and the operations available to resolve the state of the interaction.

For example, we want a default action when the symbol isn't defined. Yet, we want different levels of action if the symbol isn't blank. The user might do "define VERBOSE" or "VERBOSE=2". Also we don't want the user doing multiple things - creating confusion.

How do we implement this?

If we try to access the forward value, ambiguity acts the same as ~defined.

If we access the symbol using POSTPONE then there is no way to resolve ambiguity either.
Code:
if defined VERBOSE
        ; option is forward referrenced, defined once
        OPTIONS.VERBOSE = 1
else
        ; option is undefined or user created ambiguity
        OPTIONS.VERBOSE = 0
end if
postpone
        if defined VERBOSE
                if OPTIONS.VERBOSE
                        display 10,"using VERBOSE option"
                        ; todo: resolve blank or value
                else
                        err "only use one VERBOSE setting"
                end if
        else
                display 10,"using default VERBOSE setting"
        end if
end postpone    
... we must use both.

Try out the options and errors yourself:
Code:
include 'verbose.inc'
;       define VERBOSE
;       VERBOSE = 2
;       VERBOSE = 1    
You may think this rather complex, but it does force the use of VERBOSE to fit the interface we defined.
Post 27 Feb 2025, 01:50
View user's profile Send private message Visit poster's website Reply with quote
dosmancer



Joined: 20 Feb 2025
Posts: 7
Location: Kingdom of Sweden
dosmancer 27 Feb 2025, 17:45
Nice tables! They might be handy as a reference.

I tried to add some more tests out of curiosity:

Code:
; Some things to note:
;       + variable symbols are different based on where they are defined
;               - similar to forward symbols if already defined
;               - similar to undefined symbols if not defined, yet
;       + blank symbols are special case(s) (that depth will catch you!)
;       + defined symbols resolve to their values
;         (regardless if they are forward/variable symbols)
;       + floats can be compared to integers
;
;       absent          ; symbol not present, by design

; This can NOT be forward referenced:
; (It doesn't matter because there is no code above.)
        restore vary
        define vary blank

iterate TYPE,\
        absent,\        ; ~defined, ~definite
        vfwd,\          ; ~defined, ~definite, forward variable same as absent
        blank,\         ; defined, special case
        here,\          ; defined, forward resolves to blank value
        vary,\          ; defined, variable resolves to blank value
        1,-1,0,\        ; definite
        reg+2,\         ; defined, ~definite
        '',\            ; definite
        0.0,0.1,-3.2,\    ; definite
        x,\
        y,\
        z


        display 10,`TYPE,9
        if defined TYPE
                display ' defined,'

                ; blank special cases
                match ,TYPE
                        display ' blank'
                else
                        match temp,TYPE ; special case, deref blanks
                        match ,temp
                                display ' blank+'
                        else
                                ; note: blanks can be nested deep
                                ; (we stop early, assuming all symbols resolve to non-blank)

                                if definite TYPE
                                        display ' definite, '

                                        if TYPE eqtype ''
                                                display 'string'
                                        else if TYPE eqtype 0 ; algebraic
                                                display 'algebraic, '
                                                if TYPE relativeto 0
                                                        display 'integer, '
                                                        if TYPE > 0
                                                                display 'positive'
                                                        else if TYPE < 0
                                                                display 'negative'
                                                        else if TYPE = 0
                                                                display 'zero'
                                                        else
                                                                display 'ERROR'
                                                        end if
                                                else
                                                        display 'unknown',10
                                                end if
                                        else if TYPE eqtype 0.0 ; float
                                                display 'float, '
                                                if TYPE > 0
                                                        display 'positive'
                                                else if TYPE < 0
                                                        display 'negative'
                                                else if TYPE = 0
                                                        display 'zero'
                                                else
                                                        display 'ERROR'
                                                end if
                                        else
                                                display 'unknown',10
                                        end if
                                else
                                        display '~definite, algebraic, linear polynomial'
                                end if
                        end match
                        end match
                end match
        else
                display '~defined'
        end if
end iterate

; These can all be forward referenced, above:
        define blank            ; blank
        define here blank       ; present and defined, but resulting in blank

        element reg             ; algebraic term

; This can NOT be forward referenced, code above doesn't "see" it:
        restore vfwd
        define vfwd blank

; some more tests
        define x 1
        y = 2
        define z y
    


Output:
Code:
absent  ~defined
vfwd    ~defined
blank    defined, blank
here     defined, blank+
vary     defined, blank+
1        defined, definite, algebraic, integer, positive
-1       defined, definite, algebraic, integer, negative
0        defined, definite, algebraic, integer, zero
reg+2    defined,~definite, algebraic, linear polynomial
''       defined, definite, string
0.0      defined, definite, float, zero
0.1      defined, definite, float, positive
-3.2     defined, definite, float, negative
x        defined, definite, algebraic, integer, positive
y        defined,~definite, algebraic, linear polynomial
z        defined,~definite, algebraic, linear polynomial
    


I guessed what the output would be but was wrong about z which I thought would be definite, but think about it I think it makes sense... The "linear polynomial" for y and z are wrong too (I suppose) but that's because the code assumes it's a linear polynomial if the thing is not definite (I think).
Post 27 Feb 2025, 17:45
View user's profile Send private message Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4161
Location: vpcmpistri
bitRAKE 27 Feb 2025, 20:59
`z` will resolve to whatever `y` is, imho.

I'm surprised `y = 2` is ~definite - even `y := 2` is ~definite which is a constant.

Yet, if we move the statement before then both `y=2` and `y:=2` are definite - as expected. Honestly, not sure why this is the case.
Post 27 Feb 2025, 20:59
View user's profile Send private message Visit poster's website Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4161
Location: vpcmpistri
bitRAKE 27 Feb 2025, 21:07
Abstracting out the type resolution:
Code:
macro typetype ITEM*
        if ITEM eqtype ''
                display 'string'
        else if ITEM eqtype 0 ; algebraic
                display 'algebraic, '
                if ITEM relativeto 0
                        display 'integer, '
                        if ITEM > 0
                                display 'positive'
                        else if ITEM < 0
                                display 'negative'
                        else if ITEM = 0
                                display 'zero'
                        else
                                display 'ERROR'
                        end if
                else
                        display 'linear polynomial'
                end if
        else if ITEM eqtype 0.0 ; float
                display 'float, '
                if ITEM > 0
                        display 'positive'
                else if ITEM < 0
                        display 'negative'
                else if ITEM = 0
                        display 'zero'
                else
                        display 'ERROR'
                end if
        else
                display 'unknown',10
        end if
end macro    
Now, we have a class of defined,~definite, algebraic, integer, positive - which is very strange.
Post 27 Feb 2025, 21:07
View user's profile Send private message Visit poster's website Reply with quote
dosmancer



Joined: 20 Feb 2025
Posts: 7
Location: Kingdom of Sweden
dosmancer 27 Feb 2025, 21:14
bitRAKE wrote:
`z` will resolve to whatever `y` is, imho.


Yes, I was dumb.

bitRAKE wrote:
`I'm surprised `y = 2` is ~definite - even `y := 2` is ~definite which is a constant.

Yet, if we move the statement before then both `y=2` and `y:=2` are definite - as expected. Honestly, not sure why this is the case.


`defined` is true if the thing is defined anywhere in the code.

`definite` becomes true if thing thing is defined anywhere in the code before the definite-check. I think that's the purpose of definite.

The reason why x is definite is what is weird imo but that has something to do with the stuff being defined with `equ` and `define` are replaced with their values in the code in the whole file even before any definite-check has been made. The preprocessor and assembler stage of fasm1 are still present to some extent in fasm2.

I might get this wrong since I am new to fasm, but I've been re-reading the manual many times.
Post 27 Feb 2025, 21:14
View user's profile Send private message Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4161
Location: vpcmpistri
bitRAKE 27 Feb 2025, 21:24
This effect is seen on element as well. Such that we could change the code to:
Code:
if definite TYPE
        display 'earlier, '
        typetype TYPE
else
        display 'later, '
        typetype TYPE
end if    
To be fair, that is what the manual says,
Quote:
the "definite" operator should be used instead, as it checks whether all symbols within a basic expression that follows have been defined earlier.
Post 27 Feb 2025, 21:24
View user's profile Send private message Visit poster's website Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4161
Location: vpcmpistri
bitRAKE 27 Feb 2025, 21:31
dosmancer wrote:
The reason why x is definite is what is weird imo but that has something to do with the stuff being defined with `equ` and `define` are replaced with their values in the code in the whole file even before any definite-check has been made. The preprocessor and assembler stage of fasm1 are still present to some extent in fasm2.
That seems correct to me. Non-variable symbols are eager.

_________________
¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup
Post 27 Feb 2025, 21:31
View user's profile Send private message Visit poster's website Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4161
Location: vpcmpistri
bitRAKE 27 Feb 2025, 21:33
I think we need to use CALM to discriminate between direct values and symbols with a value (i.e. 1 verses x; with define x 1).
Post 27 Feb 2025, 21:33
View user's profile Send private message Visit poster's website Reply with quote
dosmancer



Joined: 20 Feb 2025
Posts: 7
Location: Kingdom of Sweden
dosmancer 27 Feb 2025, 23:03
bitRAKE wrote:
I think we need to use CALM to discriminate between direct values and symbols with a value (i.e. 1 verses x; with define x 1).


I guess that would be pretty tricky.

An experiment:

Code:
define x 1

    calminstruction symbolic_or_direct_value
            local tmp
            arrange tmp,=x ; outputs "symbolic" for =x. Replace with 1 and it outputs "direct value"
            transform tmp
            jyes sym
            asm display "direct value"
            exit
        sym:
            asm display "symbolic"
    end calminstruction

    symbolic_or_direct_value
    
Post 27 Feb 2025, 23:03
View user's profile Send private message Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4161
Location: vpcmpistri
bitRAKE 28 Feb 2025, 01:02
I think it does offer insight into parsing values:
Code:
calminstruction sign item*
        local show
        arrange show,=display 'negative'
        check item < 0
        jyes done

        arrange show,=display 'positive'
        check item > 0
        jyes done

        arrange show,=display 'zero'
        check item = 0
        jyes done
        arrange show,=display 'error: integer or float expected'
done:   assemble show
end calminstruction

calminstruction type item
        local any,j
        check defined item
        jyes mt
        display '~defined'
        exit

mt:     compute j,0
        match ,item
        jyes b0
        arrange any,item
        transform any
b1:     compute j,j+1
        transform any
        jyes b1
        match ,any
        jno def

b0:     display 'blank '
        display j+48
        exit

def:    check definite item
        jno late
        display 'early, '
        transform item
        jyes sym
        display 'literal, '
        jump more
late:   display 'late, '
sym:    display 'symbol, '
more:   check '' eqtype item
        jyes str
        check 0.0 eqtype item
        jyes flt
        check 0 eqtype item
        jyes alg
        display 'error: defined value expected'
        exit

str:    display 'string'
        exit

poly:   display 'linear polynomial'
        exit

flt:    display 'float, '
        call sign,item
        exit

alg:    check item relativeto 0
        jno poly
        display 'integer, '
        call sign,item
end calminstruction    
edit: I've updated it to process undefined and deep blanks.

Results in ...
Code:
        blank 0
        blank 0
absent  ~defined
vfwd    ~defined
blank   blank 1
here    blank 2
vary    blank 2
1       early, literal, integer, positive
-1      early, literal, integer, negative
0       early, literal, integer, zero
reg+2   early, literal, linear polynomial
''      early, literal, string
0.0     early, literal, float, zero
0.1     early, literal, float, positive
-3.2    early, literal, float, negative
x       early, symbol, integer, positive
y       late, symbol, integer, positive    

_________________
¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup
Post 28 Feb 2025, 01:02
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-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.