flat assembler
Message board for the users of flat assembler.

Index > Compiler Internals > Local namespaces are completely broken in fasm2

Author
Thread Post new topic Reply to topic
SArpnt



Joined: 29 Sep 2026
Posts: 5
SArpnt 29 Sep 2026, 04:17
after entering a local namespace, every instruction is an illegal instruction.

this assembly:
Code:
macro foo
        local a
        namespace a
                db 0
        end namespace
end macro
foo
    

causes the error:
Code:
flat assembler  version g.l8vn
src/main.asm [7]:
        foo
macro foo [3] ? [4]
Processed: db 0
Error: illegal instruction.
src/main.asm [7]:
        foo
macro foo [4] ? [4]
Processed: end namespace
Error: illegal instruction.
eval [1] /opt/fasm2/include/fasm2.inc [3] /opt/fasm2/include/format.inc [30]:
        if ~ definite format?
? [4]
Processed: if ~ definite format?
Error: illegal instruction.

(...)
    


i ran into this issue when trying to use strucs without a label:
Code:
struc foo, val
        local end
        label .: end - .
        namespace .
                db val
        end namespace
        end:
end struc
macro _ args&
        local _NO_LABEL
        _NO_LABEL args
end macro
_ foo 1
_ foo 2
    
Post 29 Sep 2026, 04:17
View user's profile Send private message Visit poster's website Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4640
Location: vpcmpistri
bitRAKE 29 Sep 2026, 05:06
That's a special feature.

I don't understand your intent, but wouldn't use "end" as a name unless there is some hidden meaning requiring it. MACRO happens first, you'd need to "?_ foo 1" if you want STRUC to fire first.

Edit: okay, I get it. This is the simplest fix:
Code:
struc foo val,db:db,end:end
        local _end
        label .: _end - .
        namespace .
                db val
        end namespace
        _end:
end struc
macro _ args&
        local _NO_LABEL
        _NO_LABEL args
end macro
_ foo 1
_ foo 2    
Post 29 Sep 2026, 05:06
View user's profile Send private message Visit poster's website Reply with quote
SArpnt



Joined: 29 Sep 2026
Posts: 5
SArpnt 29 Sep 2026, 05:45
...undocumented misfeature then.

what i want is to be able to use *any* struc without creating a label. adding absolutely every possible instruction after every struc isn't a real solution to that.

Code:
; use a struc without a label
macro _ args&
        local _NO_LABEL
        _NO_LABEL args
end macro

struc pad len*, args&
        label .: len
        args
        rb len - $ + .
end struc

mytext pad 30, db "Foo"
_ pad 30, db "a"
_ pad 30, db "b"
    

i can't just add everything as an argument to `pad`.
Post 29 Sep 2026, 05:45
View user's profile Send private message Visit poster's website Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4640
Location: vpcmpistri
bitRAKE 29 Sep 2026, 05:48
But do you need anonymous?
Code:
struc(NAMED) foo val
        local _end
        label NAMED: _end - NAMED
        namespace NAMED
                db val
        end namespace
        _end:
end struc    
Post 29 Sep 2026, 05:48
View user's profile Send private message Visit poster's website Reply with quote
SArpnt



Joined: 29 Sep 2026
Posts: 5
SArpnt 29 Sep 2026, 06:14
i'm not sure what you're trying to get at. writing NAMED in the struc doesn't change how it behaves.
Post 29 Sep 2026, 06:14
View user's profile Send private message Visit poster's website Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4640
Location: vpcmpistri
bitRAKE 29 Sep 2026, 06:36
Code:
macro pad len*, args&
        local name
name:
        args
        rb len - $ + name
end struc
struc(NAMED) pad len*, args&
        label NAMED:len
        pad len,args
end struc

mytext  pad 30, db "Foo"
        pad 30, db "a"
        pad 30, db "b"    
... seems to work?

