- Introduction
- Example 1 - Count Array Parameters
- Example 2 - Count All Parameters
- Example 3 - Count Array Parameters And Sum Their Size
- Example 4 - Auto-Generate
CallRemoteFunction
Specifier Strings - Example 5 - Output Input Exactly
- Example 6 - Remotes With Alternate Return Types
- Example 7 - y_timers Clone
- LEN (LENGTH)
- QAL (QUALIFICATION)
- SPC (SPECIAL)
- GRP (TAGGROUP)
- API
- Example 8 - y_inline
- PARSER_ISOLATE
- Complete Parameter Reference
- NUMBER
- NUMBER_CONST
- NUMBER_DEFAULT
- NUMBER_CONST_DEFAULT
- NUMBER_TAG
- NUMBER_CONST_TAG
- NUMBER_DEFAULT_TAG
- NUMBER_CONST_DEFAULT_TAG
- NUMBER_TAGGROUP
- NUMBER_CONST_TAGGROUP
- NUMBER_DEFAULT_TAGGROUP
- NUMBER_CONST_DEFAULT_TAGGROUP
- REFERENCE
- REFERENCE_DEFAULT
- REFERENCE_TAG
- REFERENCE_DEFAULT_TAG
- REFERENCE_TAGGROUP
- REFERENCE_DEFAULT_TAGGROUP
- STRING
- STRING_CONST
- STRING_DEFAULT
- STRING_CONST_DEFAULT
- VARARG
- VARARG_TAG
- VARARG_TAGGROUP
- ARRAY
- ARRAY_CONST
- ARRAY_TAG
- ARRAY_CONST_TAG
- ARRAY_TAGGROUP
- ARRAY_CONST_TAGGROUP
- ARRAY_MULTI
- ARRAY_MULTI_CONST
- ARRAY_MULTI_TAG
- ARRAY_MULTI_CONST_TAG
- ARRAY_MULTI_TAGGROUP
- ARRAY_MULTI_CONST_TAGGROUP
- LENGTH
- SPECIAL
- SPECIAL_CONST
- Complete Return Reference
This library is designed for generating code at compile-time based on existing code. It can be thought of as a macro equivalent to amx-assembly - used for advanced manipulation of the compiler for creating libraries and keywords, more than end-user code. As a simple example we will create a macro to count the number of array parameters in a function, walking through each step in turn. After that we will demonstrate a more in-depth example to create a y_timers clone.
// The entry point. Defines our parser.
#define ARRAY_COUNT:%1(%2) FUNC_PARSER(ARRAY_COUNT,ARR:NUM:)(%1(%2)) stock const countOf_%1 = 0; %1(%2)
// Default. Called for parameters that didn't match any other type.
#define ARRAY_COUNT_NUM(%9)%8$ %8$
// Arrays. Called when an array is matched.
#define ARRAY_COUNT_ARR(%9)%8$%0=%1; %8$%0=%1 + 1;
// Ending. Called when the parsing is complete.
#define ARRAY_COUNT_END(%9)%8$ %8$
// Ending. Called when there are no function parameters.
#define ARRAY_COUNT_NUL(%9)%8$ %8$
// Use the macro on a function.
ARRAY_COUNT:my_test_function(a, b[], c, const d[], &e = 6, string:f[] = "hi")
{
}
main()
{
printf("There are %d array parameters to \"my_test_function\"", countOf_my_test_function);
}
There are 3 array parameters to "my_test_function"
To understand the code, we need a clear idea of the code inputs and outputs (and a good understanding of the pre-processor helps as well).
This is the code input (input):
my_test_function(a, b[], c, const d[], &e = 6, string:f[] = "hi")
This is the code output (output):
stock const countOf_my_test_function = 0 + 1 + 1 + 1;
my_test_function(a, b[], c, const d[], &e = 6, string:f[] = "hi")
The bit of the output we really care about is just the first part:
stock const countOf_my_test_function = 0 + 1 + 1 + 1;
This starts out as:
stock const countOf_my_test_function = 0;
And has + 1
appended every time an array parameter is encountered, with other
parameters getting ignored (0 + 1 + 1 + 1
can be done by the compiler, so will
only generate 3
in the AMX, not a string of sums).
The library handles the hard part of understanding all the function parameter types (the input), but you still need to understand and split up your own code (the output).
Line By Line
#define ARRAY_COUNT:%1(%2) FUNC_PARSER(ARRAY_COUNT,ARR:NUM:)(%1(%2)) stock const countOf_%1 = 0; %1(%2)
#define ARRAY_COUNT:%1(%2)
This is just the macro name and match as normal. Will match anything that looks
like a function with a tag of ARRAY_COUNT:
.
FUNC_PARSER(ARRAY_COUNT,ARR:NUM:)(%1(%2))
Create a new function parser called ARRAY_COUNT
, define which parameter types
it will analyse, and pass it the input. The parameter type parsers are all
followed by colons and not separated by commas (or any spaces - that is VERY
important).
DO NOT PUT ANY SPACES IN THIS PART!
ARR:
will detect any array. NUM:
is essentially other - it will detect
anything not detected by any other parser. There is also EXT:
(extended)
which will detect ...
, REF:
(reference) which will detect &a
, and STR:
(string) which will detect string:a[]
. This last point is important - because
strings look exactly like arrays (a[]
and a[]
- because they ARE arrays) but
are frequently handled differently (for example using s
instead of a
in
CallRemoteFunction
) this library uses the YSI convention of prefixing all
strings with the string:
tag. This does not affect any other code in ANY way
- you won't even get any tag mismatch warnings because the tag is removed again later on in the compilation process. All it means is that the two types can be differentiated.
To modify the example so that strings are not included in the array count would look like:
#define ARRAY_COUNT:%1(%2) FUNC_PARSER(ARRAY_COUNT,ARR:NUM:STR:)(%1(%2)) stock const countOf_%1 = 0; %1(%2)
#define ARRAY_COUNT_STR(%9)%8$ %8$
ARRAY_COUNT
is used as a prefix to all other macros, so is prepended whenever
a macro callback is called (with a _
separator):
#define ARRAY_COUNT_NUM(%9)%8$ %8$
ARRAY_COUNT
is the custom prefix specified in the FUNC_PARSER
call. _NUM
is the suffix for any normal number variables (or anything not otherwise
matched). (%9)
is the parameters for this macro - things like name of the
variable, array size, default values, etc. These are not used here, so they can
just be ignored. %8$
is required in both the input and the output, but is
exclusively part of the parser and is what makes the iteration work. The
contents of %8
are just the current parser state, $
is the delimiter after
which comes your stuff (if desired, here it isn't).
#define ARRAY_COUNT_ARR(%9)%8$%0=%1; %8$%0=%1 + 1;
This is a more complex callback. Everything up to the $
is the same -
parameters and internal state, with the %8$
also appearing in the output
because it is always required (not putting that there will just break the
compilation).
In the #define ARRAY_COUNT:
line, the first thing that came after the call to
FUNC_PARSER
was stock const countOf_%1 = 0;
. This is the start of user-
generated output, and is what now appears after the $
. So because we want to
change this to stock const countOf_%1 = 0 + 1;
, we match against that code
with: %0=%1;
(technically even the %0=
isn't required as %1;
will just
match everything up to the first semi-colon). Copying that to the output gives
%0=%1 + 1;
. We don't need the function definition at the very end, so there's
no point matching against it.
#define ARRAY_COUNT_END(%9)%8$ %8$
Called when the parsing is complete.
#define ARRAY_COUNT_NUL(%9)%8$ %8$
Called when there are no function parameters.
We can extend the example again to count all parameter types. For this, we will set up some naming rules first:
Substitution parameter | Use |
---|---|
%0 |
The current reference count (&a ). |
%1 |
The current varargs count (... ) - should only be 0 or 1 but the parser doesn't check that, it can parse quite incorrect code. |
%2 |
The current array count (a[] ). |
%3 |
The current string count (string:a[] ). |
%4 |
The current other count (a ). |
%8 |
The parser state (black box). |
%9 |
Unused other parameters. |
// Entry. Parse all parameter types.
#define ALL_COUNT:%1(%2) FUNC_PARSER(ALL_COUNT,ARR:NUM:EXT:STR:REF:)(%1(%2)) \
stock const \
refCount_%1 = 0, \
extCount_%1 = 0, \
arrCount_%1 = 0, \
strCount_%1 = 0, \
numCount_%1 = 0; \
%1(%2)
// Counts. Add one to the relevant number.
#define ALL_COUNT_REF(%9)%8$%0,%1,%2,%3,%4; %8$%0 + 1,%1,%2,%3,%4;
#define ALL_COUNT_EXT(%9)%8$%0,%1,%2,%3,%4; %8$%0,%1 + 1,%2,%3,%4;
#define ALL_COUNT_ARR(%9)%8$%0,%1,%2,%3,%4; %8$%0,%1,%2 + 1,%3,%4;
#define ALL_COUNT_STR(%9)%8$%0,%1,%2,%3,%4; %8$%0,%1,%2,%3 + 1,%4;
#define ALL_COUNT_NUM(%9)%8$%0,%1,%2,%3,%4; %8$%0,%1,%2,%3,%4 + 1;
// Endings
#define ALL_COUNT_END(%9)%8$ %8$
#define ALL_COUNT_NUL(%9)%8$ %8$
The first macro is spread over multiple lines for clarity, but doesn't have to be.
Use:
ALL_COUNT:all_test_function(a, b[], c, const d[], &e = 6, string:f[] = "hi")
{
}
main()
{
printf("There are %d reference parameters to all_test_function", refCount_all_test_function);
printf("There are %d extended parameters to all_test_function", extCount_all_test_function);
printf("There are %d array parameters to all_test_function", arrCount_all_test_function);
printf("There are %d string parameters to all_test_function", strCount_all_test_function);
printf("There are %d other parameters to all_test_function", numCount_all_test_function);
}
Lets go back to the first example and modify it to show not just the number of
array parameters, but also their combined size. First a side-note - function
array parameters are often written as []
, which we will count as a size of 0.
However, writing 1 + + 10
is not valid syntax - we actually need a number
there. Writing (size +0)
when there is a size will resolve to (size)
, when
there isn't a size it will resolve to (+0)
, the unary plus and legal, giving
(1+0) + (+0) + (1+0)
. This is the simplest method of dealing with potentially
empty macros.
How do we get the size though?
Previously the addition macro was:
#define ARRAY_COUNT_ARR(%9)%8$%0=%1; %8$%0=%1 + 1;
The (%9)
was a placeholder for parameters we didn't care about - it will
consume them all and drop them. However, each of the _ARR
, _STR
, _NUM
,
_EXT
, and _REF
macros take several parameters:
Substitution parameter | Use |
---|---|
%0 |
const (if it exists). |
%1 |
The tag (if there is one - and only the first if there are many, includes the : ). |
%2 |
The variable name (only always present value). |
%3 |
Length (strings only). |
%4 |
Default value (if it exists, not on arrays). |
%3+ |
Dimension sizes (arrays only). |
These parameters:
const Float:pos[3]
string:name[] = "Bob"
&v
Float:v = 0
Would call as:
ARRAY_COUNT_ARR(const ,Float:,pos,3)
ARRAY_COUNT_STR(,,name,,"Bob")
ARRAY_COUNT_REF(,,v,)
ARRAY_COUNT_NUM(,Float:,v,0)
Note that the string:
tag does NOT get passed - it is special and purely used
for internal differentiation.
We can thus change the macro to use one parameter and just ignore the others:
#define ARRAY_COUNT_ARR(%0,%1,%2,%3)%8$%6;%7; %8$%6 + 1;%7 + (%3 +0);
If you didn't know, you can also use the same substitution variable multiple
times in one macro, with the value getting overridden each time. I like to do
this on values that are getting ignored, with %9
for it:
#define ARRAY_COUNT_ARR(%9,%9,%9,%4)%8$%0;%1; %8$%0 + 1;%1 + (%4 +0);
This makes the full thing:
// The entry point. Defines our parser.
#define ARRAY_COUNT:%1(%2) FUNC_PARSER(ARRAY_COUNT,ARR:NUM:)(%1(%2)) stock const countOf_%1 = 0; stock const sizeOf_%1 = 0; %1(%2)
#define ARRAY_COUNT_NUM(%9)%8$ %8$
#define ARRAY_COUNT_ARR(%9,%9,%9,%3)%8$%0;%1; %8$%0 + 1;%1 + (%3 +0);
#define ARRAY_COUNT_END(%9)%8$ %8$
#define ARRAY_COUNT_NUL(%9)%8$ %8$
// Use the macro on a function.
ARRAY_COUNT:my_test_function(a, b[], c, const d[], &e = 6, string:f[] = "hi")
{
}
main()
{
printf("There are %d array parameters with size %d to \"my_test_function\"", countOf_my_test_function, sizeOf_my_test_function);
}
Tags are always included with their :
. This could be detected and ignored
with:
#define PREFIX_ARR(%0,%1:,%2,%3)%8$ %8$
But it should be noted that while that will return tags without their colon, it will now fail to work for any variable without a tag at all.
Time for a more advanced example, using the parameter names more. The end
result will be a new keyword remote
which behaves like public
, but also
generates code to call CallRemoteFunction
directly with the correct string
specifier for out function. Doing:
remote my_func(a, b[], c)
{
}
Will generate:
my_func(a, b[], c) CallRemoteFunction("remote_my_func", "iai", a, b, c);
forward remote_my_func(a, b[], c);
public remote_my_func(a, b[], c)
{
}
Thus just doing: my_func(10, arr, sizeof (arr));
in code will call all scripts
at once, not just this one.
A normal macro would not be able to determine the exact string iai
to use in
this situation, and just using the parameters directly in CallRemoteFunction
would result in the invalid call a, b[], c
.
First, we define the entry point and bulk of the output:
#define remote%0(%1) FUNC_PARSER(REMOTE,ARR:STR:NUM:)(%0(%1)) \
%0(%1) CallRemoteFunction("remote_"#%0, ##); \
forward remote_%0(%1); \
public remote_%0(%1)
We also define a helper macro to turn remote_ my_func
in to remote_my_func
:
#define remote_%0\32; remote_%0
For each of the parameter types, we add a letter to the end of the specifier
string, and add the parameter name to the end of the CallRemoteFunction
parameter list:
#define REMOTE_ARR(%9,%9,%2,%9)%8$%0(%1)%3(%4#%5#%6#%7) %8$%0(%1)%3(%4#%5#%6a#%7,%2)
#define REMOTE_STR(%9,%9,%2,%9)%8$%0(%1)%3(%4#%5#%6#%7) %8$%0(%1)%3(%4#%5#%6s#%7,%2)
#define REMOTE_NUM(%9,%9,%2)%8$%0(%1)%3(%4#%5#%6#%7) %8$%0(%1)%3(%4#%5#%6i#%7,%2)
You could abstract this further, since the only tiny difference between those
three macros is the letter inserted at the end between the two #
s. The reason
why %0(%1)%3(%4#
was used instead of just %0#
to skip over everything up to
the first #
is that the #
is inside some brackets, and they are handled very
specially by the pre-processor unless you explicitly match against the (
.
Finally, we need the two end macros because they are required but don't do anything in this instance:
#define REMOTE_END(%9)%8$ %8$
#define REMOTE_NUL(%9)%8$ %8$
-
The
forward
keyword is optional. -
A public function with only a semi-colon after it is a forward.
-
An
@
prefix declares a function public.
We can thus shrink this code to:
#define remote%0(%1) FUNC_PARSER(REMOTE,ARR:STR:NUM:)(%0(%1)) stock%0(%1)CallRemoteFunction("@r_"#%0,##);@r_%0(%1);@r_%0(%1)
#define @r_%0\32; @r_
As a side-effect of point interesting fact 2, writing this:
remote truly_remote(x, y, z);
Will declare the function but not define it, allowing a function in a different script to be easilly called from here.
You may have noticed that all normal variables are passed as i
, never f
.
PAWN is typeless - the tags are only a hint to the compiler, and only matter at
all for some operators, which can be overloaded based on tag. Using i
instead
of f
makes no difference at all here. To be really strict you could use:
#define REMOTE_NUM(%9,%9,%2)%8$%0(%1)%3(%4#%5#%6#%7) %8$%0(%1)%3(%4#%5#%6i#%7,_:%2)
Detecting only the Float:
tag and leaving all others is much more involved,
and just not worth it.
For the next example, we are going to write a set of macros that perfectly output their input... This sounds pointless - and in code it would be, but is important here for demonstrating every parameter of every callback macro, including some I slightly lied about previously (or rather simplified). The first lie was about default parameters.
Earlier I stated that:
const Float:pos[3]
string:name[] = "Bob"
&v
Float:v = 0
Gave:
ARRAY_COUNT_ARR(const ,Float:,pos,3)
ARRAY_COUNT_STR(,,name,,"Bob")
ARRAY_COUNT_REF(,,v)
ARRAY_COUNT_NUM(,Float:,v,0)
In actual fact, when a default value is present an extra bit is appended to the macro name to aid in processing. So the real output is:
ARRAY_COUNT_ARR(const ,Float:,pos,3)
ARRAY_COUNT_STR_DEF(,,name,,"Bob")
ARRAY_COUNT_REF(,,v)
ARRAY_COUNT_NUM_DEF(,Float:,v,0)
Note that const
has a space after it (the reason for which will be seen
shortly).
The other potential suffix is for multi-dimensional arrays:
const Float:pos[][3][MY_ENUM]
Becomes:
ARRAY_COUNT_ARR_ARR_ARR(const,Float:,pos,,3,MY_NUM)
The number of _ARR
suffixes determine the number of dimensions.
The parameters might be a little confusing, so:
PREFIX_NUM(const, tag, name)
PREFIX_NUM_DEF(const, tag, name, default)
PREFIX_REF(, tag, name)
PREFIX_REF_DEF(, tag, name, default)
PREFIX_EXT(, tag,)
PREFIX_STR(const,, name, size)
PREFIX_STR_DEF(const,, name, size, default)
PREFIX_ARR(const, tag, name, size_1)
PREFIX_ARR_ARR(const, tag, name, size_1, size_2)
PREFIX_ARR_ARR_ARR(const, tag, name, size_1, size_2, size_3)
PREFIX_ARR_ARR_ARR_ARR(const, tag, name, size_1, size_2, size_3, size_4)
Reference parameters can never be const
(that makes no sense), so they will
never have const
passed. However, they still have the parameter there but it
is safe to ignore. Same with extended (vararg) parameters, which can also not
have default values so there is no _DEF
variant of them. For everything else
the const
is optional - it may be there or it may be a blank parameter. As
we will see, often it doesn't matter either way. Finally, anything more than
two dimensions in an array and the user should probably rethink everything
anyway, so don't worry about the really long ones. Strings have the tag
parameter but never use it, and can only ever have one dimension.
The other simplification was that all of these variations are detected for you - they are not, they must be requested. Each type (with/without const, defaults, etc) requires extra macros. It is always STRONGLY recommended that you use the updated compiler where this doesn't matter at all, but for very complex macros on the default compiler, long functions with many options may blow past the line length limit. Also, for some contexts it may not matter - public functions can't have default values etc, so why bother scanning for them doing extra work that isn't required? The options are:
Name | Use |
---|---|
TAG | Look for tags. |
MUL | Allow multi-dimensional arrays (more than one dimension). |
CST | Look for const . |
DEF | Look for defaults. |
The earlier parsers shown didn't use any of these, as often they weren't needed because the actual values weren't used. A parser that would detect every combination of parameter types would look something like:
FUNC_PARSER(REBUILD,ARR_MUL_TAG_CST:NUM_TAG_CST_DEF:REF_TAG_DEF:EXT_TAG:STR_CST_DEF:)(input)
There are also longer synonyms if you prefer clarity:
FUNC_PARSER(REBUILD,ARRAY_TAG_CONST_MULTI:NUMBER_CONST_TAG_DEFAULT:TAG_REFERENCE_DEFAULT:TAG_VARARG:DEFAULT_STRING_CONST:)(input)
Clearly, the order of parts doesn't matter - ARR_MUL_CST
and CST_MUL_ARR
are
the same.
The code to output one parameter exactly as it came in would be:
#define REBUILD_NUM(%0,%1,%2)%8$ %8$%0 %1%2
#define REBUILD_NUM_DEF(%0,%1,%2,%4)%8$ %8$%0 %1%2 = %4
#define REBUILD_REF(,%1,%2)%8$ %8$ & %1%2
#define REBUILD_REF_DEF(,%1,%2,%4)%8$ %8$ & %1%2 = %4
#define REBUILD_EXT(,%1,)%8$ %8$ %1...
#define REBUILD_STR(%0,,%2,%3)%8$ %8$%0 %2[%3]
#define REBUILD_STR_DEF(%0,,%2,%3,%4)%8$ %8$%0 %2[%3] = %4
#define REBUILD_ARR(%0,%1,%2,%3)%8$ %8$%0 %1%2[%3]
#define REBUILD_ARR_ARR(%0,%1,%2,%3,%4)%8$ %8$%0 %1%2[%3][%4]
#define REBUILD_ARR_ARR_ARR(%0,%1,%2,%3,%4,%5)%8$ %8$%0 %1%2[%3][%4][%5]
#define REBUILD_ARR_ARR_ARR_ARR(%0,%1,%2,%3,%4,%5,%6)%8$ %8$%0 %1%2[%3][%4][%5][%6]
If there is a const
, it will appear. If there isn't it won't. If there is a
tag it will appear. If there isn't it won't. Further, the const
parameter
actually includes its own space for efficiency reasons, so this works too:
#define REBUILD_NUM(%0,%1,%2)%8$ %8$%0%1%2
#define REBUILD_NUM_DEF(%0,%1,%2,%4)%8$ %8$%0%1%2=%4
#define REBUILD_REF(,%1,%2)%8$ %8$&%1%2
#define REBUILD_REF_DEF(,%1,%2,%4)%8$ %8$&%1%2=%4
#define REBUILD_EXT(,%1,)%8$ %8$%1...
#define REBUILD_STR(%0,,%2,%3)%8$ %8$%0%2[%3]
#define REBUILD_STR_DEF(%0,,%2,%3,%4)%8$ %8$%0%2[%3]=%4
#define REBUILD_ARR(%0,%1,%2,%3)%8$ %8$%0%1%2[%3]
#define REBUILD_ARR_ARR(%0,%1,%2,%3,%4)%8$ %8$%0%1%2[%3][%4]
#define REBUILD_ARR_ARR_ARR(%0,%1,%2,%3,%4,%5)%8$ %8$%0%1%2[%3][%4][%5]
#define REBUILD_ARR_ARR_ARR_ARR(%0,%1,%2,%3,%4,%5,%6)%8$ %8$%0%1%2[%3][%4][%5][%6]
That code will correctly render each individual parameter, but will not
correctly reform a full function call. There are no commas and, because there
is no matching against everything already output, this will reverse the
parameters (which is a cool trick, but not what we want here). The larger
version would look like the following, using a second $
to denote the current
end of the parameter list:
#define REBUILD:%0(%1) FUNC_PARSER(REBUILD,ARR_MUL_TAG_CST:NUM_TAG_CST_DEF:REF_TAG_DEF:EXT_TAG:STR_CST_DEF:)(%0(%1))%0($)
#define REBUILD_NUM(%0,%1,%2)%8$%7(%9$) %8$%7(%9, %0 %1%2 $)
#define REBUILD_NUM_DEF(%0,%1,%2,%4)%8$%7(%9$) %8$%7(%9, %0 %1%2 = %4 $)
#define REBUILD_REF(,%1,%2)%8$%7(%9$) %8$%7(%9, & %1%2 $)
#define REBUILD_REF_DEF(,%1,%2,%4)%8$%7(%9$) %8$%7(%9, & %1%2 = %4 $)
#define REBUILD_EXT(,%1,)%8$%7(%9$) %8$%7(%9, %1... $)
#define REBUILD_STR(%0,,%2,%3)%8$%7(%9$) %8$%7(%9, %0 %2[%3] $)
#define REBUILD_STR_DEF(%0,,%2,%3,%4)%8$%7(%9$) %8$%7(%9, %0 %2[%3] = %4 $)
#define REBUILD_ARR(%0,%1,%2,%3)%8$%7(%9$) %8$%7(%9, %0 %1%2[%3] $)
#define REBUILD_ARR_ARR(%0,%1,%2,%3,%4)%8$%7(%9$) %8$%7(%9, %0 %1%2[%3][%4] $)
#define REBUILD_ARR_ARR_ARR(%0,%1,%2,%3,%4,%5)%8$%7(%9$) %8$%7(%9, %0 %1%2[%3][%4][%5] $)
#define REBUILD_ARR_ARR_ARR_ARR(%0,%1,%2,%3,%4,%5,%6)%8$%7(%9$) %8$%7(%9, %0 %1%2[%3][%4][%5][%6]$)
#define REBUILD_END(%9)%8$%7(,%9$) %8$%7(%9)
#define REBUILD_NUL(%9)%8$%7($) %8$%7()
Here the two ending macros come in useful. Before they trigger the first parameter will have a leading comma, and the last parameter will have a trailing dollar. They remove those match artifacts.
A reminder of the current remote
macro:
#define remote%0(%1) FUNC_PARSER(REMOTE,ARR:STR:NUM:)(%0(%1)) \
stock %0(%1) CallRemoteFunction("remote_"#%0, ##); \
forward remote_%0(%1); \
public remote_%0(%1)
#define remote_%0\32; remote_%0
#define REMOTE_ARR(%9,%9,%2,%9)%8$%0(%1)%3(%4#%5#%6#%7) %8$%0(%1)%3(%4#%5#%6a#%7,%2)
#define REMOTE_STR(%9,%9,%2,%9)%8$%0(%1)%3(%4#%5#%6#%7) %8$%0(%1)%3(%4#%5#%6s#%7,%2)
#define REMOTE_NUM(%9,%9,%2)%8$%0(%1)%3(%4#%5#%6#%7) %8$%0(%1)%3(%4#%5#%6i#%7,%2)
#define REMOTE_END(%9)%8$ %8$
#define REMOTE_NUL(%9)%8$ %8$
Modifying this to return a value is apparently simple:
#define remote%0(%1) FUNC_PARSER(REMOTE,ARR:STR:NUM:)(%0(%1)) \
stock %0(%1) return CallRemoteFunction("remote_"#%0, ##); \
forward remote_%0(%1); \
public remote_%0(%1)
But optionally returning a value not so much.
In this library and others (YSI) no return uses the C naming of void:
when
the code from returns and no returns is different.
Adding a return value was simple, but it may not always be wanted if the
underlying function doesn't return a value. This is where void:
comes in.
void:
is similar to string:
in that it is not a real tag, just a macro to
provide hints to parsers on what code to generate. It is removed from the final
code (not that this would make any difference - you can't get a tag mismatch
warning when you don't return anything at all - that's an error regardless of
the tag).
We can request parsing of return types in the same way as parameters (RET
=
RETURN
, VOD
= VOID
):
FUNC_PARSER(REMOTE,ARR:STR:NUM:RET_VOD:)
If no special return type is found, it is assumed to be a normal return, and
this fact is passed to the end macros, where we can insert the return
:
#define REMOTE_END(%9)%8$%0(%1) %8$%0(%1)return
#define REMOTE_NUL(%9)%8$%0(%1) %8$%0(%1)return
To ensure a space is inserted between return
and CallRemoteFunction
, more
matching is required (trailing spaces on the replacement value are simply
ignored):
#define REMOTE_END(%9)%8$%0(%1)%2(%3) %8$%0(%1)return %2(%3)
#define REMOTE_NUL(%9)%8$%0(%1)%2(%3) %8$%0(%1)return %2(%3)
Since we have requested detection of void:
, handle that case as well:
#define REMOTE_END_VOD(%9)%8$ %8$
#define REMOTE_NUL_VOD(%9)%8$ %8$
There is no return
by default, so if one isn't needed there is nothing to do.
A tag return is passed as an extra macro parameter.
FUNC_PARSER(REMOTE,ARR:STR:NUM:RET_TAG:)
#define REMOTE_END_TAG(%7,%9)%8$%0(%1)%2(%3) %8$%0(%1)return %7:%2(%3)
There is no much to say about these - for the most part tags aren't actually
that interesting from a code generation point of view since they behave the same
as tagless returns, and in almost all code location tag:func()
is just as
valid as func()
, so there's no point detecting them.
Detecting either return variation would look like:
FUNC_PARSER(REMOTE,ARR:STR:NUM:RET_TAG_VOD:)
#define REMOTE_END_TAG(%7,%9)%8$%0(%1)%2(%3) %8$%0(%1)return %7:%2(%3)
#define REMOTE_END(%9)%8$%0(%1)%2(%3) %8$%0(%1)return %2(%3)
#define REMOTE_END_VOD(%9)%8$ %8$
#define REMOTE_NUL_TAG(%7,%9)%8$%0(%1)%2(%3) %8$%0(%1)return %7:%2(%3)
#define REMOTE_NUL(%9)%8$%0(%1)%2(%3) %8$%0(%1)return %2(%3)
#define REMOTE_NUL_VOD(%9)%8$ %8$
At a basic level, string returns are handled the same as other return types:
FUNC_PARSER(REMOTE,ARR:STR:NUM:RET_STR:)
#define REMOTE_END_STR(%9)%8$%0(%1)%2(%3) %8$%0(%1)return %2(%3)
#define REMOTE_END(%9)%8$%0(%1)%2(%3) %8$%0(%1)return %2(%3)
That's the generic version, but CallRemoteFunction
can't return a string, so
for this example some serious restructuring is required to enable it. If the
underlying function has a string return, the public function should wrap that in
something else, like a property, and the called function should return that
property's contents. There are several other considerations and corner cases
for a full version of this code, but they aren't important here. The output of
a regular return should look like:
stock my_func(a, b[], c)
{
return CallRemoteFunction("remote_my_func", "iai", a, b, c);
}
forward remote_my_func(a, b[], c);
public remote_my_func(a, b[], c)
{
return 1;
}
While the output of a string return should be quite structurally different:
stock my_func(a, b[], c)
{
new ret[32];
CallRemoteFunction("remote_my_func", "iai", a, b, c);
getproperty(0, "", 101, ret);
return ret;
}
forward remote_my_func(a, b[], c);
public remote_my_func(a, b[], c)
{
setproperty(0, "", 101, underlying_my_func(a, b, c));
}
static underlying_my_func(a, b[], c)
{
// Can't return string literals in this design, even with the new compiler.
new ret[32] = "hi";
return ret;
}
There are three parameter-dependent parts of this code: the input parameters
a, b[], c
, the call parameters a, b, c
, and the specifier iai
, each used
in potentially many places. Creating the full code structure from the start as
done before is non trivial, instead I like to collate all the data THEN build
the structure:
#define remote%0(%1) FUNC_PARSER(REMOTE,ARR:STR:NUM:RET_TAG_VOD_STR:)(%0(%1)) %0(%1)##$
#define remote_%0\32; remote_%0
The output here is very simply %0(%1)##$
- this is just our structure in to
which all the individual components will be placed for later processing. To
insert the parameters looks like:
#define REMOTE_ARR(%9,%9,%2,%9)%8$%0(%1)#%6#%7$ %8$%0(%1)#%6a#%7,%2$
#define REMOTE_STR(%9,%9,%2,%9)%8$%0(%1)#%6#%7$ %8$%0(%1)#%6s#%7,%2$
#define REMOTE_NUM(%9,%9,%2)%8$%0(%1)#%6#%7$ %8$%0(%1)#%6i#%7,%2$
After the processing of the my_func(a, b[], c)
example, this will have
produced:
my_func(a, b[], c)#iai#, a, b, c$
Not valid code, but has all the components required to generate the full code. The basic version is simple, and now happens in the end macro instead:
#define REMOTE_END(%9)%8$%0(%1)#%6#,%7$ %8$ \
stock %0(%1) return CallRemoteFunction("remote_"#%0, #%6#,%7); \
forward remote_%0(%1); \
public remote_%0(%1)
#define REMOTE_NUL(%9)%8$%0(%1)##$ %8$ \
stock %0(%1) return CallRemoteFunction("remote_"#%0, ##); \
forward remote_%0(%1); \
public remote_%0(%1)
Void returns are also simple (and almost identical):
#define REMOTE_END_VOD(%9)%8$%0(%1)#%6#,%7$ %8$ \
stock %0(%1) CallRemoteFunction("remote_"#%0, #%6#,%7); \
forward remote_%0(%1); \
public remote_%0(%1)
#define REMOTE_NUL_VOD(%9)%8$%0(%1)##$ %8$ \
stock %0(%1) CallRemoteFunction("remote_"#%0, ##); \
forward remote_%0(%1); \
public remote_%0(%1)
,%7
could be written in all places above as %7
- there is a leading comma
from the processing, but it is required in the CallRemoteFunction
parameter
list. In that case the _NUL
variants become identical to the _END
variants:
#define REMOTE_END(%9)%8$%0(%1)#%6#%7$ %8$ \
stock %0(%1) return CallRemoteFunction("remote_"#%0, #%6#%7); \
forward remote_%0(%1); \
public remote_%0(%1)
#define REMOTE_END_VOD(%9)%8$%0(%1)#%6#%7$ %8$ \
stock %0(%1) CallRemoteFunction("remote_"#%0, #%6#%7); \
forward remote_%0(%1); \
public remote_%0(%1)
#define REMOTE_NUL REMOTE_END
#define REMOTE_NUL_VOD REMOTE_END_VOD
Where this is not the case is in the underlying_
parameter list in the string
return variant (_STR
). Detection of the leading comma is required then:
#define REMOTE_END_STR(%9)%8$%0(%1)#%6#,%7$ %8$ \
stock %0(%1) \
{ \
new ret[32] = ""; \
CallRemoteFunction("remote_"#%0, #%6#,%7); \
getproperty(0, "", 101, ret); \
return ret; \
} \
\
forward remote_%0(%1); \
public remote_%0(%1) \
{ \
setproperty(0, "", 101, underlying_%0(%7)); \
} \
\
stock underlying_%0(%1)
#define REMOTE_NUL_STR(%9)%8$%0(%1)##$ %8$ \
stock %0() \
{ \
new ret[32] = ""; \
CallRemoteFunction("remote_"#%0, #%6#); \
getproperty(0, "", 101, ret); \
return ret; \
} \
\
forward remote_%0(); \
public remote_%0() \
{ \
setproperty(0, "", 101, underlying_%0()); \
} \
\
static underlying_%0()
#define underlying_%0\32; underlying_%0
The above code was spread out, and actually wrong. This:
#define underlying_%0\32; underlying_%0
Will output:
underlying_string:my_func()
Because we are using the original function name given to the parser, not the parsed name.
Combinations of const
and defaults (parameter tags can be ignored) are not
well handled. The public
function should keep const
, but drop defaults;
the CallRemoteFunction
call should drop both parts, so we actually need to
track three variations of the parameters:
(a, const b[], c = 11)
(a, const b[], c)
(a, b, c)
Most remote
declarations can also act as their own forward
:
remote void:other_func_6(a, c, const b[6]);
string:
ones cannot, as the final function is the underlying_
one, which is
actually called from the remote_
public, but will not be implemented.
The full code to fix these issues (except the string:
forwarding) is below.
It is already a lot more complex, but with any parser you must assess how much
flexibility you want to allow - maybe default values can be banned for example.
#define remote%0(%1) FUNC_PARSER(REMOTE,ARR_CST:STR_CST_DEF:NUM_CST_DEF:RET_TAG_VOD_STR:)(%0(%1)) ()(%1)##$
#define REMOTE_STR_DEF(%0,%1,%2,%3,%4)%8$(%9)(%5)#%6#%7$ %8$(%9,%0%2[%3])(%5)#%6s#%7,%2$
#define REMOTE_NUM_DEF(%0,%1,%2,%4)%8$(%9)(%5)#%6#%7$ %8$(%9,%0%2)(%5)#%6i#%7,%2$
#define REMOTE_ARR(%0,%1,%2,%3)%8$(%9)(%5)#%6#%7$ %8$(%9,%0%2[%3])(%5)#%6a#%7,%2$
#define REMOTE_STR(%0,%1,%2,%3)%8$(%9)(%5)#%6#%7$ %8$(%9,%0%2[%3])(%5)#%6s#%7,%2$
#define REMOTE_NUM(%0,%1,%2)%8$(%9)(%5)#%6#%7$ %8$(%9,%0%2)(%5)#%6i#%7,%2$
#define REMOTE_END(%9)%8$(,%1)(%5)#%6#,%7$ %8$ \
stock %9(%5) return CallRemoteFunction("remote_"#%9, #%6#,%7); \
forward remote_%9(%1); \
public remote_%9(%1)
#define REMOTE_END_VOD(%9)%8$(,%1)(%5)#%6#,%7$ %8$ \
stock %9(%5) CallRemoteFunction("remote_"#%9, #%6#,%7); \
forward remote_%9(%1); \
public remote_%9(%1)
#define REMOTE_END_TAG(%3,%9)%8$(,%1)(%5)#%6#,%7$ %8$ \
stock %3%9(%5) return %3CallRemoteFunction("remote_"#%9, #%6#,%7); \
forward %3remote_%9(%1); \
public %3remote_%9(%1)
#define REMOTE_NUL(%9)%8$()()##$ %8$ \
stock %9() return CallRemoteFunction("remote_"#%9, ##); \
forward remote_%9(); \
public remote_%9()
#define REMOTE_NUL_VOD(%9)%8$()()##$ %8$ \
stock %9() CallRemoteFunction("remote_"#%9, ##); \
forward remote_%9(); \
public remote_%9()
#define REMOTE_NUL_TAG(%3,%9)%8$()()##$ %8$ \
stock %3%9() return %3CallRemoteFunction("remote_"#%9, ##); \
forward %3remote_%9(); \
public %3remote_%9()
#define REMOTE_END_STR(%9)%8$(,%1)(%5)#%6#,%7$ %8$ \
stock %9(%5) \
{ \
new ret[32] = ""; \
CallRemoteFunction("remote_"#%9, #%6#,%7); \
getproperty(0, "", 101, ret); \
return ret; \
} \
\
forward remote_%9(%1); \
public remote_%9(%1) \
{ \
setproperty(0, "", 101, underlying_%9(%7)); \
} \
\
stock underlying_%9(%1)
#define REMOTE_NUL_STR(%9)%8$()()##$ %8$ \
stock %9() \
{ \
new ret[32] = ""; \
CallRemoteFunction("remote_"#%9, #%6#); \
getproperty(0, "", 101, ret); \
return ret; \
} \
\
forward remote_%9(); \
public remote_%9() \
{ \
setproperty(0, "", 101, underlying_%9()); \
} \
\
static underlying_%9()
#define underlying_%9\32; underlying_%9
#define remote_%9\32; remote_%9
remote DB:other_func_1(a, c, b[]);
remote other_func_2(a, c, string:b[]);
remote string:other_func_3(Text:a, c, b[])
{
new ret[32] = "hello";
return ret;
}
remote File:other_func_4(Text:a, c, const b[]);
remote other_func_5(Text:a, c, b[]);
remote void:other_func_6(a, c, const b[6]);
remote other_func_7(a, c, b[]);
remote other_func_8(const a, b[], Float:c);
remote void:other_func_9(const Float:a, c, b[]);
remote other_func_0(const Float:a, c, b[]);
remote string:other_func_a(const Float:a, c, b[])
{
new ret[32] = "implemented";
return ret;
}
remote Float:other_func_b(const a, b[], c = 6);
remote other_func_c(const a, c, b[]);
remote void:other_func_d(const a, c, b[]);
remote other_func(a, c, b[])
{
return 100;
}
main()
{
new var, Float:flt, str[32];
new arr[6] = { 1, 2, 3, 4, 5, 6 };
other_func_1(66, 99, arr);
var = other_func_2(66, 99, "hi");
str = other_func_3(Text:56, 4, arr);
other_func_4(Text:32, 5, arr);
var = other_func_5(Text:9, 6, arr);
other_func_6(5, 7, arr);
var = other_func_7(5, 7, arr);
var = other_func_8(700, arr, 99.0);
other_func_9(1.1, 11, arr);
var = other_func_0(1.2, 12, arr);
str = other_func_a(1.3, 13, arr);
flt = other_func_b(555, arr);
var = other_func_c(6, 9, arr);
other_func_d(6, 9, arr);
var = other_func(0, 1, arr);
}
Note that all of these examples are actually broken - an array passed to
CallRemoteFunction
MUST be immediately followed by its length, none of these
ones do that and so won't work. There are ways to enforce this at compile-time,
but the library currently doesn't.
This example is actually probably simpler than the last one, but I said I would end on it, so I will.
The end result is three macros - timer
, defer
, and repeat
; that in order
declare a timer with parameters, call it after a delay, and call it repeatedly
on a loop. The full version of the library allows for overriding the times at
the call site as well as the declaration site, but this clone will not. It is
also simplified by the fact that timers can't have return values. The full
version also fixes arrays, this one again doesn't, but that's not pre-processor
code. See Slice's include if you want a simple ready-made independent fix for
that.
#define timer%0[%2](%1) FUNC_PARSER(TIMER,ARR_CST:STR_CST_DEF:NUM_CST_DEF:LEN:)(%0(%1)) [%2]()(%1)##$
#define TIMER_STR_DEF(%0,%1,%2,%3,%4)%8$[%1](%9)(%5)#%6#%7$ %8$[%1](%9,%0%2[%3])(%5)#%6s#%7,%2$
#define TIMER_NUM_DEF(%0,%1,%2,%4)%8$[%1](%9)(%5)#%6#%7$ %8$[%1](%9,%0%2)(%5)#%6i#%7,%2$
#define TIMER_ARR(%0,%1,%2,%3)%8$[%1](%9)(%5)#%6#%7$ %8$[%1](%9,%0%2[%3])(%5)#%6a#%7,%2$
#define TIMER_STR(%0,%1,%2,%3)%8$[%1](%9)(%5)#%6#%7$ %8$[%1](%9,%0%2[%3])(%5)#%6s#%7,%2$
#define TIMER_NUM(%0,%1,%2)%8$[%1](%9)(%5)#%6#%7$ %8$[%1](%9,%0%2)(%5)#%6i#%7,%2$
#define TIMER_END(%9)%8$[%2](,%1)(%5)#%6#,%7$ %8$ \
stock defer_%9(__rep, %5) return SetTimerEx("timer_"#%9, (%2), __rep, #%6#, %7); \
forward timer_%9(%1); \
public timer_%9(%1)
#define TIMER_NUL(%9)%8$[%2]()()##$ %8$ \
stock defer_%9(__rep) return SetTimer("timer_"#%9, (%2), __rep); \
forward timer_%9(); \
public timer_%9()
#define timer_%9\32; timer_%9
#define defer_%9\32; defer_%9
#define _:%0,) _:%0)
#define defer%0(%1) defer_%0(_:0,%1)
#define repeat%0(%1) defer_%0(_:1,%1)
One tiny new macro to draw your attention to:
#define _:%0,) _:%0)
This consumes a trailing comma after the last parameter in a list. It cannot be
used everywhere, since you can't always know the true tag to use, but is useful
in cases like this where you can control the tag, and know that there may not be
any more parameters. Despite seemingly overriding the default _:
tag, it only
matches in very specific (otherwise invalid) cases so it doesn't break anything.
YSI has had this macro for years, and no-one has complained yet about it
breaking anything...
timer my_timer_1[500](const a, string:b[], c = 5)
{
}
timer my_timer_2[500](const a, string:b[], c = 5)
{
}
timer my_timer_3[500](const a, string:b[])
{
}
timer my_timer_4[500](const a, b[], d)
{
}
timer my_timer_5[500](const a, b[], d = sizeof (b))
{
}
timer my_timer_6[500](const a, b[], const d, e[], f)
{
}
main()
{
defer my_timer_1(34, "hi");
repeat my_timer_1(34, "hi");
}
CallRemoteFunction
, SetTimerEx
, and other natives that take variable
parameters with a specifier string require that arrays passed to them are
followed by the array length (so that memory can be allocated correctly). This
isn't required for strings as their length can be determined by the NULL byte.
This one fact is the sole reason for the radically different processing of
strings and arrays (i.e. a
vs. s
, and string:
).
This requirement can be enforced at compile-time by appending LEN:
to the end
of the parser definition. Most other definitions in FUNC_PARSER
can come in
any order - the library will determine the best order for them.
THE LEN:
SPECIFICATION MUST COME AT THE END.
#define timer%0[%2](%1) FUNC_PARSER(TIMER,ARR_CST:STR_CST_DEF:NUM_CST_DEF:LEN:)(%0(%1)) [%2]()(%1)##$
Beyond that, everything else is the same. Arrays and integers are called back
as normal individually, but now if an array is not followed by either a number
(a
) or a reference (&a
) the compiler will show error 017: undefined symbol "LENGTH_REQUIRED"
(this was the closest to a useful error that I could get).
This is fine:
#define timer%0[%2](%1) FUNC_PARSER(TIMER,ARR_CST:STR_CST_DEF:NUM_CST_DEF:LEN:)(%0(%1)) [%2]()(%1)##$
timer length_required[100](arr[], len)
{
}
This is fine:
#define timer%0[%2](%1) FUNC_PARSER(TIMER,ARR_CST:STR_CST_DEF:NUM_CST_DEF:)(%0(%1)) [%2]()(%1)##$
timer no_length_required[200](arr[])
{
}
This is not:
#define timer%0[%2](%1) FUNC_PARSER(TIMER,ARR_CST:STR_CST_DEF:NUM_CST_DEF:LEN:)(%0(%1)) [%2]()(%1)##$
timer length_required[100](arr[])
{
}
This is fine:
#define timer%0[%2](%1) FUNC_PARSER(TIMER,ARR_CST:STR_CST_DEF:NUM_CST_DEF:LEN:)(%0(%1)) [%2]()(%1)##$
timer length_required[200](arr[], len = sizeof (arr))
{
}
This is not:
#define timer%0[%2](%1) FUNC_PARSER(TIMER,ARR_CST:STR_CST_DEF:LEN:NUM_CST_DEF:)(%0(%1)) [%2]()(%1)##$
timer length_required[100](arr[], len = sizeof (arr))
{
}
This is not:
#define timer%0[%2](%1) FUNC_PARSER(TIMER,ARR_CST:STR_CST_DEF:NUM_CST:LEN:)(%0(%1)) [%2]()(%1)##$
timer length_required[200](arr[], len = sizeof (arr))
{
}
The last one is not allowed because only NUM_CST
was given, not NUM_CST_DEF
,
so default values on numbers are not allowed. The penultimate one has LEN:
in
the wrong place - this might work slightly, but not fully.
Function qualifiers are the bits that come before the name, i.e. stock
,
static
, const
, new
, operator
, forward
, public
, and native
. If you
are using YSI, this extends to include global
, foreign
, timer
, inline
,
ptask
, task
, remotefunc
, hook
, group_hook
, master_hook
,
master_task
, master_ptask
, master_func
, @foreign
, @global
,
timerfunc
, loadtext
, pvar
, and svar
. Several are only valid on
variables, const
and inline
are only used on inline functions, and more of
these are uncommon synonyms or alternate (backup) spellings.
The point is, keywords can be used before functions, and can be detected when
using the QAL:
modifier. The keywords are only detected if they come after
the main entry macro:
#define timer%0[%2](%1) FUNC_PARSER(TIMER,QAL:ARR_CST:STR_CST_DEF:NUM_CST_DEF:LEN:)(%0(%1)) [%2]()(%1)##$
#define TIMER_stock(%9)%8$ %8$ // Saw "stock"
Will be detected:
timer stock my_timer[100]()
{
}
Will not be detected:
stock timer my_timer[200]()
{
}
The PREFIX_keyword
macro is called after all the parameters have been
processed, but before the ending macros are called (_END
, _NUL
, etc.)
If you don't want to support a qualifier, just don't define it. If there is no
PREFIX_public
and they try use public
then they will get a very nice error
of error 017: undefined symbol "PREFIX_public"
.
Currently the keyword callbacks do not have any parameters, but use
PREFIX_forward(%9)
anyway - that will work even with zero parameters, and will
ensure future proofing in case more are added.
Special arrays are those declared through macros with <>
instead of []
,
e.g. iterators:
new Iterator:Vehicles<MAX_VEHICLES>;
The SPC
(SPECIAL
) and SPC_CST
(SPECIAL_CONST
) specifiers add detection
for these special arrays. There is no _TAG
variant since they always have a
tag by definition. Their callback would be:
#define PREFIX_SPC(%0,%1,%2,%3)%8$
With:
Substitution parameter | Use |
---|---|
%0 |
const (if it exists). |
%1 |
The special type - Iterator: above (with the colon, as ever). |
%2 |
The variable name - Vehicles above. |
%3 |
Size (anything between the <> s) - MAX_VEHICLES above. |
I did test Iterator:
with this, but that one generates so much other complex
code that it ran out of memory - the parser works, but just be careful with what
the special array macro generates later. Also, <>
s are not real brackets, so
commas between them will totally break everything, for example this:
MY_PARSER:func(Iterator:Vehicles<MAX_PLAYERS, MAX_VEHICLES>)
will be interpreted as two invalid parameters - Iterator:Vehicles<MAX_PLAYERS
and MAX_VEHICLES>
instead of what it should be.
Tag groups are multiple tags assigned to the same variable, most frequently seen as:
Func1({_, Float}:...)
{
}
However, any variable can have any tag groups on them:
Func2({_, Float}:a, &{bool, File, DB}:b, {Text, PlayerText}:tds[])
{
}
Calling tagof
on these variables at the function site will return the first
tag from the list (at the call site, it will always return the correct declared
tag). This makes the first tag the most important tag:
Func3({Text, PlayerText}:td, tag = tagof (td))
{
return (tag == tagof (Text:));
}
main()
{
new
Text:a,
PlayerText:b;
Func3(a); // true
Func3(a, tagof (a)); // true
Func3(b); // true
Func3(b, tagof (b)); // false
}
Tag groups cannot be used as tag overrides and will give an error:
main()
{
new
Float:a;
Func3({Text, PlayerText}:a); // Error
Func3(Text:a); // OK
}
For this reason it is important to be able to detect tag groups, and provide a
method for getting the correct values to tag override with. _GRP
or
_TAGGROUP
, when used in place of _TAG
, provides this:
With _TAG
:
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUL_TAG:)(%0(%1))
#define EXAMPLE_NUL(%0,%1,%2)%8$ "The tag is " #%1
EXAMPLE:Func(a:v); // The tag is a:
EXAMPLE:Func({a, b, c}:v); // The tag is {a, b, c}:
With _GRP
, both the whole tag group and the first tag (for overriding) are
provided. To keep backwards-compatability with the existing macro parameters,
they are BOTH given in %1
when _GRP
is used instead - even if there is no
tag group:
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUL_GRP:)(%0(%1))
#define EXAMPLE_NUL(%0,(%1,%3),%2)%8$ "The main is " #%1 ", the group is: " %3
EXAMPLE:Func(a:v); // The main is a:, the group is a:
EXAMPLE:Func({a, b, c}:v); // The main is a:, the group is {a, b, c}:
Note that this new sub-parameter code is on a per-type basis:
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUL_GRP:REF_TAG:ARR_GRP:EXT_TAG:)(%0(%1))
#define EXAMPLE_NUL(%0,(%1,%3),%2) // Correct.
#define EXAMPLE_REF(%0,%1,%2) // Correct.
#define EXAMPLE_ARR(%0,%1,%2) // Acceptable (ignores the sub-parameters).
#define EXAMPLE_EXT(%0,(%1,%3),%2) // Wrong (sub-parameters not expected).
For easy macro parameter management, if you only need the whole tag (but why are
you not just using _TAG
) use (%0,(%1,%1),%2)
. If you only want the main tag
use (%0,(%1,%2),%2)
. Macro parameters can appear more than once in the search
string and the old value will be replaced with the new one, so in both those
cases the value you don't need will be replaced with something else.
An alternate version of the REBUILD:
example using _GRP
instead of _TAG
and with many examples you can inspect using -l
to compile:
#define REBUILD:%0(%1) FUNC_PARSER(REBUILD,ARR_MUL_GRP_CST:NUM_GRP_CST_DEF:REF_GRP_DEF:EXT_GRP:STR_CST_DEF:SPC_CST:)(%0(%1))%0($)
#define REBUILD_NUM(%0,(%1,%1),%2)%8$%7(%9$) %8$%7(%9, %0 %1%2 $)
#define REBUILD_NUM_DEF(%0,(%1,%1),%2,%4)%8$%7(%9$) %8$%7(%9, %0 %1%2 = %4 $)
#define REBUILD_REF(,(%1,%1),%2)%8$%7(%9$) %8$%7(%9, & %1%2 $)
#define REBUILD_REF_DEF(,(%1,%1),%2,%4)%8$%7(%9$) %8$%7(%9, & %1%2 = %4 $)
#define REBUILD_EXT(,(%1,%1),)%8$%7(%9$) %8$%7(%9, %1... $)
#define REBUILD_STR(%0,,%2,%3)%8$%7(%9$) %8$%7(%9, %0 %2[%3] $)
#define REBUILD_STR_DEF(%0,,%2,%3,%4)%8$%7(%9$) %8$%7(%9, %0 %2[%3] = %4 $)
#define REBUILD_SPC(%0,%1,%2,%3)%8$%7(%9$) %8$%7(%9, %0 %1%2<%3> $)
#define REBUILD_ARR(%0,(%1,%1),%2,%3)%8$%7(%9$) %8$%7(%9, %0 %1%2[%3] $)
#define REBUILD_ARR_ARR(%0,(%1,%1),%2,%3,%4)%8$%7(%9$) %8$%7(%9, %0 %1%2[%3][%4] $)
#define REBUILD_ARR_ARR_ARR(%0,(%1,%1),%2,%3,%4,%5)%8$%7(%9$) %8$%7(%9, %0 %1%2[%3][%4][%5] $)
#define REBUILD_ARR_ARR_ARR_ARR(%0,(%1,%1),%2,%3,%4,%5,%6)%8$%7(%9$) %8$%7(%9, %0 %1%2[%3][%4][%5][%6]$)
#define REBUILD_END(%9)%8$%7(,%9$) %8$%7(%9)
#define REBUILD_NUL(%9)%8$%7($) %8$%7()
#define REBUILD_static(%9)%8$ %8$B
#define iter_%0\32; iter_
#define Example:%0<> iter_%0[10]
REBUILD:stock static rebuilt_func_1(a, c, b[]);
REBUILD:stock static rebuilt_func_2(a, &c, string:b[] = "");
REBUILD:stock static rebuilt_func_3(Text:a, c, b[]);
REBUILD:stock static rebuilt_func_4(Text:a, &c, const b[]);
REBUILD:stock rebuilt_func_5(Text:a, c, b[]);
REBUILD:stock rebuilt_func_6(a, &c, const b[6][7]);
REBUILD:stock rebuilt_func_7(a, c, b[]);
REBUILD:stock rebuilt_func_8(const a, b[], &Float:c = 66.4);
REBUILD:stock rebuilt_func_9(const Float:a, c, b[]);
REBUILD:public rebuilt_func_a(const Float:a, c, b[]);
REBUILD:public rebuilt_func_0(const Float:a, &c, b[]);
REBUILD:forward rebuilt_func_b(const a, b[], &c = 6);
REBUILD:rebuilt_func_c(const a, string:f[] = "hi", ...);
REBUILD:rebuilt_func_d(const a, c, {Float, _, Text}:...);
REBUILD:public rebuilt_func(a, c, b[]);
REBUILD:rebuilt_func_e(const a, c, Example:Player<>);
REBUILD:rebuilt_func_e(const a, c, Example:Player<>);
REBUILD:rebuilt_func_f(const Example:A<>, Example:Vehicle<>);
REBUILD:rebuilt_func_g(&{Tag1, Tag2}:a, {Float, Fake}:c);
The FUNC_PARSER
macro is the main API entry-point, and generates the macros to
do the parsing. The reason it is done this way is that things like
TAG_NUM_DEFAULT:
are pretty descriptive tags - that (relatively) clearly
indicates that you want the parser to detect numbers (regular variables, but
VAR
could be confused for both variable and vararg, hence it is avoided).
However, that tag is very long, this tag-macro based parsing method leaves a lot
of unmatched macros behind, and it is recursive. Long macros with short line-
length limits do not play well together.
The include is quite long, but it doesn't need to be. The vast majority of the code is to convert something like this:
FUNC_PARSER(REBUILD,ARRAY_TAG_CONST_MULTI:NUMBER_CONST_TAG_DEFAULT:TAG_REFERENCE_DEFAULT:TAG_VARARG:DEFAULT_STRING_CONST)(func(params))
In to this:
PARSER@FUNC:z@:l@:w@:x@<c@:b@:>a@:x@<f@:c@:t@:>v@:x@<t@:>r@:x@<t@:d@:>o@:x@<c@:t@:d@:>(REBUILD)func(||||||params,)$
I.e. just provides a nice API for using the parser. The actual complex part is
done by these few macros. Feel free to take just these if you want and derive
your own input to the magical PARSER@FUNC:
macro:
#define void:
#define string:
#define u@$ 1]);
#define PARSER@FUNC:%0$ u@(u[_:%0 u@$
#define c@:%8(%0,%1,%9const%2) %8(%0const ,%1,%9%2)
#define t@:%8(%0,%1,%9:%2) %8(%0,%1%9:,%2)
#define d@:%8(%0,%1,%2=%9) %8_DEF(%0,%1,%2,%9)
#define b@:%8(%0,%1,%2=%9,%4) %8_DEF(%0,%1,%2,%4,%9)
#define f@:%8(%0,%1,%2[%9]%6,%3) f@:%8_ARR(%0,%1,%2%6,%3,%9)
#define x@<%9>
#define w@:x@<%8>%9.%0(%5)(%4|||%6string:%1[%2]%9|||%7)%3$ %8%5_STR(,,%6%1%9,%2)%0(%5)(||||||%7)%3$
#define a@:x@<%8>%9.%0(%5)(%4|||%1[%2]%9|||%7)%3$ %8%5_ARR(,,%1%9,%2)%0(%5)(||||||%7)%3$
#define r@:x@<%8>%9.%0(%5)(%4|||%1&%2|||%7)%3$ %8%5_REF(,,%1%2)%0(%5)(||||||%7)%3$
#define v@:x@<%8>%9.%0(%5)(%4|||%1...%2|||%7)%3$ %8%5_EXT(,,%1%2)%0(%5)(||||||%7)%3$
#define o@:x@<%8>%9.%0(%5)(%4|||%1|||%7)%3$ %8%5_NUM(,,%1)%0(%5)(||||||%7)%3$
#define z@:%0(%5)(||||||,%7)%3$ %5_NUL()%7%3$
#define n@:%0(%5)(%4|||%6|||%7)%3$ %5_END()%7%3$
#define m@:n@:%0(%5)(%4|||%6|||%7,%8)%3$ %0.m@:n@:%0(%5)(%4%6|||%7|||%8)%3$
But don't be upset if the underlying macros change (since they have even since I copied them here).
This entire library is designed for parsing function declarations. These appear
at the global scope - with one exception: y_inline (or any other inline library
that someone cares to write). The PARSER@FUNC:
macro on which the tag-based
parsing works only works at the top level (I tried very hard to make it work
everywhere, but it just didn't QUITE happen). Note that this macro was
previously written as __:
(and that macro still has value), but it was renamed
in this library for flexibility, because it is internal, and to minimise global
namespace pollution.
y_inline converts this:
main()
{
inline InlineFunc(a, b[32], string:c[])
{
// Code.
}
}
In to:
main()
{
static InlineFunc[_:I@E:32]=# InlineFunc":....";if(I@E(_:@Ia:@Ib:@Ic:@Ib:@Ic:@Id: InlineFunc))for(new a, b[_:@Iy:32], c[_:(YSI_MAX_STRING)];I@F();)while(I@L(I@K(1),0,@Ix,sizeof c))
{
// Code.
}
}
Representing:
main()
{
static
InlineFunc[32] = "InlineFunc:....";
if (Inline_Entry(InlineFunc))
{
for (new a, b[32], c[YSI_MAX_STRING]; Inline_Allocator(); )
{
while (Inline_Main(HAS(const), 0, cellmax, sizeof (c)))
{
// Code.
}
}
}
}
This is rewritten at runtime to something equivalent to:
main()
{
goto after;
static InlineFunc = Inline_Start("InlineFunc", "ia[10]s", &start);
new a, b[10], string:c[];
{
start:
}
after:
}
The run-time implementation of y_inline is not the focus of this example though, only the macros.
Because inline functions are at a function local level, not a global level, we
need two custom macros to start and end the parsing. These closely mimick the
ones in the inclue (PARSER@FUNC:
and u@$
), but wrap all the tag macros up in
a local array size instead of a function parameter array size:
#define PARSER@INLINE:%0(%5)%6(%7)$ static %6[_:%0(%5)%6(%7) I@O$
#define I@O$ 32]=
The library normally calls PARSE@
once it has finished parsing the
FUNC_PARSER
parameters, to start the processing. Instead we call
MAKE_PARSER
directly, with an extra :INLINE
parameter.
#define inline%0(%1) MAKE_PARSER(INLINE,ARR:REF:STR:NUM:QAL::INLINE)(%0(%1))()1()
The I@O$
macro mirrors u@$
- both of them are there to remove the final $
on which most of the processing is based (this is the symbol used to skip over
internal state by %8$
, but needs removing eventually. They both also close
the array size in which the tag macros are hidden from the syntax checker.
From there the remaining macros are straight forward. First collate the
parameters in to two lists - one for names and one for numeric representations
of size and type (0
= variable, -1
= reference, cellmax
= string, other =
array (given as the size)).
#define INLINE_STR(%9,%9,%2,%9)%8$(%0)%1(%3) %8$(%0,%2[YSI_MAX_INLINE_STRING])%1(%3,cellmax)
#define INLINE_ARR(%9,%9,%2,%9)%8$(%0)%1(%3) %8$(%0,%2[%9])%1(%3,%9)
#define INLINE_NUM(%9,%9,%2)%8$(%0)%1(%3) %8$(%0,%2)%1(%3,0)
#define INLINE_REF(%9,%9,%2)%8$(%0)%1(%3) %8$(%0,%2)%1(%3,-1)
#define INLINE_END(%9)%8$(,%0)%1(%3) %8$#%9":....";if(I@E(%9))for(new %0;I@F();)while(I@L(I@K(%1)%3))
#define INLINE_NUL(%9)%8$()%1() %8$#%9":....";if(I@E(%9))for(;I@F();)while(I@L(I@K(%1)))
#define INLINE_const(%9)%8$(%0)%1(%2) %8$(%0)(%2)
Note that in writing this code, I found a bug in the old version, which was very
cleanly fixed in this code. The example above should read
while (Inline_Main(HAS(const), 0, sizeof (b), cellmax))
, but the code
presented there is as it is generated by the latest internal y_inline code.
This macro allows direct access to one internal part of the parser - the ability to detect a space immediately after a symbol. For example:
#define DETECT_CONST(const%0\32;%1)
DETECT_CONST(const a)
That will match, because const
is followed by a space. However, this will
ALSO match, because const
is still (eventually) followed by a space:
DETECT_CONST(constB )
In this case %0
will be B
, whereas in the first example it was `` (nothing).
The obvious solution is to try and specify that the space should be immediately
after the symbol:
#define DETECT_CONST(const\32;%1)
However, due to a quirk (bug/feature/flaw?) in the pre-processor, that will not work. Any character matched via an escape code MUST be preceeded by a match parameter. Instead, the trick used in this library is to test the contents of the parameter separately:
#define IS_NOTHING()
#define DETECT_CONST(const%0\32;%1) IS_NOTHING(%0)
IS_NOTHING
will not match if %0
contains anything. Armed with that
information, and a few more tag macros to handle the else
case, we can write
PARSER_ISOLATE
:
#define PARSER_ISOLATE(%0,%1){%2,%3} _:T@:O@$%1$%0${%2,%3}
#define T@:O@$$%0$(){%2,%3} %2(%0)
#define O@$%1$%0$(%9){%2,%3} %3(%9%0%1)
T@
detects the "nothing" case by matching $$
, O@
detects the "something"
case by matching $%1$
. %0
would in this example contain const
, %2
is
the macro to call when const
is on its own, %3
the macro to call when it
isn't. Both are passed everything passed in (so const
alone or the fully
reassembled symbol). We also want to detect that nothing OR spaces comes before
the const
(otherwise we still match symbols that end with const
), so this is
given in %9
; passed between brackets since they ignore spaces.
// `%1` is everything after the space.
#define HAS_CONST(%9)(%1) %1 is `const`
// `%9` is everything before the space.
#define NO_CONST(%9)(%1) %9 contains `const`
// Think of the brackets and braces here as somewhat like `if () {} else {}`.
#define DETECT_CONST(%9const%0\32;%1) PARSER_ISOLATE(%9,const,%0){HAS_CONST,NO_CONST}(%1)
Note that this code is designed to detect spaces and other awkwardness in end-user code. DO NOT use any extra spaces in the macros themselves or you'll probably break the result.
Example use:
DETECT_CONST(const a) // a has `const`
DETECT_CONST(constB ) // constB contains `const`
DETECT_CONST(a_const_var ) // a_const_var contains `const`
DETECT_CONST(constC) // Won't match.
DETECT_CONST( const d) // d is `const`
The last case is left to you to deal with. The lack of space detection is
actually in the example DETECT_CONST
macro, not PARSER_ISOLATE
, which is
written assuming you've already determined what needs testing.
All the specifiers, with all their variations, callbacks, and examples; in one place. Note that a lot of extra spacing has been added for clarity and ease of direct comparison.
AKA NUM
Detects standard variables.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2)%8$
EXAMPLE:Func( name ); // EXAMPLE_NUM(,, name )
EXAMPLE:Func( Tag:name ); // EXAMPLE_NUM(,, Tag:name )
EXAMPLE:Func( name = 7); // EXAMPLE_NUM(,, name = 7)
EXAMPLE:Func( Tag:name = 7); // EXAMPLE_NUM(,, Tag:name = 7)
EXAMPLE:Func(const name ); // EXAMPLE_NUM(,,const name )
EXAMPLE:Func(const Tag:name ); // EXAMPLE_NUM(,,const Tag:name )
EXAMPLE:Func(const name = 7); // EXAMPLE_NUM(,,const name = 7)
EXAMPLE:Func(const Tag:name = 7); // EXAMPLE_NUM(,,const Tag:name = 7)
EXAMPLE:Func( {Tag1, Tag2}:name ); // EXAMPLE_NUM(,, {Tag1, Tag2}:name )
EXAMPLE:Func( {Tag1, Tag2}:name = 7); // EXAMPLE_NUM(,, {Tag1, Tag2}:name = 7)
EXAMPLE:Func(const {Tag1, Tag2}:name ); // EXAMPLE_NUM(,,const {Tag1, Tag2}:name )
EXAMPLE:Func(const {Tag1, Tag2}:name = 7); // EXAMPLE_NUM(,,const {Tag1, Tag2}:name = 7)
AKA NUM_CST
Detects standard variables with optional const
s.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM_CST:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2)%8$
EXAMPLE:Func( name ); // EXAMPLE_NUM( ,, name )
EXAMPLE:Func( Tag:name ); // EXAMPLE_NUM( ,, Tag:name )
EXAMPLE:Func( name = 7); // EXAMPLE_NUM( ,, name = 7)
EXAMPLE:Func( Tag:name = 7); // EXAMPLE_NUM( ,, Tag:name = 7)
EXAMPLE:Func(const name ); // EXAMPLE_NUM(const ,, name )
EXAMPLE:Func(const Tag:name ); // EXAMPLE_NUM(const ,, Tag:name )
EXAMPLE:Func(const name = 7); // EXAMPLE_NUM(const ,, name = 7)
EXAMPLE:Func(const Tag:name = 7); // EXAMPLE_NUM(const ,, Tag:name = 7)
EXAMPLE:Func( {Tag1, Tag2}:name ); // EXAMPLE_NUM( ,,{Tag1, Tag2}:name )
EXAMPLE:Func( {Tag1, Tag2}:name = 7); // EXAMPLE_NUM( ,,{Tag1, Tag2}:name = 7)
EXAMPLE:Func(const {Tag1, Tag2}:name ); // EXAMPLE_NUM(const ,,{Tag1, Tag2}:name )
EXAMPLE:Func(const {Tag1, Tag2}:name = 7); // EXAMPLE_NUM(const ,,{Tag1, Tag2}:name = 7)
AKA NUM_DEF
Detects standard variables with optional default values.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM_DEF:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2,%4)%8$
#define EXAMPLE_NUM_DEF(%0,%1,%2,%4)%8$
EXAMPLE:Func( name ); // EXAMPLE_NUM (,, name)
EXAMPLE:Func( Tag:name ); // EXAMPLE_NUM (,, Tag:name)
EXAMPLE:Func( name = 7); // EXAMPLE_NUM_DEF(,, name,7)
EXAMPLE:Func( Tag:name = 7); // EXAMPLE_NUM_DEF(,, Tag:name,7)
EXAMPLE:Func(const name ); // EXAMPLE_NUM (,,const name)
EXAMPLE:Func(const Tag:name ); // EXAMPLE_NUM (,,const Tag:name)
EXAMPLE:Func(const name = 7); // EXAMPLE_NUM_DEF(,,const name,7)
EXAMPLE:Func(const Tag:name = 7); // EXAMPLE_NUM_DEF(,,const Tag:name,7)
EXAMPLE:Func( {Tag1, Tag2}:name ); // EXAMPLE_NUM (,, {Tag1, Tag2}:name)
EXAMPLE:Func( {Tag1, Tag2}:name = 7); // EXAMPLE_NUM_DEF(,, {Tag1, Tag2}:name,7)
EXAMPLE:Func(const {Tag1, Tag2}:name ); // EXAMPLE_NUM (,,const {Tag1, Tag2}:name)
EXAMPLE:Func(const {Tag1, Tag2}:name = 7); // EXAMPLE_NUM_DEF(,,const {Tag1, Tag2}:name,7)
AKA NUM_CST_DEF
Detects standard variables with optional const
s and default values.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM_CST_DEF:)(%0(%1))
#define EXAMPLE_NUM(%0,(%1,%3),%2)%8$
#define EXAMPLE_NUM_DEF(%0,%1,%2,%4)%8$
EXAMPLE:Func( name ); // EXAMPLE_NUM ( ,, name)
EXAMPLE:Func( Tag:name ); // EXAMPLE_NUM ( ,, Tag:name)
EXAMPLE:Func( name = 7); // EXAMPLE_NUM_DEF( ,, name,7)
EXAMPLE:Func( Tag:name = 7); // EXAMPLE_NUM_DEF( ,, Tag:name,7)
EXAMPLE:Func(const name ); // EXAMPLE_NUM (const ,, name)
EXAMPLE:Func(const Tag:name ); // EXAMPLE_NUM (const ,, Tag:name)
EXAMPLE:Func(const name = 7); // EXAMPLE_NUM_DEF(const ,, name,7)
EXAMPLE:Func(const Tag:name = 7); // EXAMPLE_NUM_DEF(const ,, Tag:name,7)
EXAMPLE:Func( {Tag1, Tag2}:name ); // EXAMPLE_NUM ( ,,{Tag1, Tag2}:name)
EXAMPLE:Func( {Tag1, Tag2}:name = 7); // EXAMPLE_NUM_DEF( ,,{Tag1, Tag2}:name,7)
EXAMPLE:Func(const {Tag1, Tag2}:name ); // EXAMPLE_NUM (const ,,{Tag1, Tag2}:name)
EXAMPLE:Func(const {Tag1, Tag2}:name = 7); // EXAMPLE_NUM_DEF(const ,,{Tag1, Tag2}:name,7)
AKA NUM_TAG
Detects standard variables with optional tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM_TAG:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2)%8$
EXAMPLE:Func( name ); // EXAMPLE_NUM(, ,name )
EXAMPLE:Func( Tag:name ); // EXAMPLE_NUM(, Tag:,name )
EXAMPLE:Func( name = 7); // EXAMPLE_NUM(, ,name = 7)
EXAMPLE:Func( Tag:name = 7); // EXAMPLE_NUM(, Tag:,name = 7)
EXAMPLE:Func(const name ); // EXAMPLE_NUM(,const ,name )
EXAMPLE:Func(const Tag:name ); // EXAMPLE_NUM(,const Tag:,name )
EXAMPLE:Func(const name = 7); // EXAMPLE_NUM(,const ,name = 7)
EXAMPLE:Func(const Tag:name = 7); // EXAMPLE_NUM(,const Tag:,name = 7)
EXAMPLE:Func( {Tag1, Tag2}:name ); // EXAMPLE_NUM(, {Tag1, Tag2}:,name )
EXAMPLE:Func( {Tag1, Tag2}:name = 7); // EXAMPLE_NUM(, {Tag1, Tag2}:,name = 7)
EXAMPLE:Func(const {Tag1, Tag2}:name ); // EXAMPLE_NUM(,const {Tag1, Tag2}:,name )
EXAMPLE:Func(const {Tag1, Tag2}:name = 7); // EXAMPLE_NUM(,const {Tag1, Tag2}:,name = 7)
AKA NUM_CST_TAG
Detects standard variables with optional const
s and tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM_CST_TAG:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2)%8$
EXAMPLE:Func( name ); // EXAMPLE_NUM( , ,name )
EXAMPLE:Func( Tag:name ); // EXAMPLE_NUM( , Tag:,name )
EXAMPLE:Func( name = 7); // EXAMPLE_NUM( , ,name = 7)
EXAMPLE:Func( Tag:name = 7); // EXAMPLE_NUM( , Tag:,name = 7)
EXAMPLE:Func(const name ); // EXAMPLE_NUM(const , ,name )
EXAMPLE:Func(const Tag:name ); // EXAMPLE_NUM(const , Tag:,name )
EXAMPLE:Func(const name = 7); // EXAMPLE_NUM(const , ,name = 7)
EXAMPLE:Func(const Tag:name = 7); // EXAMPLE_NUM(const , Tag:,name = 7)
EXAMPLE:Func( {Tag1, Tag2}:name ); // EXAMPLE_NUM( ,{Tag1, Tag2}:,name )
EXAMPLE:Func( {Tag1, Tag2}:name = 7); // EXAMPLE_NUM( ,{Tag1, Tag2}:,name = 7)
EXAMPLE:Func(const {Tag1, Tag2}:name ); // EXAMPLE_NUM(const ,{Tag1, Tag2}:,name )
EXAMPLE:Func(const {Tag1, Tag2}:name = 7); // EXAMPLE_NUM(const ,{Tag1, Tag2}:,name = 7)
AKA NUM_DEF_TAG
Detects standard variables with optional default values and tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM_DEF_TAG:)(%0(%1))
#define EXAMPLE_NUM(%0,(%1,%3),%2)%8$
#define EXAMPLE_NUM_DEF(%0,%1,%2,%4)%8$
EXAMPLE:Func( name ); // EXAMPLE_NUM (, ,name)
EXAMPLE:Func( Tag:name ); // EXAMPLE_NUM (, Tag:,name)
EXAMPLE:Func( name = 7); // EXAMPLE_NUM_DEF(, ,name,7)
EXAMPLE:Func( Tag:name = 7); // EXAMPLE_NUM_DEF(, Tag:,name,7)
EXAMPLE:Func(const name ); // EXAMPLE_NUM (,const ,name)
EXAMPLE:Func(const Tag:name ); // EXAMPLE_NUM (,const Tag:,name)
EXAMPLE:Func(const name = 7); // EXAMPLE_NUM_DEF(,const ,name,7)
EXAMPLE:Func(const Tag:name = 7); // EXAMPLE_NUM_DEF(,const Tag:,name,7)
EXAMPLE:Func( {Tag1, Tag2}:name ); // EXAMPLE_NUM (, {Tag1, Tag2}:,name)
EXAMPLE:Func( {Tag1, Tag2}:name = 7); // EXAMPLE_NUM_DEF(, {Tag1, Tag2}:,name,7)
EXAMPLE:Func(const {Tag1, Tag2}:name ); // EXAMPLE_NUM (,const {Tag1, Tag2}:,name)
EXAMPLE:Func(const {Tag1, Tag2}:name = 7); // EXAMPLE_NUM_DEF(,const {Tag1, Tag2}:,name,7)
AKA NUM_CST_DEF_TAG
Detects standard variables with optional const
s, default values, and tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM_CST_DEF_TAG:)(%0(%1))
#define EXAMPLE_NUM_DEF(%0,%1,%2,%4)%8$
EXAMPLE:Func( name ); // EXAMPLE_NUM ( , ,name)
EXAMPLE:Func( Tag:name ); // EXAMPLE_NUM ( , Tag:,name)
EXAMPLE:Func( name = 7); // EXAMPLE_NUM_DEF( , ,name,7)
EXAMPLE:Func( Tag:name = 7); // EXAMPLE_NUM_DEF( , Tag:,name,7)
EXAMPLE:Func(const name ); // EXAMPLE_NUM (const , ,name)
EXAMPLE:Func(const Tag:name ); // EXAMPLE_NUM (const , Tag:,name)
EXAMPLE:Func(const name = 7); // EXAMPLE_NUM_DEF(const , ,name,7)
EXAMPLE:Func(const Tag:name = 7); // EXAMPLE_NUM_DEF(const , Tag:,name,7)
EXAMPLE:Func( {Tag1, Tag2}:name ); // EXAMPLE_NUM ( ,{Tag1, Tag2}:,name)
EXAMPLE:Func( {Tag1, Tag2}:name = 7); // EXAMPLE_NUM_DEF( ,{Tag1, Tag2}:,name,7)
EXAMPLE:Func(const {Tag1, Tag2}:name ); // EXAMPLE_NUM (const ,{Tag1, Tag2}:,name)
EXAMPLE:Func(const {Tag1, Tag2}:name = 7); // EXAMPLE_NUM_DEF(const ,{Tag1, Tag2}:,name,7)
AKA NUM_GRP
Detects standard variables with optional multiple tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM_GRP:)(%0(%1))
#define EXAMPLE_NUM(%0,(%1,%3),%2)%8$
EXAMPLE:Func( name ); // EXAMPLE_NUM(,( , ),name )
EXAMPLE:Func( Tag:name ); // EXAMPLE_NUM(,( Tag:, Tag:),name )
EXAMPLE:Func( name = 7); // EXAMPLE_NUM(,( , ),name = 7)
EXAMPLE:Func( Tag:name = 7); // EXAMPLE_NUM(,( Tag:, Tag:),name = 7)
EXAMPLE:Func(const name ); // ERROR
EXAMPLE:Func(const Tag:name ); // ERROR
EXAMPLE:Func(const name = 7); // ERROR
EXAMPLE:Func(const Tag:name = 7); // ERROR
EXAMPLE:Func( {Tag1, Tag2}:name ); // EXAMPLE_NUM(,(Tag1:,{Tag1, Tag2}:),name )
EXAMPLE:Func( {Tag1, Tag2}:name = 7); // EXAMPLE_NUM(,(Tag1:,{Tag1, Tag2}:),name = 7)
EXAMPLE:Func(const {Tag1, Tag2}:name ); // ERROR
EXAMPLE:Func(const {Tag1, Tag2}:name = 7); // ERROR
AKA NUM_CST_GRP
Detects standard variables with optional const
s and multiple tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM_CST_GRP:)(%0(%1))
#define EXAMPLE_NUM(%0,(%1,%3),%2)%8$
EXAMPLE:Func( name ); // EXAMPLE_NUM( ,( , ),name )
EXAMPLE:Func( Tag:name ); // EXAMPLE_NUM( ,( Tag:, Tag:),name )
EXAMPLE:Func( name = 7); // EXAMPLE_NUM( ,( , ),name = 7)
EXAMPLE:Func( Tag:name = 7); // EXAMPLE_NUM( ,( Tag:, Tag:),name = 7)
EXAMPLE:Func(const name ); // EXAMPLE_NUM(const ,( , ),name )
EXAMPLE:Func(const Tag:name ); // EXAMPLE_NUM(const ,( Tag:, Tag:),name )
EXAMPLE:Func(const name = 7); // EXAMPLE_NUM(const ,( , ),name = 7)
EXAMPLE:Func(const Tag:name = 7); // EXAMPLE_NUM(const ,( Tag:, Tag:),name = 7)
EXAMPLE:Func( {Tag1, Tag2}:name ); // EXAMPLE_NUM( ,(Tag1:, {Tag1, Tag2}:),name )
EXAMPLE:Func( {Tag1, Tag2}:name = 7); // EXAMPLE_NUM( ,(Tag1:, {Tag1, Tag2}:),name = 7)
EXAMPLE:Func(const {Tag1, Tag2}:name ); // EXAMPLE_NUM(const ,(Tag1:, {Tag1, Tag2}:),name )
EXAMPLE:Func(const {Tag1, Tag2}:name = 7); // EXAMPLE_NUM(const ,(Tag1:, {Tag1, Tag2}:),name = 7)
AKA NUM_DEF_GRP
Detects standard variables with optional default values and multiple tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM_DEF_GRP:)(%0(%1))
#define EXAMPLE_NUM(%0,(%1,%3),%2)%8$
#define EXAMPLE_NUM_DEF(%0,(%1,%3),%2,%4)%8$
EXAMPLE:Func( name ); // EXAMPLE_NUM (,( , ),name)
EXAMPLE:Func( Tag:name ); // EXAMPLE_NUM (,( Tag:, Tag:),name)
EXAMPLE:Func( name = 7); // EXAMPLE_NUM_DEF(,( , ),name,7)
EXAMPLE:Func( Tag:name = 7); // EXAMPLE_NUM_DEF(,( Tag:, Tag:),name,7)
EXAMPLE:Func(const name ); // ERROR
EXAMPLE:Func(const Tag:name ); // ERROR
EXAMPLE:Func(const name = 7); // ERROR
EXAMPLE:Func(const Tag:name = 7); // ERROR
EXAMPLE:Func( {Tag1, Tag2}:name ); // EXAMPLE_NUM (,(Tag1:, {Tag1, Tag2}:),name)
EXAMPLE:Func( {Tag1, Tag2}:name = 7); // EXAMPLE_NUM_DEF(,(Tag1:, {Tag1, Tag2}:),name,7)
EXAMPLE:Func(const {Tag1, Tag2}:name ); // ERROR
EXAMPLE:Func(const {Tag1, Tag2}:name = 7); // ERROR
AKA NUM_CST_DEF_GRP
Detects standard variables with optional const
s, default values, and multiple tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM_CST_DEF_GRP:)(%0(%1))
#define EXAMPLE_NUM(%0,(%1,%3),%2)%8$
#define EXAMPLE_NUM_DEF(%0,(%1,%3),%2,%4)%8$
EXAMPLE:Func( name ); // EXAMPLE_NUM ( ,( , ),name)
EXAMPLE:Func( Tag:name ); // EXAMPLE_NUM ( ,( Tag:, Tag:),name)
EXAMPLE:Func( name = 7); // EXAMPLE_NUM_DEF( ,( , ),name,7)
EXAMPLE:Func( Tag:name = 7); // EXAMPLE_NUM_DEF( ,( Tag:, Tag:),name,7)
EXAMPLE:Func(const name ); // EXAMPLE_NUM (const ,( , ),name)
EXAMPLE:Func(const Tag:name ); // EXAMPLE_NUM (const ,( Tag:, Tag:),name)
EXAMPLE:Func(const name = 7); // EXAMPLE_NUM_DEF(const ,( , ),name,7)
EXAMPLE:Func(const Tag:name = 7); // EXAMPLE_NUM_DEF(const ,( Tag:, Tag:),name,7)
EXAMPLE:Func( {Tag1, Tag2}:name ); // EXAMPLE_NUM ( ,(Tag1:, {Tag1, Tag2}:),name)
EXAMPLE:Func( {Tag1, Tag2}:name = 7); // EXAMPLE_NUM_DEF( ,(Tag1:, {Tag1, Tag2}:),name,7)
EXAMPLE:Func(const {Tag1, Tag2}:name ); // EXAMPLE_NUM (const ,(Tag1:, {Tag1, Tag2}:),name)
EXAMPLE:Func(const {Tag1, Tag2}:name = 7); // EXAMPLE_NUM_DEF(const ,(Tag1:, {Tag1, Tag2}:),name,7)
AKA REF
Detects references.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,REF:)(%0(%1))
#define EXAMPLE_REF(%0,%1,%2)%8$
EXAMPLE:Func(& name ); // EXAMPLE_REF(,, name )
EXAMPLE:Func(& Tag:name ); // EXAMPLE_REF(,, Tag:name )
EXAMPLE:Func(& name = 7); // EXAMPLE_REF(,, name = 7)
EXAMPLE:Func(& Tag:name = 7); // EXAMPLE_REF(,, Tag:name = 7)
EXAMPLE:Func(&{Tag1, Tag2}:name ); // EXAMPLE_REF(,,{Tag1, Tag2}:name )
EXAMPLE:Func(&{Tag1, Tag2}:name = 7); // EXAMPLE_REF(,,{Tag1, Tag2}:name = 7)
AKA REF_DEF
Detects references with optional default values.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,REF_DEF:)(%0(%1))
#define EXAMPLE_REF(%0,%1,%2,%4)%8$
#define EXAMPLE_REF_DEF(%0,%1,%2,%4)%8$
EXAMPLE:Func(& name ); // EXAMPLE_REF (,, name)
EXAMPLE:Func(& Tag:name ); // EXAMPLE_REF (,, Tag:name)
EXAMPLE:Func(& name = 7); // EXAMPLE_REF_DEF(,, name,7)
EXAMPLE:Func(& Tag:name = 7); // EXAMPLE_REF_DEF(,, Tag:name,7)
EXAMPLE:Func(&{Tag1, Tag2}:name ); // EXAMPLE_REF (,,{Tag1, Tag2}:name)
EXAMPLE:Func(&{Tag1, Tag2}:name = 7); // EXAMPLE_REF_DEF(,,{Tag1, Tag2}:name,7)
AKA REF_TAG
Detects references with optional tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,REF_TAG:)(%0(%1))
#define EXAMPLE_REF(%0,%1,%2)%8$
EXAMPLE:Func(& name ); // EXAMPLE_REF(, ,name )
EXAMPLE:Func(& Tag:name ); // EXAMPLE_REF(, Tag:,name )
EXAMPLE:Func(& name = 7); // EXAMPLE_REF(, ,name = 7)
EXAMPLE:Func(& Tag:name = 7); // EXAMPLE_REF(, Tag:,name = 7)
EXAMPLE:Func(&{Tag1, Tag2}:name ); // EXAMPLE_REF(,{Tag1, Tag2}:,name )
EXAMPLE:Func(&{Tag1, Tag2}:name = 7); // EXAMPLE_REF(,{Tag1, Tag2}:,name = 7)
AKA REF_DEF_TAG
Detects references with optional default values and tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,REF_DEF_TAG:)(%0(%1))
#define EXAMPLE_REF(%0,(%1,%3),%2)%8$
#define EXAMPLE_REF_DEF(%0,%1,%2,%4)%8$
EXAMPLE:Func(& name ); // EXAMPLE_REF (, ,name)
EXAMPLE:Func(& Tag:name ); // EXAMPLE_REF (, Tag:,name)
EXAMPLE:Func(& name = 7); // EXAMPLE_REF_DEF(, ,name,7)
EXAMPLE:Func(& Tag:name = 7); // EXAMPLE_REF_DEF(, Tag:,name,7)
EXAMPLE:Func(&{Tag1, Tag2}:name ); // EXAMPLE_REF (,{Tag1, Tag2}:,name)
EXAMPLE:Func(&{Tag1, Tag2}:name = 7); // EXAMPLE_REF_DEF(,{Tag1, Tag2}:,name,7)
AKA REF_GRP
Detects references with optional multiple tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,REF_GRP:)(%0(%1))
#define EXAMPLE_REF(%0,(%1,%3),%2)%8$
EXAMPLE:Func(& name ); // EXAMPLE_REF(,( , ),name )
EXAMPLE:Func(& Tag:name ); // EXAMPLE_REF(,( Tag:, Tag:),name )
EXAMPLE:Func(& name = 7); // EXAMPLE_REF(,( , ),name = 7)
EXAMPLE:Func(& Tag:name = 7); // EXAMPLE_REF(,( Tag:, Tag:),name = 7)
EXAMPLE:Func(&{Tag1, Tag2}:name ); // EXAMPLE_REF(,(Tag1:,{Tag1, Tag2}:),name )
EXAMPLE:Func(&{Tag1, Tag2}:name = 7); // EXAMPLE_REF(,(Tag1:,{Tag1, Tag2}:),name = 7)
AKA REF_DEF_GRP
Detects references with optional default values and multiple tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,REF_DEF_GRP:)(%0(%1))
#define EXAMPLE_REF(%0,(%1,%3),%2)%8$
#define EXAMPLE_REF_DEF(%0,(%1,%3),%2,%4)%8$
EXAMPLE:Func(& name ); // EXAMPLE_REF (,( , ),name)
EXAMPLE:Func(& Tag:name ); // EXAMPLE_REF (,( Tag:, Tag:),name)
EXAMPLE:Func(& name = 7); // EXAMPLE_REF_DEF(,( , ),name,7)
EXAMPLE:Func(& Tag:name = 7); // EXAMPLE_REF_DEF(,( Tag:, Tag:),name,7)
EXAMPLE:Func(&{Tag1, Tag2}:name ); // EXAMPLE_REF (,(Tag1:, {Tag1, Tag2}:),name)
EXAMPLE:Func(&{Tag1, Tag2}:name = 7); // EXAMPLE_REF_DEF(,(Tag1:, {Tag1, Tag2}:),name,7)
AKA STR
Detects strings (string:
only).
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,STR:)(%0(%1))
#define EXAMPLE_STR(%0,%1,%2,%3)%8$
EXAMPLE:Func( string:name[ ] ); // EXAMPLE_STR(,, name , )
EXAMPLE:Func( string:name[32] ); // EXAMPLE_STR(,, name ,32)
EXAMPLE:Func( string:name[ ] = "hi"); // EXAMPLE_STR(,, name = "hi", )
EXAMPLE:Func( string:name[32] = "hi"); // EXAMPLE_STR(,, name = "hi",32)
EXAMPLE:Func(const string:name[ ] ); // EXAMPLE_STR(,,const name , )
EXAMPLE:Func(const string:name[32] ); // EXAMPLE_STR(,,const name ,32)
EXAMPLE:Func(const string:name[ ] = "hi"); // EXAMPLE_STR(,,const name = "hi", )
EXAMPLE:Func(const string:name[32] = "hi"); // EXAMPLE_STR(,,const name = "hi",32)
AKA STR_CST
Detects strings (string:
only) with optional const
s.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,STR_CST:)(%0(%1))
#define EXAMPLE_STR(%0,%1,%2,%3)%8$
EXAMPLE:Func( string:name[ ] ); // EXAMPLE_STR( ,,name , )
EXAMPLE:Func( string:name[32] ); // EXAMPLE_STR( ,,name ,32)
EXAMPLE:Func( string:name[ ] = "hi"); // EXAMPLE_STR( ,,name = "hi", )
EXAMPLE:Func( string:name[32] = "hi"); // EXAMPLE_STR( ,,name = "hi",32)
EXAMPLE:Func(const string:name[ ] ); // EXAMPLE_STR(const ,,name , )
EXAMPLE:Func(const string:name[32] ); // EXAMPLE_STR(const ,,name ,32)
EXAMPLE:Func(const string:name[ ] = "hi"); // EXAMPLE_STR(const ,,name = "hi", )
EXAMPLE:Func(const string:name[32] = "hi"); // EXAMPLE_STR(const ,,name = "hi",32)
AKA STR_DEF
Detects strings (string:
only) with optional default values.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,STR_DEF:)(%0(%1))
#define EXAMPLE_STR(%0,%1,%2,%3)%8$
#define EXAMPLE_STR_DEF(%0,%1,%2,%3,%4)%8$
EXAMPLE:Func( string:name[ ] ); // EXAMPLE_STR (,, name, , )
EXAMPLE:Func( string:name[32] ); // EXAMPLE_STR (,, name,32, )
EXAMPLE:Func( string:name[ ] = "hi"); // EXAMPLE_STR_DEF(,, name, ,"hi")
EXAMPLE:Func( string:name[32] = "hi"); // EXAMPLE_STR_DEF(,, name,32,"hi")
EXAMPLE:Func(const string:name[ ] ); // EXAMPLE_STR (,,const name, , )
EXAMPLE:Func(const string:name[32] ); // EXAMPLE_STR (,,const name,32, )
EXAMPLE:Func(const string:name[ ] = "hi"); // EXAMPLE_STR_DEF(,,const name, ,"hi")
EXAMPLE:Func(const string:name[32] = "hi"); // EXAMPLE_STR_DEF(,,const name,32,"hi")
AKA STR_CST_DEF
Detects strings (string:
only) with optional const
s and default values.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,STR_CST_DEF:)(%0(%1))
#define EXAMPLE_STR(%0,%1,%2,%3)%8$
#define EXAMPLE_STR_DEF(%0,%1,%2,%3,%4)%8$
EXAMPLE:Func( string:name[ ] ); // EXAMPLE_STR ( ,,name, , )
EXAMPLE:Func( string:name[32] ); // EXAMPLE_STR ( ,,name,32, )
EXAMPLE:Func( string:name[ ] = "hi"); // EXAMPLE_STR_DEF( ,,name, ,"hi")
EXAMPLE:Func( string:name[32] = "hi"); // EXAMPLE_STR_DEF( ,,name,32,"hi")
EXAMPLE:Func(const string:name[ ] ); // EXAMPLE_STR (const ,,name, , )
EXAMPLE:Func(const string:name[32] ); // EXAMPLE_STR (const ,,name,32, )
EXAMPLE:Func(const string:name[ ] = "hi"); // EXAMPLE_STR_DEF(const ,,name, ,"hi")
EXAMPLE:Func(const string:name[32] = "hi"); // EXAMPLE_STR_DEF(const ,,name,32,"hi")
AKA EXT
Detects varargs.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,EXT:)(%0(%1))
#define EXAMPLE_EXT(%0,%1,%2)%8$
EXAMPLE:Func( ...); // EXAMPLE_EXT(,, )
EXAMPLE:Func( Tag:...); // EXAMPLE_EXT(,, Tag:)
EXAMPLE:Func({Tag1, Tag2}:...); // EXAMPLE_EXT(,,{Tag1, Tag2}:)
AKA EXT_TAG
Detects varargs with optional tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,EXT_TAG:)(%0(%1))
#define EXAMPLE_EXT(%0,%1,%2)%8$
EXAMPLE:Func( ...); // EXAMPLE_EXT(, ,)
EXAMPLE:Func( Tag:...); // EXAMPLE_EXT(, Tag:,)
EXAMPLE:Func({Tag1, Tag2}:...); // EXAMPLE_EXT(,{Tag1, Tag2}:,)
AKA EXT_GRP
Detects varargs with optional multiple tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,EXT_GRP:)(%0(%1))
#define EXAMPLE_EXT(%0,(%1,%3),%2)%8$
EXAMPLE:Func( ...); // EXAMPLE_EXT(,( , ),)
EXAMPLE:Func( Tag:...); // EXAMPLE_EXT(,( Tag:, Tag:),)
EXAMPLE:Func({Tag1, Tag2}:...); // EXAMPLE_EXT(,(Tag1:,{Tag1, Tag2}:),)
AKA ARR
Detects 1d arrays.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,ARR:)(%0(%1))
#define EXAMPLE_ARR(%0,%1,%2,%4)%8$
EXAMPLE:Func( name[42]); // EXAMPLE_ARR(,, name,42)
EXAMPLE:Func( Tag:name[42]); // EXAMPLE_ARR(,, Tag:name,42)
EXAMPLE:Func(const name[42]); // EXAMPLE_ARR(,,const name,42)
EXAMPLE:Func(const Tag:name[42]); // EXAMPLE_ARR(,,const Tag:name,42)
EXAMPLE:Func( {Tag1, Tag2}:name[42]); // EXAMPLE_ARR(,, {Tag1, Tag2}:name,42)
EXAMPLE:Func(const {Tag1, Tag2}:name[42]); // EXAMPLE_ARR(,,const {Tag1, Tag2}:name,42)
EXAMPLE:Func( name[ ]); // EXAMPLE_ARR(,, name, )
EXAMPLE:Func( Tag:name[ ]); // EXAMPLE_ARR(,, Tag:name, )
EXAMPLE:Func(const name[ ]); // EXAMPLE_ARR(,,const name, )
EXAMPLE:Func(const Tag:name[ ]); // EXAMPLE_ARR(,,const Tag:name, )
EXAMPLE:Func( {Tag1, Tag2}:name[ ]); // EXAMPLE_ARR(,, {Tag1, Tag2}:name, )
EXAMPLE:Func(const {Tag1, Tag2}:name[ ]); // EXAMPLE_ARR(,,const {Tag1, Tag2}:name, )
AKA ARR_CST
Detects 1d arrays with optional const
s.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,ARR_CST:)(%0(%1))
#define EXAMPLE_ARR(%0,%1,%2,%4)%8$
EXAMPLE:Func( name[42]); // EXAMPLE_ARR( ,, name,42)
EXAMPLE:Func( Tag:name[42]); // EXAMPLE_ARR( ,, Tag:name,42)
EXAMPLE:Func(const name[42]); // EXAMPLE_ARR(const ,, name,42)
EXAMPLE:Func(const Tag:name[42]); // EXAMPLE_ARR(const ,, Tag:name,42)
EXAMPLE:Func( {Tag1, Tag2}:name[42]); // EXAMPLE_ARR( ,,{Tag1, Tag2}:name,42)
EXAMPLE:Func(const {Tag1, Tag2}:name[42]); // EXAMPLE_ARR(const ,,{Tag1, Tag2}:name,42)
EXAMPLE:Func( name[ ]); // EXAMPLE_ARR( ,, name, )
EXAMPLE:Func( Tag:name[ ]); // EXAMPLE_ARR( ,, Tag:name, )
EXAMPLE:Func(const name[ ]); // EXAMPLE_ARR(const ,, name, )
EXAMPLE:Func(const Tag:name[ ]); // EXAMPLE_ARR(const ,, Tag:name, )
EXAMPLE:Func( {Tag1, Tag2}:name[ ]); // EXAMPLE_ARR( ,,{Tag1, Tag2}:name, )
EXAMPLE:Func(const {Tag1, Tag2}:name[ ]); // EXAMPLE_ARR(const ,,{Tag1, Tag2}:name, )
AKA ARR_TAG
Detects 1d arrays with optional tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,ARR_TAG:)(%0(%1))
#define EXAMPLE_ARR(%0,%1,%2,%4)%8$
EXAMPLE:Func( name[42]); // EXAMPLE_ARR(, ,name,42)
EXAMPLE:Func( Tag:name[42]); // EXAMPLE_ARR(, Tag:,name,42)
EXAMPLE:Func(const name[42]); // EXAMPLE_ARR(,const ,name,42)
EXAMPLE:Func(const Tag:name[42]); // EXAMPLE_ARR(,const Tag:,name,42)
EXAMPLE:Func( {Tag1, Tag2}:name[42]); // EXAMPLE_ARR(, {Tag1, Tag2}:,name,42)
EXAMPLE:Func(const {Tag1, Tag2}:name[42]); // EXAMPLE_ARR(,const {Tag1, Tag2}:,name,42)
EXAMPLE:Func( name[ ]); // EXAMPLE_ARR(, ,name, )
EXAMPLE:Func( Tag:name[ ]); // EXAMPLE_ARR(, Tag:,name, )
EXAMPLE:Func(const name[ ]); // EXAMPLE_ARR(,const ,name, )
EXAMPLE:Func(const Tag:name[ ]); // EXAMPLE_ARR(,const Tag:,name, )
EXAMPLE:Func( {Tag1, Tag2}:name[ ]); // EXAMPLE_ARR(, {Tag1, Tag2}:,name, )
EXAMPLE:Func(const {Tag1, Tag2}:name[ ]); // EXAMPLE_ARR(,const {Tag1, Tag2}:,name, )
AKA ARR_CST_TAG
Detects 1d arrays with optional const
s tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,ARR_CST_TAG:)(%0(%1))
#define EXAMPLE_ARR(%0,%1,%2,%4)%8$
EXAMPLE:Func( name[42]); // EXAMPLE_ARR( , ,name,42)
EXAMPLE:Func( Tag:name[42]); // EXAMPLE_ARR( , Tag:,name,42)
EXAMPLE:Func(const name[42]); // EXAMPLE_ARR(const , ,name,42)
EXAMPLE:Func(const Tag:name[42]); // EXAMPLE_ARR(const , Tag:,name,42)
EXAMPLE:Func( {Tag1, Tag2}:name[42]); // EXAMPLE_ARR( ,{Tag1, Tag2}:,name,42)
EXAMPLE:Func(const {Tag1, Tag2}:name[42]); // EXAMPLE_ARR(const ,{Tag1, Tag2}:,name,42)
EXAMPLE:Func( name[ ]); // EXAMPLE_ARR( , ,name, )
EXAMPLE:Func( Tag:name[ ]); // EXAMPLE_ARR( , Tag:,name, )
EXAMPLE:Func(const name[ ]); // EXAMPLE_ARR(const , ,name, )
EXAMPLE:Func(const Tag:name[ ]); // EXAMPLE_ARR(const , Tag:,name, )
EXAMPLE:Func( {Tag1, Tag2}:name[ ]); // EXAMPLE_ARR( ,{Tag1, Tag2}:,name, )
EXAMPLE:Func(const {Tag1, Tag2}:name[ ]); // EXAMPLE_ARR(const ,{Tag1, Tag2}:,name, )
AKA ARR_GRP
Detects 1d arrays with optional multiple tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,ARR_GRP:)(%0(%1))
#define EXAMPLE_ARR(%0,(%1,%3),%2,%4)%8$
EXAMPLE:Func( name[42]); // EXAMPLE_ARR(,( , ),name,42)
EXAMPLE:Func( Tag:name[42]); // EXAMPLE_ARR(,( Tag:, Tag:),name,42)
EXAMPLE:Func(const name[42]); // ERROR
EXAMPLE:Func(const Tag:name[42]); // ERROR
EXAMPLE:Func( {Tag1, Tag2}:name[42]); // EXAMPLE_ARR(,(Tag1:,{Tag1, Tag2}:),name,42)
EXAMPLE:Func(const {Tag1, Tag2}:name[42]); // ERROR
EXAMPLE:Func( name[ ]); // EXAMPLE_ARR(,( , ),name, )
EXAMPLE:Func( Tag:name[ ]); // EXAMPLE_ARR(,( Tag:, Tag:),name, )
EXAMPLE:Func(const name[ ]); // ERROR
EXAMPLE:Func(const Tag:name[ ]); // ERROR
EXAMPLE:Func( {Tag1, Tag2}:name[ ]); // EXAMPLE_ARR(,(Tag1:,{Tag1, Tag2}:),name, )
EXAMPLE:Func(const {Tag1, Tag2}:name[ ]); // ERROR
AKA ARR_CST_GRP
Detects 1d arrays with optional const
s and multiple tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,ARR_CST_GRP:)(%0(%1))
#define EXAMPLE_ARR(%0,(%1,%3),%2,%4)%8$
EXAMPLE:Func( name[42]); // EXAMPLE_ARR( ,( , ),name,42)
EXAMPLE:Func( Tag:name[42]); // EXAMPLE_ARR( ,( Tag:, Tag:),name,42)
EXAMPLE:Func(const name[42]); // EXAMPLE_ARR(const ,( , ),name,42)
EXAMPLE:Func(const Tag:name[42]); // EXAMPLE_ARR(const ,( Tag:, Tag:),name,42)
EXAMPLE:Func( {Tag1, Tag2}:name[42]); // EXAMPLE_ARR( ,(Tag1:, {Tag1, Tag2}:),name,42)
EXAMPLE:Func(const {Tag1, Tag2}:name[42]); // EXAMPLE_ARR(const ,(Tag1:, {Tag1, Tag2}:),name,42)
EXAMPLE:Func( name[ ]); // EXAMPLE_ARR( ,( , ),name, )
EXAMPLE:Func( Tag:name[ ]); // EXAMPLE_ARR( ,( Tag:, Tag:),name, )
EXAMPLE:Func(const name[ ]); // EXAMPLE_ARR(const ,( , ),name, )
EXAMPLE:Func(const Tag:name[ ]); // EXAMPLE_ARR(const ,( Tag:, Tag:),name, )
EXAMPLE:Func( {Tag1, Tag2}:name[ ]); // EXAMPLE_ARR( ,(Tag1:, {Tag1, Tag2}:),name, )
EXAMPLE:Func(const {Tag1, Tag2}:name[ ]); // EXAMPLE_ARR(const ,(Tag1:, {Tag1, Tag2}:),name, )
AKA ARR_MUL
Detects multi-dimensional arrays.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,ARR_MUL:)(%0(%1))
#define EXAMPLE_ARR_ARR(%0,%1,%2,%4,%5)%8$
EXAMPLE:Func( name[42][11]); // EXAMPLE_ARR_ARR(,, name,42,11)
EXAMPLE:Func( Tag:name[42][11]); // EXAMPLE_ARR_ARR(,, Tag:name,42,11)
EXAMPLE:Func(const name[42][11]); // EXAMPLE_ARR_ARR(,,const name,42,11)
EXAMPLE:Func(const Tag:name[42][ ]); // EXAMPLE_ARR_ARR(,,const Tag:name,42, )
EXAMPLE:Func( {Tag1, Tag2}:name[42][ ]); // EXAMPLE_ARR_ARR(,, {Tag1, Tag2}:name,42, )
EXAMPLE:Func(const {Tag1, Tag2}:name[42][ ]); // EXAMPLE_ARR_ARR(,,const {Tag1, Tag2}:name,42, )
EXAMPLE:Func( name[ ][11]); // EXAMPLE_ARR_ARR(,, name, ,11)
EXAMPLE:Func( Tag:name[ ][11]); // EXAMPLE_ARR_ARR(,, Tag:name, ,11)
EXAMPLE:Func(const name[ ][11]); // EXAMPLE_ARR_ARR(,,const name, ,11)
EXAMPLE:Func(const Tag:name[ ][ ]); // EXAMPLE_ARR_ARR(,,const Tag:name, , )
EXAMPLE:Func( {Tag1, Tag2}:name[ ][ ]); // EXAMPLE_ARR_ARR(,, {Tag1, Tag2}:name, , )
EXAMPLE:Func(const {Tag1, Tag2}:name[ ][ ]); // EXAMPLE_ARR_ARR(,,const {Tag1, Tag2}:name, , )
#define EXAMPLE_ARR_ARR_ARR(%0,%1,%2,%4,%5,%6)%8$
EXAMPLE:Func( name[42][11][ 90]); // EXAMPLE_ARR_ARR_ARR(,, name,42,11,90 )
EXAMPLE:Func( Tag:name[42][11][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR(,, Tag:name,42,11,MY_ENUM)
EXAMPLE:Func(const name[42][11][ ]); // EXAMPLE_ARR_ARR_ARR(,,const name,42,11, )
EXAMPLE:Func(const Tag:name[42][ ][ 90]); // EXAMPLE_ARR_ARR_ARR(,,const Tag:name,42, ,90 )
EXAMPLE:Func( {Tag1, Tag2}:name[42][ ][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR(,, {Tag1, Tag2}:name,42, ,MY_ENUM)
EXAMPLE:Func(const {Tag1, Tag2}:name[42][ ][ ]); // EXAMPLE_ARR_ARR_ARR(,,const {Tag1, Tag2}:name,42, , )
EXAMPLE:Func( name[ ][11][ 90]); // EXAMPLE_ARR_ARR_ARR(,, name, ,11,90 )
EXAMPLE:Func( Tag:name[ ][11][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR(,, Tag:name, ,11,MY_ENUM)
EXAMPLE:Func(const name[ ][11][ ]); // EXAMPLE_ARR_ARR_ARR(,,const name, ,11, )
EXAMPLE:Func(const Tag:name[ ][ ][ 90]); // EXAMPLE_ARR_ARR_ARR(,,const Tag:name, , ,90 )
EXAMPLE:Func( {Tag1, Tag2}:name[ ][ ][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR(,, {Tag1, Tag2}:name, , ,MY_ENUM)
EXAMPLE:Func(const {Tag1, Tag2}:name[ ][ ][ ]); // EXAMPLE_ARR_ARR_ARR(,,const {Tag1, Tag2}:name, , , )
AKA ARR_MUL_CST
Detects multi-dimensional arrays with optional const
s.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,ARR_MUL_CST:)(%0(%1))
#define EXAMPLE_ARR_ARR(%0,%1,%2,%4,%5)%8$
EXAMPLE:Func( name[42][11]); // EXAMPLE_ARR_ARR( ,, name,42,11)
EXAMPLE:Func( Tag:name[42][11]); // EXAMPLE_ARR_ARR( ,, Tag:name,42,11)
EXAMPLE:Func(const name[42][11]); // EXAMPLE_ARR_ARR(const ,, name,42,11)
EXAMPLE:Func(const Tag:name[42][ ]); // EXAMPLE_ARR_ARR(const ,, Tag:name,42, )
EXAMPLE:Func( {Tag1, Tag2}:name[42][ ]); // EXAMPLE_ARR_ARR( ,,{Tag1, Tag2}:name,42, )
EXAMPLE:Func(const {Tag1, Tag2}:name[42][ ]); // EXAMPLE_ARR_ARR(const ,,{Tag1, Tag2}:name,42, )
EXAMPLE:Func( name[ ][11]); // EXAMPLE_ARR_ARR( ,, name, ,11)
EXAMPLE:Func( Tag:name[ ][11]); // EXAMPLE_ARR_ARR( ,, Tag:name, ,11)
EXAMPLE:Func(const name[ ][11]); // EXAMPLE_ARR_ARR(const ,, name, ,11)
EXAMPLE:Func(const Tag:name[ ][ ]); // EXAMPLE_ARR_ARR(const ,, Tag:name, , )
EXAMPLE:Func( {Tag1, Tag2}:name[ ][ ]); // EXAMPLE_ARR_ARR( ,,{Tag1, Tag2}:name, , )
EXAMPLE:Func(const {Tag1, Tag2}:name[ ][ ]); // EXAMPLE_ARR_ARR(const ,,{Tag1, Tag2}:name, , )
#define EXAMPLE_ARR_ARR_ARR(%0,%1,%2,%4,%5,%6)%8$
EXAMPLE:Func( name[42][11][ 90]); // EXAMPLE_ARR_ARR_ARR( ,, name,42,11,90 )
EXAMPLE:Func( Tag:name[42][11][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR( ,, Tag:name,42,11,MY_ENUM)
EXAMPLE:Func(const name[42][11][ ]); // EXAMPLE_ARR_ARR_ARR(const ,, name,42,11, )
EXAMPLE:Func(const Tag:name[42][ ][ 90]); // EXAMPLE_ARR_ARR_ARR(const ,, Tag:name,42, ,90 )
EXAMPLE:Func( {Tag1, Tag2}:name[42][ ][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR( ,,{Tag1, Tag2}:name,42, ,MY_ENUM)
EXAMPLE:Func(const {Tag1, Tag2}:name[42][ ][ ]); // EXAMPLE_ARR_ARR_ARR(const ,,{Tag1, Tag2}:name,42, , )
EXAMPLE:Func( name[ ][11][ 90]); // EXAMPLE_ARR_ARR_ARR( ,, name, ,11,90 )
EXAMPLE:Func( Tag:name[ ][11][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR( ,, Tag:name, ,11,MY_ENUM)
EXAMPLE:Func(const name[ ][11][ ]); // EXAMPLE_ARR_ARR_ARR(const ,, name, ,11, )
EXAMPLE:Func(const Tag:name[ ][ ][ 90]); // EXAMPLE_ARR_ARR_ARR(const ,, Tag:name, , ,90 )
EXAMPLE:Func( {Tag1, Tag2}:name[ ][ ][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR( ,,{Tag1, Tag2}:name, , ,MY_ENUM)
EXAMPLE:Func(const {Tag1, Tag2}:name[ ][ ][ ]); // EXAMPLE_ARR_ARR_ARR(const ,,{Tag1, Tag2}:name, , , )
AKA ARR_MUL_TAG
Detects multi-dimensional arrays with optional tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,ARR_MUL_TAG:)(%0(%1))
#define EXAMPLE_ARR_ARR(%0,%1,%2,%4,%5)%8$
EXAMPLE:Func( name[42][11]); // EXAMPLE_ARR_ARR(, ,name,42,11)
EXAMPLE:Func( Tag:name[42][11]); // EXAMPLE_ARR_ARR(, Tag:,name,42,11)
EXAMPLE:Func(const name[42][11]); // EXAMPLE_ARR_ARR(,const ,name,42,11)
EXAMPLE:Func(const Tag:name[42][ ]); // EXAMPLE_ARR_ARR(,const Tag:,name,42, )
EXAMPLE:Func( {Tag1, Tag2}:name[42][ ]); // EXAMPLE_ARR_ARR(, {Tag1, Tag2}:,name,42, )
EXAMPLE:Func(const {Tag1, Tag2}:name[42][ ]); // EXAMPLE_ARR_ARR(,const {Tag1, Tag2}:,name,42, )
EXAMPLE:Func( name[ ][11]); // EXAMPLE_ARR_ARR(, ,name, ,11)
EXAMPLE:Func( Tag:name[ ][11]); // EXAMPLE_ARR_ARR(, Tag:,name, ,11)
EXAMPLE:Func(const name[ ][11]); // EXAMPLE_ARR_ARR(,const ,name, ,11)
EXAMPLE:Func(const Tag:name[ ][ ]); // EXAMPLE_ARR_ARR(,const Tag:,name, , )
EXAMPLE:Func( {Tag1, Tag2}:name[ ][ ]); // EXAMPLE_ARR_ARR(, {Tag1, Tag2}:,name, , )
EXAMPLE:Func(const {Tag1, Tag2}:name[ ][ ]); // EXAMPLE_ARR_ARR(,const {Tag1, Tag2}:,name, , )
#define EXAMPLE_ARR_ARR_ARR(%0,%1,%2,%4,%5,%6)%8$
EXAMPLE:Func( name[42][11][ 90]); // EXAMPLE_ARR_ARR_ARR(, ,name,42,11,90 )
EXAMPLE:Func( Tag:name[42][11][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR(, Tag:,name,42,11,MY_ENUM)
EXAMPLE:Func(const name[42][11][ ]); // EXAMPLE_ARR_ARR_ARR(,const ,name,42,11, )
EXAMPLE:Func(const Tag:name[42][ ][ 90]); // EXAMPLE_ARR_ARR_ARR(,const Tag:,name,42, ,90 )
EXAMPLE:Func( {Tag1, Tag2}:name[42][ ][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR(, {Tag1, Tag2}:,name,42, ,MY_ENUM)
EXAMPLE:Func(const {Tag1, Tag2}:name[42][ ][ ]); // EXAMPLE_ARR_ARR_ARR(,const {Tag1, Tag2}:,name,42, , )
EXAMPLE:Func( name[ ][11][ 90]); // EXAMPLE_ARR_ARR_ARR(, ,name, ,11,90 )
EXAMPLE:Func( Tag:name[ ][11][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR(, Tag:,name, ,11,MY_ENUM)
EXAMPLE:Func(const name[ ][11][ ]); // EXAMPLE_ARR_ARR_ARR(,const ,name, ,11, )
EXAMPLE:Func(const Tag:name[ ][ ][ 90]); // EXAMPLE_ARR_ARR_ARR(,const Tag:,name, , ,90 )
EXAMPLE:Func( {Tag1, Tag2}:name[ ][ ][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR(, {Tag1, Tag2}:,name, , ,MY_ENUM)
EXAMPLE:Func(const {Tag1, Tag2}:name[ ][ ][ ]); // EXAMPLE_ARR_ARR_ARR(,const {Tag1, Tag2}:,name, , , )
AKA ARR_MUL_CST_TAG
Detects multi-dimensional arrays with optional const
s and tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,ARR_MUL_CST_TAG:)(%0(%1))
#define EXAMPLE_ARR_ARR(%0,%1,%2,%4,%5)%8$
EXAMPLE:Func( name[42][11]); // EXAMPLE_ARR_ARR( , ,name,42,11)
EXAMPLE:Func( Tag:name[42][11]); // EXAMPLE_ARR_ARR( , Tag:,name,42,11)
EXAMPLE:Func(const name[42][11]); // EXAMPLE_ARR_ARR(const , ,name,42,11)
EXAMPLE:Func(const Tag:name[42][ ]); // EXAMPLE_ARR_ARR(const , Tag:,name,42, )
EXAMPLE:Func( {Tag1, Tag2}:name[42][ ]); // EXAMPLE_ARR_ARR( ,{Tag1, Tag2}:,name,42, )
EXAMPLE:Func(const {Tag1, Tag2}:name[42][ ]); // EXAMPLE_ARR_ARR(const ,{Tag1, Tag2}:,name,42, )
EXAMPLE:Func( name[ ][11]); // EXAMPLE_ARR_ARR( , ,name, ,11)
EXAMPLE:Func( Tag:name[ ][11]); // EXAMPLE_ARR_ARR( , Tag:,name, ,11)
EXAMPLE:Func(const name[ ][11]); // EXAMPLE_ARR_ARR(const , ,name, ,11)
EXAMPLE:Func(const Tag:name[ ][ ]); // EXAMPLE_ARR_ARR(const , Tag:,name, , )
EXAMPLE:Func( {Tag1, Tag2}:name[ ][ ]); // EXAMPLE_ARR_ARR( ,{Tag1, Tag2}:,name, , )
EXAMPLE:Func(const {Tag1, Tag2}:name[ ][ ]); // EXAMPLE_ARR_ARR(const ,{Tag1, Tag2}:,name, , )
#define EXAMPLE_ARR_ARR_ARR(%0,%1,%2,%4,%5,%6)%8$
EXAMPLE:Func( name[42][11][ 90]); // EXAMPLE_ARR_ARR_ARR( , ,name,42,11,90 )
EXAMPLE:Func( Tag:name[42][11][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR( , Tag:,name,42,11,MY_ENUM)
EXAMPLE:Func(const name[42][11][ ]); // EXAMPLE_ARR_ARR_ARR(const , ,name,42,11, )
EXAMPLE:Func(const Tag:name[42][ ][ 90]); // EXAMPLE_ARR_ARR_ARR(const , Tag:,name,42, ,90 )
EXAMPLE:Func( {Tag1, Tag2}:name[42][ ][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR( ,{Tag1, Tag2}:,name,42, ,MY_ENUM)
EXAMPLE:Func(const {Tag1, Tag2}:name[42][ ][ ]); // EXAMPLE_ARR_ARR_ARR(const ,{Tag1, Tag2}:,name,42, , )
EXAMPLE:Func( name[ ][11][ 90]); // EXAMPLE_ARR_ARR_ARR( , ,name, ,11,90 )
EXAMPLE:Func( Tag:name[ ][11][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR( , Tag:,name, ,11,MY_ENUM)
EXAMPLE:Func(const name[ ][11][ ]); // EXAMPLE_ARR_ARR_ARR(const , ,name, ,11, )
EXAMPLE:Func(const Tag:name[ ][ ][ 90]); // EXAMPLE_ARR_ARR_ARR(const , Tag:,name, , ,90 )
EXAMPLE:Func( {Tag1, Tag2}:name[ ][ ][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR( ,{Tag1, Tag2}:,name, , ,MY_ENUM)
EXAMPLE:Func(const {Tag1, Tag2}:name[ ][ ][ ]); // EXAMPLE_ARR_ARR_ARR(const ,{Tag1, Tag2}:,name, , , )
AKA ARR_MUL_GRP
Detects multi-dimensional arrays with optional multiple tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,ARR_MUL_GRP:)(%0(%1))
#define EXAMPLE_ARR_ARR(%0,(%1,%3),%2,%4,%5)%8$
EXAMPLE:Func( name[42][11]); // EXAMPLE_ARR_ARR(,( , ),name,42,11)
EXAMPLE:Func( Tag:name[42][11]); // EXAMPLE_ARR_ARR(,( Tag:, Tag:),name,42,11)
EXAMPLE:Func(const name[42][11]); // ERROR
EXAMPLE:Func(const Tag:name[42][ ]); // ERROR
EXAMPLE:Func( {Tag1, Tag2}:name[42][ ]); // EXAMPLE_ARR_ARR(,(Tag1:,{Tag1, Tag2}:),name,42, )
EXAMPLE:Func(const {Tag1, Tag2}:name[42][ ]); // ERROR
EXAMPLE:Func( name[ ][11]); // EXAMPLE_ARR_ARR(,( , ),name, ,11)
EXAMPLE:Func( Tag:name[ ][11]); // EXAMPLE_ARR_ARR(,( Tag:, Tag:),name, ,11)
EXAMPLE:Func(const name[ ][11]); // ERROR
EXAMPLE:Func(const Tag:name[ ][ ]); // ERROR
EXAMPLE:Func( {Tag1, Tag2}:name[ ][ ]); // EXAMPLE_ARR_ARR(,(Tag1:,{Tag1, Tag2}:),name, , )
EXAMPLE:Func(const {Tag1, Tag2}:name[ ][ ]); // ERROR
#define EXAMPLE_ARR_ARR_ARR(%0,(%1,%3),%2,%4,%5,%6)%8$
EXAMPLE:Func( name[42][11][ 90]); // EXAMPLE_ARR_ARR_ARR(,( , ),name,42,11,90 )
EXAMPLE:Func( Tag:name[42][11][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR(,( Tag:, Tag:),name,42,11,MY_ENUM)
EXAMPLE:Func(const name[42][11][ ]); // ERROR
EXAMPLE:Func(const Tag:name[42][ ][ 90]); // ERROR
EXAMPLE:Func( {Tag1, Tag2}:name[42][ ][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR(,(Tag1:,{Tag1, Tag2}:),name,42, ,MY_ENUM)
EXAMPLE:Func(const {Tag1, Tag2}:name[42][ ][ ]); // ERROR
EXAMPLE:Func( name[ ][11][ 90]); // EXAMPLE_ARR_ARR_ARR(,( , ),name, ,11,90 )
EXAMPLE:Func( Tag:name[ ][11][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR(,( Tag:, Tag:),name, ,11,MY_ENUM)
EXAMPLE:Func(const name[ ][11][ ]); // ERROR
EXAMPLE:Func(const Tag:name[ ][ ][ 90]); // ERROR
EXAMPLE:Func( {Tag1, Tag2}:name[ ][ ][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR(,(Tag1:,{Tag1, Tag2}:),name, , ,MY_ENUM)
EXAMPLE:Func(const {Tag1, Tag2}:name[ ][ ][ ]); // ERROR
AKA ARR_MUL_CST_GRP
Detects multi-dimensional arrays with optional const
s and multiple tags.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,ARR_CST_GRP:)(%0(%1))
#define EXAMPLE_ARR_ARR(%0,(%1,%3),%2,%4,%5)%8$
EXAMPLE:Func( name[42][11]); // EXAMPLE_ARR_ARR( ,( , ),name,42,11)
EXAMPLE:Func( Tag:name[42][11]); // EXAMPLE_ARR_ARR( ,( Tag:, Tag:),name,42,11)
EXAMPLE:Func(const name[42][11]); // EXAMPLE_ARR_ARR(const ,( , ),name,42,11)
EXAMPLE:Func(const Tag:name[42][ ]); // EXAMPLE_ARR_ARR(const ,( Tag:, Tag:),name,42, )
EXAMPLE:Func( {Tag1, Tag2}:name[42][ ]); // EXAMPLE_ARR_ARR( ,(Tag1:, {Tag1, Tag2}:),name,42, )
EXAMPLE:Func(const {Tag1, Tag2}:name[42][ ]); // EXAMPLE_ARR_ARR(const ,(Tag1:, {Tag1, Tag2}:),name,42, )
EXAMPLE:Func( name[ ][11]); // EXAMPLE_ARR_ARR( ,( , ),name, ,11)
EXAMPLE:Func( Tag:name[ ][11]); // EXAMPLE_ARR_ARR( ,( Tag:, Tag:),name, ,11)
EXAMPLE:Func(const name[ ][11]); // EXAMPLE_ARR_ARR(const ,( , ),name, ,11)
EXAMPLE:Func(const Tag:name[ ][ ]); // EXAMPLE_ARR_ARR(const ,( Tag:, Tag:),name, , )
EXAMPLE:Func( {Tag1, Tag2}:name[ ][ ]); // EXAMPLE_ARR_ARR( ,(Tag1:, {Tag1, Tag2}:),name, , )
EXAMPLE:Func(const {Tag1, Tag2}:name[ ][ ]); // EXAMPLE_ARR_ARR(const ,(Tag1:, {Tag1, Tag2}:),name, , )
#define EXAMPLE_ARR_ARR_ARR(%0,(%1,%3),%2,%4,%5,%6)%8$
EXAMPLE:Func( name[42][11][ 90]); // EXAMPLE_ARR_ARR_ARR( ,( , ),name,42,11,90 )
EXAMPLE:Func( Tag:name[42][11][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR( ,( Tag:, Tag:),name,42,11,MY_ENUM)
EXAMPLE:Func(const name[42][11][ ]); // EXAMPLE_ARR_ARR_ARR(const ,( , ),name,42,11, )
EXAMPLE:Func(const Tag:name[42][ ][ 90]); // EXAMPLE_ARR_ARR_ARR(const ,( Tag:, Tag:),name,42, ,90 )
EXAMPLE:Func( {Tag1, Tag2}:name[42][ ][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR( ,(Tag1:, {Tag1, Tag2}:),name,42, ,MY_ENUM)
EXAMPLE:Func(const {Tag1, Tag2}:name[42][ ][ ]); // EXAMPLE_ARR_ARR_ARR(const ,(Tag1:, {Tag1, Tag2}:),name,42, , )
EXAMPLE:Func( name[ ][11][ 90]); // EXAMPLE_ARR_ARR_ARR( ,( , ),name, ,11,90 )
EXAMPLE:Func( Tag:name[ ][11][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR( ,( Tag:, Tag:),name, ,11,MY_ENUM)
EXAMPLE:Func(const name[ ][11][ ]); // EXAMPLE_ARR_ARR_ARR(const ,( , ),name, ,11, )
EXAMPLE:Func(const Tag:name[ ][ ][ 90]); // EXAMPLE_ARR_ARR_ARR(const ,( Tag:, Tag:),name, , ,90 )
EXAMPLE:Func( {Tag1, Tag2}:name[ ][ ][MY_ENUM]); // EXAMPLE_ARR_ARR_ARR( ,(Tag1:, {Tag1, Tag2}:),name, , ,MY_ENUM)
EXAMPLE:Func(const {Tag1, Tag2}:name[ ][ ][ ]); // EXAMPLE_ARR_ARR_ARR(const ,(Tag1:, {Tag1, Tag2}:),name, , , )
AKA LEN
Enforces length variables appearing after arrays.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,ARR:NUM:LEN:)(%0(%1))
#define EXAMPLE_ARR(%0,%1,%2,%4)%8$
#define EXAMPLE_NUM(%0,%1,%2)%8$
EXAMPLE:Func( length); // EXAMPLE_NUM(,,length)
EXAMPLE:Func(array[], length); // EXAMPLE_ARR(,,array,) EXAMPLE_NUM(,,length)
EXAMPLE:Func(array[] ); // ERROR
AKA SPC
Detects special arrays (Type:name<size>
s).
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,SPC:)(%0(%1))
#define EXAMPLE_SPC(%0,%1,%2,%4)%8$
EXAMPLE:Func( Type:name< >); // EXAMPLE_SPC(,Type:, name, )
EXAMPLE:Func( Type:name<10>); // EXAMPLE_SPC(,Type:, name,10)
EXAMPLE:Func(const Type:name< >); // EXAMPLE_SPC(,Type:,const name, )
EXAMPLE:Func(const Type:name<10>); // EXAMPLE_SPC(,Type:,const name,10)
AKA SPC_CST
Detects special arrays (Type:name<size>
s) with optional const
s.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,SPC_CST:)(%0(%1))
#define EXAMPLE_SPC(%0,%1,%2,%4)%8$
EXAMPLE:Func( Type:name< >); // EXAMPLE_SPC( ,Type:,name, )
EXAMPLE:Func( Type:name<10>); // EXAMPLE_SPC( ,Type:,name,10)
EXAMPLE:Func(const Type:name< >); // EXAMPLE_SPC(const ,Type:,name, )
EXAMPLE:Func(const Type:name<10>); // EXAMPLE_SPC(const ,Type:,name,10)
Called for completion after all parameters have been parsed.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2)%8$
#define EXAMPLE_END(%0)%8$
EXAMPLE: Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END( Func)
EXAMPLE: void:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END( void:Func)
EXAMPLE: Float:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END( Float:Func)
EXAMPLE:string:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END(string:Func)
Called for completion when there are no parameters.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2)%8$
#define EXAMPLE_NUL(%0)%8$
EXAMPLE: Func(); // EXAMPLE_NUL( Func)
EXAMPLE: void:Func(); // EXAMPLE_NUL( void:Func)
EXAMPLE: Float:Func(); // EXAMPLE_NUL( Float:Func)
EXAMPLE:string:Func(); // EXAMPLE_NUL(string:Func)
Called for completion after all parameters have been parsed, with an optional tagged return.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM:RET_TAG:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2)%8$
#define EXAMPLE_END(%0)%8$
#define EXAMPLE_END_TAG(%0,%1)%8$
EXAMPLE: Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END ( Func)
EXAMPLE: void:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END_TAG( void:,Func)
EXAMPLE: Float:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END_TAG( Float:,Func)
EXAMPLE:string:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END_TAG(string:,Func)
Called for completion when there are no parameters, with an optional tagged return.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM:RET_TAG:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2)%8$
#define EXAMPLE_NUL(%0)%8$
#define EXAMPLE_NUL_TAG(%0,%1)%8$
EXAMPLE: Func(); // EXAMPLE_NUL ( Func)
EXAMPLE: void:Func(); // EXAMPLE_NUL_TAG( void:,Func)
EXAMPLE: Float:Func(); // EXAMPLE_NUL_TAG( Float:,Func)
EXAMPLE:string:Func(); // EXAMPLE_NUL_TAG(string:,Func)
Called for completion after all parameters have been parsed, with an optional void (missing) return.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM:RET_VOD:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2)%8$
#define EXAMPLE_END(%0)%8$
#define EXAMPLE_END_VOD(%0)%8$
EXAMPLE: Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END ( Func)
EXAMPLE: void:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END_VOD( Func)
EXAMPLE: Float:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END ( Float:Func)
EXAMPLE:string:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END (string:Func)
Called for completion when there are no parameters, with an optional void (missing) return.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM:RET_VOD:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2)%8$
#define EXAMPLE_NUL(%0)%8$
#define EXAMPLE_NUL_VOD(%0)%8$
EXAMPLE: Func(); // EXAMPLE_NUL ( Func)
EXAMPLE: void:Func(); // EXAMPLE_NUL_VOD( Func)
EXAMPLE: Float:Func(); // EXAMPLE_NUL ( Float:Func)
EXAMPLE:string:Func(); // EXAMPLE_NUL (string:Func)
Called for completion after all parameters have been parsed, with an optional string return.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM:RET_STR:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2)%8$
#define EXAMPLE_END(%0)%8$
#define EXAMPLE_END_STR(%0)%8$
EXAMPLE: Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END ( Func)
EXAMPLE: void:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END ( void:Func)
EXAMPLE: Float:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END (Float:Func)
EXAMPLE:string:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END_STR( Func)
Called for completion when there are no parameters, with an optional string return.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM:RET_STR:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2)%8$
#define EXAMPLE_NUL(%0)%8$
#define EXAMPLE_NUL_STR(%0)%8$
EXAMPLE: Func(); // EXAMPLE_NUL ( Func)
EXAMPLE: void:Func(); // EXAMPLE_NUL ( void:Func)
EXAMPLE: Float:Func(); // EXAMPLE_NUL (Float:Func)
EXAMPLE:string:Func(); // EXAMPLE_NUL_STR( Func)
Called for completion after all parameters have been parsed, with an optional tagged return or void (missing) return.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM:RET_TAG_VOD:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2)%8$
#define EXAMPLE_END(%0)%8$
#define EXAMPLE_END_TAG(%0,%1)%8$
#define EXAMPLE_END_VOD(%0)%8$
EXAMPLE: Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END ( Func)
EXAMPLE: void:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END_VOD( Func)
EXAMPLE: Float:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END_TAG( Float:,Func)
EXAMPLE:string:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END_TAG(string:,Func)
Called for completion when there are no parameters, with an optional tagged return or void (missing) return.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM:RET_TAG_VOD:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2)%8$
#define EXAMPLE_NUL(%0)%8$
#define EXAMPLE_NUL_TAG(%0,%1)%8$
#define EXAMPLE_NUL_VOD(%0)%8$
EXAMPLE: Func(); // EXAMPLE_NUL ( Func)
EXAMPLE: void:Func(); // EXAMPLE_NUL_VOD( Func)
EXAMPLE: Float:Func(); // EXAMPLE_NUL_TAG( Float:,Func)
EXAMPLE:string:Func(); // EXAMPLE_NUL_TAG(string:,Func)
Called for completion after all parameters have been parsed, with an optional void (missing) return or string return.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM:RET_VOD_STR:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2)%8$
#define EXAMPLE_END(%0)%8$
#define EXAMPLE_END_VOD(%0)%8$
#define EXAMPLE_END_STR(%0)%8$
EXAMPLE: Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END ( Func)
EXAMPLE: void:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END_VOD( Func)
EXAMPLE: Float:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END ( Float:Func)
EXAMPLE:string:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END_STR( Func)
Called for completion when there are no parameters, with an optional void (missing) return or string return.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM:RET_VOD_STR:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2)%8$
#define EXAMPLE_NUL(%0)%8$
#define EXAMPLE_NUL_VOD(%0)%8$
#define EXAMPLE_NUL_STR(%0)%8$
EXAMPLE: Func(); // EXAMPLE_NUL ( Func)
EXAMPLE: void:Func(); // EXAMPLE_NUL_VOD( Func)
EXAMPLE: Float:Func(); // EXAMPLE_NUL ( Float:Func)
EXAMPLE:string:Func(); // EXAMPLE_NUL_STR( Func)
Called for completion after all parameters have been parsed, with an optional tagged return or string return.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM:RET_TAG_STR:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2)%8$
#define EXAMPLE_END(%0)%8$
#define EXAMPLE_END_TAG(%0,%1)%8$
#define EXAMPLE_END_STR(%0)%8$
EXAMPLE: Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END ( Func)
EXAMPLE: void:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END_TAG( void:,Func)
EXAMPLE: Float:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END_TAG(Float:,Func)
EXAMPLE:string:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END_STR( Func)
Called for completion when there are no parameters, with an optional tagged return or string return.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM:RET_TAG_STR:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2)%8$
#define EXAMPLE_NUL(%0)%8$
#define EXAMPLE_NUL_TAG(%0,%1)%8$
#define EXAMPLE_NUL_STR(%0)%8$
EXAMPLE: Func(); // EXAMPLE_NUL ( Func)
EXAMPLE: void:Func(); // EXAMPLE_NUL_TAG( void:,Func)
EXAMPLE: Float:Func(); // EXAMPLE_NUL_TAG(Float:,Func)
EXAMPLE:string:Func(); // EXAMPLE_NUL_STR( Func)
Called for completion after all parameters have been parsed; with an optional string return, tagged return, or void (missing) return.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM:RET_TAG_VOD_STR:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2)%8$
#define EXAMPLE_END(%0)%8$
#define EXAMPLE_END_TAG(%0,%1)%8$
#define EXAMPLE_END_STR(%0)%8$
#define EXAMPLE_END_VOD(%0)%8$
EXAMPLE: Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END ( Func)
EXAMPLE: void:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END_VOD( Func)
EXAMPLE: Float:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END_TAG(Float:,Func)
EXAMPLE:string:Func(var); // EXAMPLE_NUM(,,var) EXAMPLE_END_STR( Func)
Called for completion when there are no parameters; with an optional string return, tagged return, or void (missing) return.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM:RET_TAG_VOD_STR:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2)%8$
#define EXAMPLE_NUL(%0)%8$
#define EXAMPLE_NUL_TAG(%0,%1)%8$
#define EXAMPLE_NUL_STR(%0)%8$
#define EXAMPLE_NUL_VOD(%0)%8$
EXAMPLE: Func(); // EXAMPLE_NUL ( Func)
EXAMPLE: void:Func(); // EXAMPLE_NUL_VOD( Func)
EXAMPLE: Float:Func(); // EXAMPLE_NUL_TAG(Float:,Func)
EXAMPLE:string:Func(); // EXAMPLE_NUL_STR( Func)
AKA QAL
Used to detect function qualifiers before endings are performed.
#define EXAMPLE:%0(%1) FUNC_PARSER(EXAMPLE,NUM:QAL:)(%0(%1))
#define EXAMPLE_NUM(%0,%1,%2)%8$
#define EXAMPLE_NUL(%0)%8$
#define EXAMPLE_stock()%8$
#define EXAMPLE_static()%8$
#define EXAMPLE_global()%8$
#define EXAMPLE_operator()%8$
EXAMPLE: Func(); // EXAMPLE_NUL(Func)
EXAMPLE:stock Func(); // EXAMPLE_stock() EXAMPLE_NUL(Func)
EXAMPLE:static stock Func(); // EXAMPLE_static() EXAMPLE_stock() EXAMPLE_NUL(Func)
EXAMPLE:global Func(); // EXAMPLE_global() EXAMPLE_NUL(Func)
EXAMPLE:operator !(num); // EXAMPLE_NUM(num) EXAMPLE_operator() EXAMPLE_END(!)