POV-Ray : Newsgroups : povray.general : #ifdef using a string expression? : Re: #ifdef using a string expression? Server Time
19 Apr 2024 14:38:38 EDT (-0400)
  Re: #ifdef using a string expression?  
From: William F Pokorny
Date: 19 Mar 2023 16:30:35
Message: <641770eb$1@news.povray.org>
On 3/19/23 10:14, Kenneth wrote:
> William F Pokorny <ano### [at] anonymousorg> wrote:
>>
>> Alright.
>>
>> A long time ago I created a bunch of statically linked(a) versions of
>> POV-Ray going back through time. Anyhow. Used these to trace the
>> introduction of the str/num OK in #ifdef test bug.
>> [clip]
>> My BIG bet is on the following commit being the problem,
>> but I don't have a static compile of it or the one prior to it to
>> be sure.
>>
> 
> Given the current mix of flaws, the use of a string literal still has me
> scratching my head...
>          #ifdef("...string...")
> 
> Alain's and JR's explanation of the expected behavior seems valid; but with a
> properly-working #ifdef, should the comparison fail outright (fatal error)? Or
> should it still be seen as defined? I'm mostly just curious ;-)
> 

I'm a little further along in looking at this. It's looking messy.

I think we need to start with the fact #ifdef, #ifndef and #undef have 
ALWAYS been #ifIdDefined, #ifIdNotDefined and #undefineId. Going back to 
the v3.6 documentation we have:

---------------
2.2.2.6.2 The #ifdef and #ifndef Directives

The #ifdef and #ifndef directive are similar to the #if directive 
however they are used to determine if an identifier has been previously 
declared.

IFDEF_DIRECTIVE:
     #ifdef ( IDENTIFIER ) TOKENS... [#else TOKENS...] #end
IFNDEF_DIRECTIVE:
     #ifndef ( IDENTIFIER ) TOKENS... [#else TOKENS...] #end

If the IDENTIFIER exists then the first group of tokens is parsed 
normally and the second set is skipped. If false, the first set is 
skipped and the second set is parsed. ...
----------------

So... The up front, not so good, news is the behavior of at least the 
#ifdef and #ifndef keywords was partly changed back in March of 2015. 
Intentional or accidental? It's not mentioned as an intended change 
anywhere I have seen - and I still don't understand how it happened even 
with some time reviewing the changes when it happened.

Christoph went on to add a bunch of inbuilt keywords to be considered 
'defined' sometime after late November 2018 - which makes me begin to 
think he too might have been considering these *def keywords in the 
c/c++ coding, macro test sense.

The few 'keywords' I've tested these generate a warning in at least some 
versions of POV-Ray. But it's weird, keywords NOT returning immediate 
numbers or strings are also considered 'defined' in these versions 
though they are in fact arbitrary SDL keywords.

Even this worked in the pre-backed off v3.8 release parser:

#ifdef(#declare V=99;#undef V)
...

Though without some other mistake it would usually die with a later 
unmatched something parsing fail. That said it's not hard to get it to 
parse clean - say with an added #if(). I will always die if somebody 
tries use the undef'd V.

So, much more was being supported as testing true in povr/v4.0, but 
still not some things like raw vectors. Though things like x,y,z are OK.

Christoph backed up the v3.8 parser and again lost the inbuilt keywords 
as "defined". I do not know the reasons for the parser backup, but 
perhaps this issue it - or big part of it. I don't know.