... another way is to match "_" and bypass label creation - if you really want "_".
Post 29 Sep 2026, 06:36
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8559
Location: Kraków, Poland
Tomasz Grysztar 29 Sep 2026, 06:46
SArpnt wrote:
...undocumented misfeature then.
It has been documented:
Quote:
Moreover, its descendant namespace is disconnected from the main tree of symbols, so if "namespace" command was used with a local symbol as the argument, symbols from the main tree would no longer be visible (including all the named instructions of the assembler, even commands like "end namespace").
Entering such namespace allows to get a blank page where you can define directives differently than in the base language, what makes it obviously not a good choice of a tool for your case. If you look how fasm2 does it, instead of a local label, it uses a counter to create a new unique name (which is very similar to how fasm 1 did it).

Code:
define __unnamed
__unnamed.counter = 0

struc foo val
        local End       ; changed case, otherwise it also replaces "end" in "end namespace"
        label .: End - .
        namespace .
                db val
        end namespace
        End:
end struc
macro _ args&
        repeat 1, i:__unnamed.counter+1
                __unnamed.i args
                __unnamed.counter = i
        end repeat
end macro
_ foo 1
_ foo 2    
Note that your sample code also had an "end" name conflict.
Post 29 Sep 2026, 06:46
View user's profile Send private message Visit poster's website Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4640
Location: vpcmpistri
bitRAKE 29 Sep 2026, 06:48
Code:
macro _ args&
        local _NO_LABEL
        _NO_LABEL args
end macro    
... this is the problem piece.
Code:
_index = 0 ; global counter
macro _ args&
        repeat 1,i:_index
                ?i args
        end repeat
        _index = _index+1
end macro

struc foo val
        local _end
        label .: _end - .
        namespace .
                db val
        end namespace
        _end:
end struc

_ foo 1
_ foo 2    
... there - the no label label.
Post 29 Sep 2026, 06:48
View user's profile Send private message Visit poster's website Reply with quote
SArpnt



Joined: 29 Sep 2026
Posts: 5
SArpnt 29 Sep 2026, 07:01
right, i'm going to treat this as an xy problem then (even though i think this is something i really should just be able to do).

i have several structs, where struct is a macro i made to define a data structure. it's supposed to make it easy to construct objects and get their offsets and sizes.
Code:
struct FileName, name:""
        pad 13, db name,0 ; "NAMENAME.EXT",0
end struct
struct LevelPath, name:""
        db "levels/"
        filename FileName name
end struct
struct SongTA, t1:"",t2:"",a1:"",a2:""
        ; title is 2 lines of asciiz, author is two lines of asciiz *from the end*
        label title: 21
                pad 21, db t1,0,t2
        label author: 22
                db 0
                padstart 21, db a2,0,a1
end struct
struct LevelHeader
        ; TODO align
        song SongHeader
        chart ChartHeader
        ;chart1 ChartHeader
        ;chart2 ChartHeader
        ;chart3 ChartHeader
end struct
struct SongHeader
        ; TODO align
        title_author SongTA
        offset dw ?
        size dw ?
end struct
struct ChartHeader
        ; TODO align
        offset dw ? ; 0 indicates end of list
        size dw ?
        difficulty db ?
        author rb 0 ; TODO size
end struct
struct LevelLHeader
        title_author SongTA
        difficulty db ?
end struct
    

a struct is supposed to make 3 things. a macro that generates the relevant data, a struc that does the same, and a label to get the offset and size with.
all of this is supposed to be able to work:
Code:
files:
repeat 10
        FileName ""
end repeat
file FileName ""
x = sizeof FileName
    


i have the struc and label working fine, but the macro causes label conflicts. a local namespace seemed like the obvious solution, because a local label is exactly the thing that's supposed to allow reuse, but it didn't work. i can't think of any solution other than an actual local namespace. i haven't learned how calminstructions work, so i wouldn't know how i could use them to prevent label conflicts. i have no clue what the struct.inc that comes with fasm2 does because as far as i can tell it doesn't have official documentation.

my current best is this, which again, doesn't work
Code:
; TODO shouldn't need a comma after name
macro struct! name*, args&
        local content
        macro end.struct!
                esc end macro
                ; constructor macro
                macro name x&
                        local a
                        namespace a
                                content x
                        end namespace
                end macro
                ; virtual label to get offsets and sizes
                virtual at 0
                        set name, name
                end virtual
                ; struc
                struc name x&
                        local endpos
                        label .: endpos - .
                        namespace .
                                content x
                        end namespace
                        endpos:
                end struc
                purge end.struct
        end macro
        esc macro content args
