"Sputnik" help  
Sputnik Help
Language Reference - Preprocessor - Macro Pitfalls - Swallowing the Semicolon

Swallowing the Semicolon

Often it is desirable to define a macro that expands into a compound statement. Consider, for example, the following macro, that advances an index through a string to skip whitespace characters:

#define SKIP_SPACES(p, index)    \
{                                \
    while (index < StrLen(p))    \
    {                            \
        if (p[index] == ' ')     \
            index++;             \
        else                     \
            break;               \
    }                            \
}

$p = "    Hello     world";
for(my $i = 0; $i < StrLen($p); $i++)
{
    SKIP_SPACES($p, $i);
    my $ch = $p[$i];
    say "Char: $ch";
}

// PRINTS
// Char: H
// Char: e
// Char: l
// Char: l
// Char: o
// Char: w
// Char: o
// Char: r
// Char: l
// Char: d

Here backslash-newline is used to split the macro definition, which must be a single logical line, so that it resembles the way such code would be laid out if not part of a macro definition.

A call to this macro might be SKIP_SPACES($p, $i). Strictly speaking, the call expands to a compound statement, which is a complete statement with no need for a semicolon to end it. However, since it looks like a function call, it minimizes confusion if you can use it like a function call, writing a semicolon afterward, as in SKIP_SPACES($p, $i);

This can cause trouble before else statements, because the semicolon is actually a null statement. Suppose you write

if ($test)
    SKIP_SPACES($p, $i);
else ...

The presence of two statements—the compound statement and a null statement—in between the if condition and the else makes invalid Sptunik code.

The definition of the macro SKIP_SPACES can be altered to solve this problem, using a scope (or any statement that will cover the entire code block) statement. Here is how:

#define SKIP_SPACES(p, index)    \
do {                             \
    while (index < StrLen(p))    \
    {                            \
        if (p[index] == ' ')     \
            index++;             \
        else                     \
            break;               \
    }                            \
} while(0)

Now SKIP_SPACES($p, $i); expands into

do {...} while (0);

In Sputnik you can omit the while from a do statement here is he definition of the macro SKIP_SPACES altered to show this:

#define SKIP_SPACES(p, index)    \
do {                             \
    while (index < StrLen(p))    \
    {                            \
        if (p[index] == ' ')     \
            index++;             \
        else                     \
            break;               \
    }                            \
}

$p = "    Hello     world";
for(my $i = 0; $i < StrLen($p); $i++)
{
    SKIP_SPACES($p, $i);
    my $ch = $p[$i];
    say "Char: $ch";
}

// PRINTS
// Char: H
// Char: e
// Char: l
// Char: l
// Char: o
// Char: w
// Char: o
// Char: r
// Char: l
// Char: d

Now SKIP_SPACES($p, $i); expands into

do {...};

Here is what the entire thing expands into:

$p = "    Hello     world";
for(my $i = 0; $i < StrLen($p); $i++)
{
    do
    {
        while ($i < StrLen($p))
        {
            if ($p[$i] == ((Char)32))
                $i++;
            else
                break;
        }
    };
    my $ch = $p[$i];
    say "Char: $ch";
}

As you can see preprocessor macros are fully inlined.


Contact
Cheryl (uberfox@hotmail.com)
Homepage
http://ubersoft.org