# code-parse.inc ## Contents * [Introduction](#introduction) * [Example 1 - Count Array Parameters](#example-1---count-array-parameters) * [Full Code](#full-code) * [Console Output](#console-output) * [Explanation](#explanation) * [Exclude Strings](#exclude-strings) * [Example 2 - Count All Parameters](#example-2---count-all-parameters) * [Example 3 - Count Array Parameters And Sum Their Size](#example-3---count-array-parameters-and-sum-their-size) * [Example 4 - Auto-Generate `CallRemoteFunction` Specifier Strings](#example-4---auto-generate-callremotefunction-specifier-strings) * [Three Facts](#three-facts) * [Tags](#tags) * [Example 5 - Output Input Exactly](#example-5---output-input-exactly) * [Lie 1](#lie-1) * [Lie 2](#lie-2) * [Output One Parameter](#output-one-parameter) * [Output Everything](#output-everything) * [Example 6 - Remotes With Alternate Return Types](#example-6---remotes-with-alternate-return-types) * [No Return](#no-return) * [Tag Return](#tag-return) * [String Return](#string-return) * [String Return Code Issues](#string-return-code-issues) * [Complete String Return Code](#complete-string-return-code) * [Use](#use-1) * [Example 7 - y_timers Clone](#example-7---y_timers-clone) * [Use](#use) * [LEN (LENGTH)](#len-length) * [QAL (QUALIFICATION)](#qal-qualification) * [SPC (SPECIAL)](#spc-special) * [GRP (TAGGROUP)](#grp-taggroup) * [Alternate Rebuild](#alternate-rebuild) * [API](#api) * [Example 8 - y_inline](#example-8---y_inline) * [PARSER_ISOLATE](#parser_isolate) * [Complete Parameter Reference](#complete-parameter-reference) * [NUMBER](#number) * [NUMBER_CONST](#number_const) * [NUMBER_DEFAULT](#number_default) * [NUMBER_CONST_DEFAULT](#number_const_default) * [NUMBER_TAG](#number_tag) * [NUMBER_CONST_TAG](#number_const_tag) * [NUMBER_DEFAULT_TAG](#number_default_tag) * [NUMBER_CONST_DEFAULT_TAG](#number_const_default_tag) * [NUMBER_TAGGROUP](#number_taggroup) * [NUMBER_CONST_TAGGROUP](#number_const_taggroup) * [NUMBER_DEFAULT_TAGGROUP](#number_default_taggroup) * [NUMBER_CONST_DEFAULT_TAGGROUP](#number_const_default_taggroup) * [REFERENCE](#reference) * [REFERENCE_DEFAULT](#reference_default) * [REFERENCE_TAG](#reference_tag) * [REFERENCE_DEFAULT_TAG](#reference_default_tag) * [REFERENCE_TAGGROUP](#reference_taggroup) * [REFERENCE_DEFAULT_TAGGROUP](#reference_default_taggroup) * [STRING](#string) * [STRING_CONST](#string_const) * [STRING_DEFAULT](#string_default) * [STRING_CONST_DEFAULT](#string_const_default) * [VARARG](#vararg) * [VARARG_TAG](#vararg_tag) * [VARARG_TAGGROUP](#vararg_taggroup) * [ARRAY](#array) * [ARRAY_CONST](#array_const) * [ARRAY_TAG](#array_tag) * [ARRAY_CONST_TAG](#array_const_tag) * [ARRAY_TAGGROUP](#array_taggroup) * [ARRAY_CONST_TAGGROUP](#array_const_taggroup) * [ARRAY_MULTI](#array_multi) * [ARRAY_MULTI_CONST](#array_multi_const) * [ARRAY_MULTI_TAG](#array_multi_tag) * [ARRAY_MULTI_CONST_TAG](#array_multi_const_tag) * [ARRAY_MULTI_TAGGROUP](#array_multi_taggroup) * [ARRAY_MULTI_CONST_TAGGROUP](#array_multi_const_taggroup) * [LENGTH](#length) * [SPECIAL](#special) * [SPECIAL_CONST](#special_const) * [Complete Return Reference](#complete-return-reference) * [_END](#_end) * [_NUL](#_nul) * [_END_TAG](#_end_tag) * [_NUL_TAG](#_nul_tag) * [_END_VOD](#_end_vod) * [_NUL_VOD](#_nul_vod) * [_END_STR](#_end_str) * [_NUL_STR](#_nul_str) * [_END_TAG_VOD](#_end_tag_vod) * [_NUL_TAG_VOD](#_nul_tag_vod) * [_END_VOD_STR](#_end_vod_str) * [_NUL_VOD_STR](#_nul_vod_str) * [_END_TAG_STR](#_end_tag_str) * [_NUL_TAG_STR](#_nul_tag_str) * [_END_TAG_VOD_STR](#_end_tag_vod_str) * [_NUL_TAG_VOD_STR](#_nul_tag_vod_str) * [QUALIFICATION](#qualification) ## Introduction 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. ## Example 1 - Count Array Parameters ### Full Code ```pawn // 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); } ``` ### Console Output ``` There are 3 array parameters to "my_test_function" ``` ### Explanation 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): ```pawn my_test_function(a, b[], c, const d[], &e = 6, string:f[] = "hi") ``` This is the code output (output): ```pawn 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: ```pawn stock const countOf_my_test_function = 0 + 1 + 1 + 1; ``` This starts out as: ```pawn 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 ```pawn #define ARRAY_COUNT:%1(%2) FUNC_PARSER(ARRAY_COUNT,ARR:NUM:)(%1(%2)) stock const countOf_%1 = 0; %1(%2) ``` ```pawn #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:`. ```pawn 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. ### Exclude Strings To modify the example so that strings are not included in the array count would look like: ```pawn #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): ```pawn #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). ```pawn #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. ```pawn #define ARRAY_COUNT_END(%9)%8$ %8$ ``` Called when the parsing is complete. ```pawn #define ARRAY_COUNT_NUL(%9)%8$ %8$ ``` Called when there are no function parameters. ## Example 2 - Count All 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. ```pawn // 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: ```pawn 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); } ``` ## Example 3 - Count Array Parameters And Sum Their Size 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: ```pawn #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: ```pawn const Float:pos[3] string:name[] = "Bob" &v Float:v = 0 ``` Would call as: ```pawn 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: ```pawn #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: ```pawn #define ARRAY_COUNT_ARR(%9,%9,%9,%4)%8$%0;%1; %8$%0 + 1;%1 + (%4 +0); ``` This makes the full thing: ```pawn // 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: ```pawn #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. ## Example 4 - Auto-Generate `CallRemoteFunction` Specifier Strings 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: ```pawn remote my_func(a, b[], c) { } ``` Will generate: ```pawn 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: ```pawn #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`: ```pawn #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: ```pawn #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: ```pawn #define REMOTE_END(%9)%8$ %8$ #define REMOTE_NUL(%9)%8$ %8$ ``` ### Three Facts 1. The `forward` keyword is optional. 2. A public function with only a semi-colon after it is a forward. 3. An `@` prefix declares a function public. We can thus shrink this code to: ```pawn #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: ```pawn 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. ### Tags 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: ```pawn #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. ## Example 5 - Output Input Exactly 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. ### Lie 1 Earlier I stated that: ```pawn const Float:pos[3] string:name[] = "Bob" &v Float:v = 0 ``` Gave: ```pawn 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: ```pawn 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: ```pawn const Float:pos[][3][MY_ENUM] ``` Becomes: ```pawn 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: ```pawn 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. ### Lie 2 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: ```pawn 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: ```pawn 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. ### Output One Parameter The code to output one parameter exactly as it came in would be: ```pawn #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: ```pawn #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] ``` ### Output Everything 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: ```pawn #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. ## Example 6 - Remotes With Alternate Return Types A reminder of the current `remote` macro: ```pawn #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: ```pawn #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. ### No Return 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`): ```pawn 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`: ```pawn #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): ```pawn #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: ```pawn #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. ### Tag Return A tag return is passed as an extra macro parameter. ```pawn 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: ```pawn 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$ ``` ### String Return At a basic level, string returns are handled the same as other return types: ```pawn 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: ```pawn 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: ```pawn 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: ```pawn #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: ```pawn #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: ```pawn 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: ```pawn #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): ```pawn #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: ```pawn #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: ```pawn #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 ``` ### String Return Code Issues The above code was spread out, and actually wrong. This: ```pawn #define underlying_%0\32; underlying_%0 ``` Will output: ```pawn 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: ```pawn (a, const b[], c = 11) (a, const b[], c) (a, b, c) ``` Most `remote` declarations can also act as their own `forward`: ```pawn 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. ### Complete String Return Code ```pawn #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 ``` ### Use ```pawn 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. ## Example 7 - y_timers Clone 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. ```pawn #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: ```pawn #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... ### Use ```pawn 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"); } ``` ## LEN (LENGTH) `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.** ```pawn #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: ```pawn #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: ```pawn #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: ```pawn #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: ```pawn #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: ```pawn #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: ```pawn #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. ## QAL (QUALIFICATION) 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`, `remoterunc`, `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: ```pawn #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: ```pawn timer stock my_timer[100]() { } ``` Will not be detected: ```pawn 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. ## SPC (SPECIAL) *Special* arrays are those declared through macros with `<>` instead of `[]`, e.g. iterators: ```pawn new Iterator: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: ```pawn #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: ```pawn MY_PARSER:func(Iterator:Vehicles) ``` will be interpreted as two invalid parameters - `Iterator:Vehicles` instead of what it should be. ## GRP (TAGGROUP) Tag groups are multiple tags assigned to the same variable, most frequently seen as: ```pawn Func1({_, Float}:...) { } ``` However, any variable can have any tag groups on them: ```pawn 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: ```pawn 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: ```pawn 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`: ```pawn #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: ```pawn #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: ```pawn #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. ### Alternate Rebuild An alternate version of the `REBUILD:` example using `_GRP` instead of `_TAG` and with many examples you can inspect using `-l` to compile: ```pawn #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); ``` ## API 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: ```pawn FUNC_PARSER(REBUILD,ARRAY_TAG_CONST_MULTI:NUMBER_CONST_TAG_DEFAULT:TAG_REFERENCE_DEFAULT:TAG_VARARG:DEFAULT_STRING_CONST)(func(params)) ``` In to this: ```pawn PARSER@FUNC:z@:l@:w@:x@a@:x@v@:x@r@:x@o@:x@(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: ```pawn #define void: #define string: #define u@$ 0]); #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). ## Example 8 - y_inline 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: ```pawn main() { inline InlineFunc(a, b[32], string:c[]) { // Code. } } ``` In to: ```pawn 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: ```pawn 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: ```pawn 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: ```pawn #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. ```pawn #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)). ```pawn #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. ## PARSER_ISOLATE This macro allows direct access to one internal part of the parser - the ability to detect a space immediately after a symbol. For example: ```pawn #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: ```pawn 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: ```pawn #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: ```pawn #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`: ```pawn #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. ```pawn // `%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: ```pawn 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. ## Complete Parameter Reference 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. ### NUMBER AKA **NUM** Detects standard variables. ```pawn #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) ``` ### NUMBER_CONST AKA **NUM_CST** Detects standard variables with optional `const`s. ```pawn #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) ``` ### NUMBER_DEFAULT AKA **NUM_DEF** Detects standard variables with optional default values. ```pawn #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) ``` ### NUMBER_CONST_DEFAULT AKA **NUM_CST_DEF** Detects standard variables with optional `const`s and default values. ```pawn #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) ``` ### NUMBER_TAG AKA **NUM_TAG** Detects standard variables with optional tags. ```pawn #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) ``` ### NUMBER_CONST_TAG AKA **NUM_CST_TAG** Detects standard variables with optional `const`s and tags. ```pawn #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) ``` ### NUMBER_DEFAULT_TAG AKA **NUM_DEF_TAG** Detects standard variables with optional default values and tags. ```pawn #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) ``` ### NUMBER_CONST_DEFAULT_TAG AKA **NUM_CST_DEF_TAG** Detects standard variables with optional `const`s, default values, and tags. ```pawn #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) ``` ### NUMBER_TAGGROUP AKA **NUM_GRP** Detects standard variables with optional multiple tags. ```pawn #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 ``` ### NUMBER_CONST_TAGGROUP AKA **NUM_CST_GRP** Detects standard variables with optional `const`s and multiple tags. ```pawn #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) ``` ### NUMBER_DEFAULT_TAGGROUP AKA **NUM_DEF_GRP** Detects standard variables with optional default values and multiple tags. ```pawn #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 ``` ### NUMBER_CONST_DEFAULT_TAGGROUP AKA **NUM_CST_DEF_GRP** Detects standard variables with optional `const`s, default values, and multiple tags. ```pawn #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) ``` ### REFERENCE AKA **REF** Detects references. ```pawn #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) ``` ### REFERENCE_DEFAULT AKA **REF_DEF** Detects references with optional default values. ```pawn #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) ``` ### REFERENCE_TAG AKA **REF_TAG** Detects references with optional tags. ```pawn #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) ``` ### REFERENCE_DEFAULT_TAG AKA **REF_DEF_TAG** Detects references with optional default values and tags. ```pawn #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) ``` ### REFERENCE_TAGGROUP AKA **REF_GRP** Detects references with optional multiple tags. ```pawn #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) ``` ### REFERENCE_DEFAULT_TAGGROUP AKA **REF_DEF_GRP** Detects references with optional default values and multiple tags. ```pawn #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) ``` ### STRING AKA **STR** Detects strings (`string:` only). ```pawn #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) ``` ### STRING_CONST AKA **STR_CST** Detects strings (`string:` only) with optional `const`s. ```pawn #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) ``` ### STRING_DEFAULT AKA **STR_DEF** Detects strings (`string:` only) with optional default values. ```pawn #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") ``` ### STRING_CONST_DEFAULT AKA **STR_CST_DEF** Detects strings (`string:` only) with optional `const`s and default values. ```pawn #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") ``` ### VARARG AKA **EXT** Detects varargs. ```pawn #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}:) ``` ### VARARG_TAG AKA **EXT_TAG** Detects varargs with optional tags. ```pawn #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}:,) ``` ### VARARG_TAGGROUP AKA **EXT_GRP** Detects varargs with optional multiple tags. ```pawn #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}:),) ``` ### ARRAY AKA **ARR** Detects 1d arrays. ```pawn #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, ) ``` ### ARRAY_CONST AKA **ARR_CST** Detects 1d arrays with optional `const`s. ```pawn #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, ) ``` ### ARRAY_TAG AKA **ARR_TAG** Detects 1d arrays with optional tags. ```pawn #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, ) ``` ### ARRAY_CONST_TAG AKA **ARR_CST_TAG** Detects 1d arrays with optional `const`s tags. ```pawn #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, ) ``` ### ARRAY_TAGGROUP AKA **ARR_GRP** Detects 1d arrays with optional multiple tags. ```pawn #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 ``` ### ARRAY_CONST_TAGGROUP AKA **ARR_CST_GRP** Detects 1d arrays with optional `const`s and multiple tags. ```pawn #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, ) ``` ### ARRAY_MULTI AKA **ARR_MUL** Detects multi-dimensional arrays. ```pawn #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, , , ) ``` ### ARRAY_MULTI_CONST AKA **ARR_MUL_CST** Detects multi-dimensional arrays with optional `const`s. ```pawn #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, , , ) ``` ### ARRAY_MULTI_TAG AKA **ARR_MUL_TAG** Detects multi-dimensional arrays with optional tags. ```pawn #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, , , ) ``` ### ARRAY_MULTI_CONST_TAG AKA **ARR_MUL_CST_TAG** Detects multi-dimensional arrays with optional `const`s and tags. ```pawn #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, , , ) ``` ### ARRAY_MULTI_TAGGROUP AKA **ARR_MUL_GRP** Detects multi-dimensional arrays with optional multiple tags. ```pawn #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 ``` ### ARRAY_MULTI_CONST_TAGGROUP AKA **ARR_MUL_CST_GRP** Detects multi-dimensional arrays with optional `const`s and multiple tags. ```pawn #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, , , ) ``` ## LENGTH AKA **LEN** Enforces length variables appearing after arrays. ```pawn #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 ``` ### SPECIAL AKA **SPC** Detects special arrays (`Type:name`s). ```pawn #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) ``` ### SPECIAL_CONST AKA **SPC_CST** Detects special arrays (`Type:name`s) with optional `const`s. ```pawn #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) ``` ## Complete Return Reference ### _END Called for completion after all parameters have been parsed. ```pawn #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) ``` ### _NUL Called for completion when there are no parameters. ```pawn #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) ``` ### _END_TAG Called for completion after all parameters have been parsed, with an optional tagged return. ```pawn #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) ``` ### _NUL_TAG Called for completion when there are no parameters, with an optional tagged return. ```pawn #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) ``` ### _END_VOD Called for completion after all parameters have been parsed, with an optional void (missing) return. ```pawn #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) ``` ### _NUL_VOD Called for completion when there are no parameters, with an optional void (missing) return. ```pawn #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) ``` ### _END_STR Called for completion after all parameters have been parsed, with an optional string return. ```pawn #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) ``` ### _NUL_STR Called for completion when there are no parameters, with an optional string return. ```pawn #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) ``` ### _END_TAG_VOD Called for completion after all parameters have been parsed, with an optional tagged return or void (missing) return. ```pawn #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) ``` ### _NUL_TAG_VOD Called for completion when there are no parameters, with an optional tagged return or void (missing) return. ```pawn #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) ``` ### _END_VOD_STR Called for completion after all parameters have been parsed, with an optional void (missing) return or string return. ```pawn #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) ``` ### _NUL_VOD_STR Called for completion when there are no parameters, with an optional void (missing) return or string return. ```pawn #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) ``` ### _END_TAG_STR Called for completion after all parameters have been parsed, with an optional tagged return or string return. ```pawn #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) ``` ### _NUL_TAG_STR Called for completion when there are no parameters, with an optional tagged return or string return. ```pawn #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) ``` ### _END_TAG_VOD_STR Called for completion after all parameters have been parsed; with an optional string return, tagged return, or void (missing) return. ```pawn #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) ``` ### _NUL_TAG_VOD_STR Called for completion when there are no parameters; with an optional string return, tagged return, or void (missing) return. ```pawn #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) ``` ### QUALIFICATION AKA **QAL** Used to detect function qualifiers before endings are performed. ```pawn #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(!) ```