flat assembler
Message board for the users of flat assembler.

Index > Main > Strange behavior in if-else

Author
Thread Post new topic Reply to topic
Heskeutz



Joined: 25 Feb 2014
Posts: 12
Heskeutz 25 Feb 2014, 11:40
Hey all,

Simply, I have the following code in an include file:
Code:
; windows.inc
if defined UNICODE
        display 'UNICODE Build'
        _tprintf equ wprintf
        include 'win32wx.inc'
else
        display 'ASCII Build'
        _tprintf equ printf
        include 'win32ax.inc'
end if
    

And here I am including the file in my main code:
Code:
; main.asm
UNICODE = 1
format pe console
include 'windows.inc'
. . .
call [_tprintf]
. . .
    

When I assemble the program, the preprocessor displays the message "UNICODE Build", yet when I look into the generated binary, not 'wprintf' but 'printf' is being called. I tried moving things around and finally realized that the 'else' part of the if-else clause is always the one that makes it to the assembly stage. See this:
Code:
if ~ defined UNICODE
        display 'ASCII Build'
        _tprintf equ printf
        include 'win32ax.inc'
else
        display 'UNICODE Build'
        _tprintf equ wprintf
        include 'win32wx.inc'
end if
    

The above snippet is exactly the same as the very first one, yet in the latter 'wprintf' ALWAYS makes it into the final binary. Is this the expected behavior? Or is it a bug? Am I missing something?

BTW, I'm trying to build a package that will simplify FASM Windows app development for those who are already familiar with using the API in C. Any reply is greatly appreciated Smile
Post 25 Feb 2014, 11:40
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20451
Location: In your JS exploiting you and your system
revolution 25 Feb 2014, 11:59
The problem is the "equ" lines. The preprocessor ignores the "if/else/endif" lines and always does both equ's with the second equ being the final value equated.

BTW: The display directive is an assembly time output not a preprocessor output. This may be why you did not notice the equ problem.


Last edited by revolution on 25 Feb 2014, 12:03; edited 1 time in total
Post 25 Feb 2014, 11:59
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20451
Location: In your JS exploiting you and your system
revolution 25 Feb 2014, 12:02
Also, both includes will be included. This may cause a problem when the included files have preprocessor directives since they will also always be parsed in both files.

Actually the entire construct should really be a preprocessor match, or similar, to avoid such problems.
Post 25 Feb 2014, 12:02
View user's profile Send private message Visit poster's website Reply with quote
Heskeutz



Joined: 25 Feb 2014
Posts: 12
Heskeutz 25 Feb 2014, 12:21
Thanks for your response.

If that is the case with equ's, then it's the same with include's too, because I tried doing the following:
Code:
if defined UNICODE
    include 'unicode.inc'
else
    include 'ascii.inc'
end if
    

yet, I didn't realize the intended result; such that whether 'UNICODE' is defined or not both files (unicode.inc and asciii.inc) are somewhat processed. Man, this behavior is so uncool. Thanks for your response anyway.
Post 25 Feb 2014, 12:21
View user's profile Send private message Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881
l_inc 25 Feb 2014, 12:35
Heskeutz
You should gain more understanding of how fasm works. Nearly everyone hits this misexpectation when first starting to try out the fasm's macrolanguage. The behaviour you observe is explainable, correct and desired. There are different ways to achieve what you want: as revolution suggested you may use the match directive.

For a very brief explanation/overview you could read this post starting from the second paragraph. For a more detailed look just read the documentation attentively.

_________________
Faith is a superposition of knowledge and fallacy
Post 25 Feb 2014, 12:35
View user's profile Send private message Reply with quote
Heskeutz



Joined: 25 Feb 2014
Posts: 12
Heskeutz 25 Feb 2014, 16:44
Thanks l_inc, I understand fasm better now Smile So actually 'if' is NOT a preprocessor directive but that of the assembler. OK, that one bit me a little Smile This is what I have now:
Code:
; windows.inc
define _unicode 0 ; default to ascii
match =true, unicode { define _unicode 1 }
match =0, _unicode { include 'win32ax.inc' }
match =1, _unicode { include 'win32wx.inc' }    
And the includer will do thus:
Code:
define unicode true
include 'windows.inc'
. . .    
Thanks y'all Smile
Post 25 Feb 2014, 16:44
View user's profile Send private message Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881
l_inc 25 Feb 2014, 23:08
Heskeutz
Quote:
This is what I have now

