Preprocessor changes

Several bugs have been fixed in the preprocessor, that can now result in a compilation error.

String token expansion

Before version 3.00, the following preprocessor syntax could be used to expand a string macro parameter:
&define T(x) DISPLAY "head_"#x"_tail"
-- macro usage:
T(body)
This was producing following result (after preprocessing):
"head_""body""_tail"

And was accepted by the compiler, because it was interpreted as a single string literal.

The new preprocessor now produces (as expected):
"head_" "body" "_tail"

However, this will now result in a compiler error, because this is not a valid string literal.

To solve such issue and get the same result string as before version 3.00, use the || concatenation operator in the preprocessor macro and add (escaped) double quotes before and after the #ident placeholder:

&define T(x) DISPLAY "head_""" || #x || """_tail"
or, by using single quotes as border strings delimiters:
&define T(x) DISPLAY 'head_"' || #x || '"_tail'

Identifier concatenation

Before version 3.00, the following type of macro:
&define FOO() foo
-- macro usage:
FOO()bar
was producing a single identifier token (accepted by the compiler):
foobar
But it will now produce two distinct identifier tokens (as expected):
foo bar

And this will result in a compilation error.

Backslash in macro parameters

Before version 3.00.00 is was possible to use the backslash to escape a comma in preprocessor macro parameters. This syntax is no longer allowed by the preprocessor, it is not a valid usage. To solve such issue, replace parameters by real string literals in the macro:

-- bad coding
&define FOO(p1) DISPLAY #p1
FOO(hello world)       -- expands to: DISPLAY "hello world"
FOO(hello \, world)    -- error 

-- good coding
&define FOO(p1) DISPLAY p1
FOO("hello world")     -- expands to: DISPLAY "hello world"
FOO("hello , world")   -- expands to: DISPLAY "hello , world"

The ## paste operator

Before version 3.00.00, the ## paste operator could be used to construct code with two elements that did not result in a valid token, for example:
&define FOO(name) rec_ ## [ x ]
FOO(x)
was producing:
rec_[ x ]
This kind of preprocessor macro is no longer allowed in version 3.00.00 and will result in a compiler error:
x.4gl:2:1:2:1:error:(-8042) The operator '##' formed 'rec_[', an invalid preprocessing token.
The ## paste operator must be used to join two identifiers, to create a new identifier:
&define REC_PREFIX(name) rec_ ## name
LET REC_PREFIX(customer) = NULL
will produce:
LET rec_customer = NULL