end macro
    
Post 29 Sep 2026, 07:01
View user's profile Send private message Visit poster's website Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4640
Location: vpcmpistri
bitRAKE 29 Sep 2026, 07:37
Code:
namespace _struct
        counter = 0 ; doesn't conflict with other counters
end namespace

; TODO: shouldn't need a comma after name
macro struct! name*, args&
        local content
        macro end.struct!
                esc end macro
                purge end.struct

                ; struc
                struc name x&
                        local endpos
                        label .: endpos - .
                        namespace .
                                content x
                        end namespace
                        endpos:
                end struc

; virtual label to get offsets and sizes
                virtual at 0
                        ?name name
                end virtual

                ; constructor macro
                macro name x&
                        repeat 1,i:_struct.counter
                        namespace _struct.i
                                content x
                        end namespace
                        end repeat
                        _struct.counter = _struct.counter + 1
                end macro
        end macro

        esc macro content args
end macro

macro pad len*, args&
        local name
name:
        args
        rb len - $ + name
end macro
struc pad len*, args&
        label .:len
        pad len,args
end struc

macro padstart len*, args& ; Note: unknown difference from pad
        local name
name:
        args
        rb len - $ + name
end macro

; Testing ...

struct FileName, name:""
        pad 13, db name,0 ; "NAMENAME.EXT",0
end struct
struct LevelPath, name:""
        db "levels/"
        filename FileName name
end struct
struct SongTA, t1:"",t2:"",a1:"",a2:""
        ; title is 2 lines of asciiz, author is two lines of asciiz *from the end*
        label title: 21
                pad 21, db t1,0,t2
        label author: 22
                db 0
                padstart 21, db a2,0,a1
end struct
struct LevelHeader
        ; TODO align
        song SongHeader
        chart ChartHeader
        ;chart1 ChartHeader
        ;chart2 ChartHeader
        ;chart3 ChartHeader
end struct
struct SongHeader
        ; TODO align
        title_author SongTA
        offset dw ?
        size dw ?
end struct
struct ChartHeader
        ; TODO align
        offset dw ? ; 0 indicates end of list
        size dw ?
        difficulty db ?
        author rb 0 ; TODO size
end struct
struct LevelLHeader
        title_author SongTA
        difficulty db ?
end struct

files:
repeat 10
        FileName ""
end repeat
?file FileName "" ; Note: file is a directive
x = sizeof FileName    
... not that this is correct - just getting closer to working.
Post 29 Sep 2026, 07:37
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8559
Location: Kraków, Poland
Tomasz Grysztar 29 Sep 2026, 10:29
SArpnt wrote:
i haven't learned how calminstructions work, so i wouldn't know how i could use them to prevent label conflicts.
I can give you a ready-to-use solution based on that snippet from fasm2's implementation:
Code:
calminstruction _ &statement&
        local ic
        init ic
        compute ic, ic + 1
        arrange statement, =__unnamed__#ic statement
        assemble statement
end calminstruction

_ foo 1
_ foo 2    
It doesn't matter how "foo" is defined, this simply replaces the "_" with a numbered (and thus unique) label each time. It is self-contained, you can just take it and use it inside a more complex macro. It requires an INIT macro from the xcalm.inc, but it is included in fasm2 anyway.
SArpnt wrote:
i have no clue what the struct.inc that comes with fasm2 does because as far as i can tell it doesn't have official documentation.
Because the aim of fasm2 was to provide as much compatibility with classic fasmw package as possible, its struct.inc was designed to follow the rules documented for fasmw headers.
Post 29 Sep 2026, 10:29
View user's profile Send private message Visit poster's website Reply with quote
SArpnt



Joined: 29 Sep 2026
Posts: 5
SArpnt 30 Sep 2026, 00:42
this works, thanks tomasz
Post 30 Sep 2026, 00:42
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.