Good. You're improvising. But just for your information, there are ways to do the same in two lines without introducing an additional macroconstant:

1. This one is based on the fact that a symbol matches it's own name, if not defined:
Code:
; windows.inc
match =true, unicode { include 'win32wx.inc' }
match =unicode, unicode { include 'win32ax.inc' }    

A disadvantage is that define unicode false would skip both blocks.

2. This one is seen by some people as hacky, but I loved it immediately when I first saw it (baldr's idea):
Code:
; windows.inc
match =true, unicode { match,\{ include 'win32wx.inc' \} rept 0 \{ }
match , { include 'win32ax.inc' }    

The internal match is not necessary: it's just for enclosing the include directive into a separate macroblock, so that the rept directive can be put on the same line.

_________________
Faith is a superposition of knowledge and fallacy
Post 25 Feb 2014, 23:08
View user's profile Send private message Reply with quote
Heskeutz



Joined: 25 Feb 2014
Posts: 12
Heskeutz 26 Feb 2014, 04:53
l_inc wrote:
2. This one is seen by some people as hacky, but I loved it immediately when I first saw it (baldr's idea):
Code:
; windows.inc
match =true, unicode { match,\{ include 'win32wx.inc' \} rept 0 \{ }
match , { include 'win32ax.inc' }    

Neat! I think I'd go for something like this since it's succinct and eliminates the use of the macroconstant too Smile So, if I understand it correctly, you are exploiting the algorithm of the preprocessor parser, right? Nice. Such is an instance of cases where those who actually read and understand the source have the advantage. See you around Smile
Post 26 Feb 2014, 04:53
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20451
Location: In your JS exploiting you and your system
revolution 26 Feb 2014, 05:05
Heskeutz wrote:
So, if I understand it correctly, you are exploiting the algorithm of the preprocessor parser, right?
It exploits the fact that fasm doesn't nest opening curly brackets. This is valid:
Code:
rept 0{{{{{{{{}    
Post 26 Feb 2014, 05:05
View user's profile Send private message Visit poster's website Reply with quote
Heskeutz



Joined: 25 Feb 2014
Posts: 12
Heskeutz 26 Feb 2014, 07:54
revolution wrote:
It exploits the fact that fasm doesn't nest opening curly brackets. This is valid:
Code:
rept 0{{{{{{{{}    

Hmmm, then I'm thinking that the escaping of the opening curly brace in the snippet, that is
Code:
 . . . rept 0 \{ }    
is not needed since it neither has any effect on match nor rept ??
Post 26 Feb 2014, 07:54
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20451
Location: In your JS exploiting you and your system
revolution 26 Feb 2014, 08:56
Heskeutz wrote:
Hmmm, then I'm thinking that the escaping of the opening curly brace in the snippet, that is
Code:
 . . . rept 0 \{ }    
is not needed since it neither has any effect on match nor rept ??
Yes. Open bracket escaping is completely optional. Perhaps this is also helpful:

http://board.flatassembler.net/topic.php?p=108637#108637
Post 26 Feb 2014, 08:56
View user's profile Send private message Visit poster's website Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881
l_inc 26 Feb 2014, 13:48
Heskeutz
Quote:
then I'm thinking that the escaping of the opening curly brace in the snippet, that is
Code:
 . . . rept 0 \{ }    
is not needed since it neither has any effect on match nor rept ??

It's purpose is a visual help. As revolution said, you can almost always (except for some odd cases) omit escaping of opening braces, but I feel some psychological discomfort when I see a part of code like
Code:
rept 0 {}    
and should force my mind to not consider those braces as corresponding to each other.

_________________
Faith is a superposition of knowledge and fallacy
Post 26 Feb 2014, 13:48
View user's profile Send private message 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.