I do know, I've got a mess with these in the povr parser given my branch 
point... :-(


When I test v3.7, v3.8b2 and my povr(v4.0?) code I get:

v3.7
----------------------
GOOD_ID  --> This is a valid ID. (ifdef returning true)
GOOD_ID  --> This is a valid ID. (ifndef returning false)
BAD_ID   --> This is NOT a valid ID. (ifdef returning false)
BAD_ID   --> This is NOT a valid ID. (ifndef returning true)
"STRING" --> Other than an ID. (ifdef returning false)
"STRING" --> Other than an ID. (ifndef returning true)
""       --> Other than an ID. (ifdef returning false)
""       --> Other than an ID. (ifndef returning true)
1.23456  --> Other than an ID. (ifdef returning false)
1.23456  --> Other than an ID. (ifndef returning true)
0        --> Other than an ID. (ifdef returning false)
0        --> Other than an ID. (ifndef returning true)
pi       --> Other than an ID. (ifdef returning false)
pi       --> Other than an ID. (ifndef returning true)
          --> Other than an ID. (ifdef returning true)
          --> Other than an ID. (ifndef returning true)

v3.8b2
-----------------------
GOOD_ID  --> This is a valid ID. (ifdef returning true)
GOOD_ID  --> This is a valid ID. (ifndef returning false)
BAD_ID   --> This is NOT a valid ID. (ifdef returning false)
BAD_ID   --> This is NOT a valid ID. (ifndef returning true)
"STRING" --> Other than an ID. (ifdef returning true)        ***
"STRING" --> Other than an ID. (ifndef returning false)      ***
""       --> Other than an ID. (ifdef returning true)        ***
""       --> Other than an ID. (ifndef returning false)      ***
1.23456  --> Other than an ID. (ifdef returning true)        ***
1.23456  --> Other than an ID. (ifndef returning false)      ***
0        --> Other than an ID. (ifdef returning true)        ***
0        --> Other than an ID. (ifndef returning false)      ***
pi       --> Other than an ID. (ifdef returning false)
pi       --> Other than an ID. (ifndef returning true)
          --> Other than an ID. (ifdef returning true)
          --> Other than an ID. (ifndef returning true)

povr & likely v4.0 and other misc releases before parser backup
-------------------------
GOOD_ID  --> This is a valid ID. (ifdef returning true)
GOOD_ID  --> This is a valid ID. (ifndef returning false)
BAD_ID   --> This is NOT a valid ID. (ifdef returning false)
BAD_ID   --> This is NOT a valid ID. (ifndef returning true)
"STRING" --> Other than an ID. (ifdef returning true)        ***
"STRING" --> Other than an ID. (ifndef returning false)      ***
""       --> Other than an ID. (ifdef returning true)        ***
""       --> Other than an ID. (ifndef returning false)      ***
1.23456  --> Other than an ID. (ifdef returning true)        ***
1.23456  --> Other than an ID. (ifndef returning false)      ***
0        --> Other than an ID. (ifdef returning true)        ***
0        --> Other than an ID. (ifndef returning false)      ***
pi       --> Other than an ID. (ifdef returning true)        ###
pi       --> Other than an ID. (ifndef returning false)      ###
          --> Other than an ID. (ifdef returning true)
          --> Other than an ID. (ifndef returning true)

The last case with empty parens is an exposure back to v3.7. In a lot of 
code the effective fall through at the #if____ will cause later parsing 
problems, but the error are of the more unhelpful sort. It would be best
if the empty parens were themselves a parse error. I 'think' it's 
probably also possible to fix the following parsing issues with another, 
cleaning syntax (actual bad-syntax) sort of mistake.

My feeling is the right thing to do would be to take the behavior back 
to what it has always been with the nearer term v3.8 release. If we want 
the most backward compatibility this it. Further, the extra now being 
changed currently in the v3.8 code is not consistent with respect to 
things like pi - which to the parser is an immediate value of pi. And 
datetime would be an example of an immediate string which would test 
true, you'd think, if "string" does.

What to do... I could spend a lot of time trying to figure out the 
history here, but I think the current state not completely tenable since 
2015...

We need functionality which deals only with IDs.

We, perhaps, need some sort of what is in the parenthesis is 'defined' 
functionality too, but the generic sort being allowed or not seems 
questionable to me. Are people already using this functionality?

With povr I might do something drastic like create 'id' versions and and 
'defined' versions - with all new keyword names so users would be forced 
to look at potential problems with interpretation and behavior given the 
old keywords wouldn't work!

Hmm... We do have new to v3.8 the local and global dictionaries. Could I 
just dump the #ifdef and #ifndef keyword for something based on those. I 
can't remember at the moment how they work.

Don't know... Whatever it is in povr, afraid at the moment it'll be a 
lot of work - because I'll need to digest a lot of the parser code.

Guess it's time to do my taxes... :-)

Bill P.


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.