[SOLVED] Are type members exposed as symbols in the preprocessor?

General FreeBASIC programming questions.
Post Reply
shadow008
Posts: 86
Joined: Nov 26, 2013 2:43

[SOLVED] Are type members exposed as symbols in the preprocessor?

Post by shadow008 »

EDIT:
No type member symbols are not accessible, but namespace members are

Hello, quick question.

So you can do a quick and dirty check if a type or sub/function exists like so:

Code: Select all

#ifdef mytype
print "mytype has been declared"
#else
print "mytype not yet declared"
#endif

#ifdef somefunction
print "somefunction has been declared"
#else
print "somefunction not yet declared"
#endif

type mytype
    dim x as integer
    
    declare sub dothing()
    
end type

sub mytype.dothing()
    'Do nothing
end sub

function somefunction() as integer
    return 0
end function

#ifdef mytype
print "mytype has been declared"
#else
print "mytype not yet declared"
#endif

#ifdef somefunction
print "somefunction has been declared"
#else
print "somefunction not yet declared"
#endif

'I want to do this:
'#ifdef mytype.dothing

sleep
When this code is converted to C using -gen gcc, we see that the mytype sub member "dothing" is simply just another function (as expected):

Code: Select all

...
void _ZN6MYTYPE7DOTHINGEv( struct $6MYTYPE* THIS$1 )
{
    label$2:;
    label$3:;
}
...
This, of course, could be checked for existence in C just like demonstrated above. I assume the freebasic backend, specifically the symbol table, holds this member somewhere.

Question: Can you get a type's member symbol in freebasic through the preprocessor? Or, another way of asking, is there any way to do the equivalent of this which doesn't currently work:

Code: Select all

#ifdef mytype.dothing
...do something
Last edited by shadow008 on Mar 02, 2023 22:47, edited 2 times in total.
shadow008
Posts: 86
Joined: Nov 26, 2013 2:43

Re: [Question] Are type members exposed as symbols in the preprocessor?

Post by shadow008 »

In case it helps anyone, the sub-par workaround to this that I've been using basically looks like:

Code: Select all

type thing
    
    dim x as integer
    #define thing_dothing
    declare sub dothing()
    
end type

#if defined(thing_dothing)
    print "thing.dothing defined"
#else
    print "keep trying..."
#endif

sleep
Where the user defines the symbol like <type>_<member_name>.
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: [Question] Are type members exposed as symbols in the preprocessor?

Post by fxm »

@Jeff and the others,

shadow008 wrote: Feb 24, 2023 20:52 Question: Can you get a type's member symbol in freebasic through the preprocessor?
At first glance, this does not work, but there is currently a small inconsistency because that works with symbols defined in a Namespace but not with static symbols defined in a Type.
coderJeff
Site Admin
Posts: 4326
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: [Question] Are type members exposed as symbols in the preprocessor?

Post by coderJeff »

fxm wrote: Feb 25, 2023 8:23 @Jeff and the others,
shadow008 wrote: Feb 24, 2023 20:52 Question: Can you get a type's member symbol in freebasic through the preprocessor?
At first glance, this does not work, but there is currently a small inconsistency because that works with symbols defined in a Namespace but not with static symbols defined in a Type.
I think we can try a small change that will allow defined( UDT.member) that is kind of safe; shouldn't break anything. We did a lot of work on namespaces and symbol lookups so maybe some of the changes can help to make UDT lookups work now too. #ifdef and #ifndef use same internal calls as defined() so will work the same.

For interest:
- the preprocessor (what substitutes text expressions) and lexer (what gets next token) are combined components in fbc compiler - they are not separate. This allows the preprocessor to access information about current compilation state and not only text in the user source.
- the parser (what tries to make sense of syntax), asks the lexer to give the next token which depends on the current parsing context (what the parser is expecting to be next), and preprocessor may substitute user source for something other text (i.e. macros, instrinsic #define's, etc.)
- however, some lexer/preprocessor functions like defined() and typeof() call back in to the parser.
coderJeff
Site Admin
Posts: 4326
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: [SOLVED] Are type members exposed as symbols in the preprocessor?

Post by coderJeff »

Updated in fbc 1.10.0: added support for defined( typename.member )
- ditto for #IFDEF / #IFNDEF
- member can be a data field, static member, nested type, data field, constructor, destructor, property, operator, or member procedure.
- constructors and operators can be overloaded so defined() is is true if at least one is defined (declared actually).

Trivial types are not handled identically to complex types.

Derived types (extends), UDTs with nested types, and UDTs with member procedures have their own namespace and have immediate access to declared / defined fields:

Code: Select all

type T extends object
  b as byte
  #ifdef b
    #print b is defined (inside T's namespace)
  #endif
end type
However, fields of trivial type can still be tested by qualifying the name:

Code: Select all

type T
  b as byte
  #ifdef T.b
    #print T.b is defined
  #endif
end type
Note: implicit constructors are not defined until the UDT declaration is closed at the end type

Code: Select all

type T
  dim s as string
  #ifndef T.constructor
    #print T.constructor not defined
  #endif
end type

#ifdef T.constructor
  #print T.constructor defined
#endif
coderJeff
Site Admin
Posts: 4326
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: [SOLVED] Are type members exposed as symbols in the preprocessor?

Post by coderJeff »

I have a little fix-up to make to the last addition.

We can have fields with same names as keywords, but only if the TYPE is not extended, has nested types, or has declared member procedures.
For example, this is allowed, even though 'constructor' is a keyword:

Code: Select all

type T
	constructor as byte
end type
#if defined( T.constructor )
	#print T.constructor is defined
#endif
Which means my last example in my last post, the logic is probably wrong and probably should be:

Code: Select all

type T
	operator as string
end type
#if not defined( T.constructor )
	#print T.constructor is not defined (even though T has implicit constructor)
#endif
I think it has to be that way because otherwise it would be ambiguous and I don't have an idea for parsing one over the other:

Code: Select all

type T
	constructor as string
end type
#if defined( T.constructor )
	#print T.constructor is defined (but should it be because of field or implicit constructor?)
#endif
Post Reply