PreProcessor Commands: Difference between revisions
m (Cleanup) |
m (Grammar, spacing, add use of codecomment formatting to reduce space.) |
||
Line 1: | Line 1: | ||
[[Category:Scripting Topics]] | [[Category:Scripting Topics]] | ||
The parser allows you to use macros in configs. Macros are a bit similar to functions in programming and allow you to use a single definition many times in the config, without having to duplicate the whole definition again and again. It also gives you a centralized place to correct errors in this definition. This page mainly | The parser allows you to use macros in configs. Macros are a bit similar to functions in programming and allow you to use a single definition many times in the config, without having to duplicate the whole definition again and again. It also gives you a centralized place to correct errors in this definition. This page mainly refers to OFP, some examples won't work for ARMA and ARMA 2.<br> | ||
{{Important|In ArmA 3, preprocessor commands are <b>case-sensitive!</b>}} | |||
== Parsing == | == Parsing == | ||
Line 13: | Line 14: | ||
=== Comments === | === Comments === | ||
A comment is a line | A comment is a line within code that is not actually processed by the game engine. They are used to make code more readable or to add notes for future reference. The preprocessor removes all comments from the file before it is processed. Therefore, comments are never actually "seen" by the game engine. | ||
Comments may span multiple lines, or only part of a line if needed. | |||
{{codecomment|//this is a single line comment}} | {{codecomment|//this is a single-line comment}} | ||
{{codecomment|/* this is a | |||
multi-line | |||
comment */}} | |||
mycode = something; {{codecomment|//only this part of the line is commented out}} | mycode = something; {{codecomment|//only this part of the line is commented out}} | ||
{{codecomment|/* this | |||
myArray = ["apple"{{codecomment|/*,"bananna*/}},"pear"]; {{codecomment|//a portion in the middle of this line is commented out}} | |||
=== #define === | === #define === | ||
Using the ''#define'' instruction you can define a keyword and assign a definition to it. | Using the ''#define'' instruction, you can define a keyword and assign a definition to it. As an example: | ||
#define true 1 | #define true 1 | ||
The above means that whenever | The above means that whenever ''true'' is used in a config, the parser will replace this with the value ''1''. | ||
==== Arguments ==== | ==== Arguments ==== | ||
You can add arguments to | You can add arguments to more complex macros, by including them between brackets after the keyword: | ||
#define CAR(NAME) displayName = NAME; | #define CAR(NAME) displayName = NAME; | ||
Line 46: | Line 51: | ||
Incorrect usage: | Incorrect usage: | ||
HINTARG([1,2,3,4,5,6,7,8,9,0]); //ERROR, | HINTARG([1,2,3,4,5,6,7,8,9,0]); //ERROR, won't even compile | ||
Correct usage: | Correct usage: | ||
Line 65: | Line 70: | ||
==== Multi-line ==== | ==== Multi-line ==== | ||
For longer definitions, you can stretch the macro across multiple lines. | For longer definitions, you can stretch the macro across multiple lines. To create a multi-line definition, each line except the last one should end with a ''\'' character: | ||
#define DRAWBUTTON(NAME)\ | #define DRAWBUTTON(NAME)\ | ||
Line 71: | Line 76: | ||
... | ... | ||
'''NOTE''': The backslash | '''NOTE''': The backslash must be the last character in a line when defining a multi-line macro. Any character (including spaces) after the backslash will cause issues. | ||
=== #undef === | === #undef === | ||
Line 79: | Line 84: | ||
=== #ifdef === | === #ifdef === | ||
You can use a simple if-then construction to | You can use a simple if-then construction to check whether a certain set of definitions has already been made: | ||
#ifdef NAME | #ifdef NAME | ||
...text that will be used if NAME is defined... | ...text that will be used if NAME is defined... | ||
#endif | #endif | ||
IFDEFs ''cannot'' be nested | IFDEFs ''cannot'' be nested. The preprocessor will generate errors for all inner definitions if the outer definition doesn't exist. | ||
Line 102: | Line 107: | ||
=== #endif === | === #endif === | ||
This ends a conditional block as shown in the descriptions of #ifdef and #ifndef above. | This ends a conditional block as shown in the descriptions of #ifdef and #ifndef above. | ||
=== #include === | === #include === | ||
Copies the code from a target file and pastes it where #include directive is. | Copies the code from a target file and pastes it where #include directive is. | ||
#include "file.hpp" | #include "file.hpp" | ||
#include <file.txt> {{codecomment |//Brackets are equivalent to quotation marks and may be used in their place.}} | |||
#include <file.txt> | |||
Source directory is: | Source directory is: | ||
Line 114: | Line 118: | ||
* When starting with \ - the internal filesystem root (see [[CMA:DevelopmentSetup#Addon_development|Addon_development]]) or the Game's working directory (only with [[Arma_3_Startup_Parameters#Developer_Options -filePatching]] enabled) | * When starting with \ - the internal filesystem root (see [[CMA:DevelopmentSetup#Addon_development|Addon_development]]) or the Game's working directory (only with [[Arma_3_Startup_Parameters#Developer_Options -filePatching]] enabled) | ||
You can | |||
You can define a path beginning with: | |||
* drive (only with [[Arma_3_Startup_Parameters#Developer_Options -filePatching]] enabled): | * drive (only with [[Arma_3_Startup_Parameters#Developer_Options -filePatching]] enabled): | ||
Line 121: | Line 126: | ||
* PBO with [[PBOPREFIX]]: | * PBO with [[PBOPREFIX]]: | ||
#include "\myMod\myAddon\file.txt" | #include "\myMod\myAddon\file.txt" | ||
* PBO (keep in mind that in this case ,if the PBO's file name will be changed ,all #include | |||
* PBO (keep in mind that in this case, if the PBO's file name will be changed, all '#include' referencing it will need to be updated) | |||
#include"\myMod\myAddon\file.txt" // Arma 3\@myMod\addons\myAddon.pbo\file.txt; | #include"\myMod\myAddon\file.txt" // Arma 3\@myMod\addons\myAddon.pbo\file.txt; | ||
To move to parent directory use '..' (two dots) (Supported in Arma 3 since v1.49.131707): | To move to parent directory use '..' (two dots) (Supported in Arma 3 since v1.49.131707): | ||
#include "..\file.sqf" | #include "..\file.sqf" | ||
Preprocessor does not support | |||
Preprocessor does not support the use of macros for pre-defined file names. | |||
#define path "codestrip.txt" | #define path "codestrip.txt" | ||
#include path | #include path {{codecomment|//this will cause an error}} | ||
=== # === | === # === | ||
Line 152: | Line 159: | ||
__EXEC(cat = 5 + 1; lev = 0) | __EXEC(cat = 5 + 1; lev = 0) | ||
__EXEC(string1 = "if ((_this select 0) == 22) then {true}") | This macro terminates at the first ')' it encounters, so the following will not be possible: | ||
__EXEC(string1 = "if ((_this select 0) == 22) then {true}") {{codecomment | //string1 returns "if ((_this select 0", which can cause unexpected results}} | |||
The variables that receive expression result inside __EXEC are available in [[parsingNamespace]]: | |||
_cat = [[parsingNamespace]] [[getVariable]] "cat"; //6 | _cat = [[parsingNamespace]] [[getVariable]] "cat"; //6 |
Revision as of 18:06, 8 August 2018
The parser allows you to use macros in configs. Macros are a bit similar to functions in programming and allow you to use a single definition many times in the config, without having to duplicate the whole definition again and again. It also gives you a centralized place to correct errors in this definition. This page mainly refers to OFP, some examples won't work for ARMA and ARMA 2.
Parsing
- Config.cpp - parsed when PBO is binarized.
- localize cannot be used in macros, as it would hardcode string of current language instead of creating reference.
- Description.ext - parsed when mission is loaded or previewed in missions list.
- SQF script - parsed when preprocessFile, preprocessFileLineNumbers or execVM is used.
Macros
Comments
A comment is a line within code that is not actually processed by the game engine. They are used to make code more readable or to add notes for future reference. The preprocessor removes all comments from the file before it is processed. Therefore, comments are never actually "seen" by the game engine.
Comments may span multiple lines, or only part of a line if needed.
//this is a single-line comment /* this is a multi-line comment */ mycode = something; //only this part of the line is commented out myArray = ["apple"/*,"bananna*/,"pear"]; //a portion in the middle of this line is commented out
#define
Using the #define instruction, you can define a keyword and assign a definition to it. As an example:
#define true 1
The above means that whenever true is used in a config, the parser will replace this with the value 1.
Arguments
You can add arguments to more complex macros, by including them between brackets after the keyword:
#define CAR(NAME) displayName = NAME;
If you now use CAR("Mini"), this will be replaced with displayName = "Mini";. Multiple arguments can also be used:
#define BLASTOFF(UNIT,RATE) UNIT setVelocity [0,0,RATE];
Passing arrays with more than one element [el1,el2,...] as arguments into macros as well as any argument containing comas "some, sentence", will need a small workaround:
#define HINTARG(ARG) hint ("Passed argument: " + str ARG)
Incorrect usage:
HINTARG([1,2,3,4,5,6,7,8,9,0]); //ERROR, won't even compile
Correct usage:
#define array1 [1,2,3,4,5,6,7,8,9,0] HINTARG(array1); //SUCCESS
Replacing parts of words
By default you can only replace whole words by arguments. If you need to replace only part of a word, you can use the ## instruction. This is necessary when either the start or the end of the argument connects to another character that is not a ; (semi-colon) or (space).
class NAME##_Button_Slider: RscText \ { \ model = \OFP2\Structures\Various\##FOLDER##\##FOLDER; \
You can also use the single # to convert an argument to a string.
statement = (this animate [#SEL, 0]); \
Multi-line
For longer definitions, you can stretch the macro across multiple lines. To create a multi-line definition, each line except the last one should end with a \ character:
#define DRAWBUTTON(NAME)\ __EXEC(idcNav = idcNav + 4) \ ...
NOTE: The backslash must be the last character in a line when defining a multi-line macro. Any character (including spaces) after the backslash will cause issues.
#undef
Undefine (delete) a macro previously set by the use of #define.
#undef NAME
#ifdef
You can use a simple if-then construction to check whether a certain set of definitions has already been made:
#ifdef NAME ...text that will be used if NAME is defined... #endif
IFDEFs cannot be nested. The preprocessor will generate errors for all inner definitions if the outer definition doesn't exist.
#ifndef
Same as #ifdef, but checks for absence of definiton instead.
#ifndef NAME ...text that will be used if NAME isn't defined... #endif
#else
#ifndef NAME ...text that will be used if NAME isn't defined... #else ...text that will be used if NAME is defined... #endif
#endif
This ends a conditional block as shown in the descriptions of #ifdef and #ifndef above.
#include
Copies the code from a target file and pastes it where #include directive is.
#include "file.hpp"
#include <file.txt> //Brackets are equivalent to quotation marks and may be used in their place.
Source directory is:
- for any file without starting the include path with \ - the file's current directory
- When starting with \ - the internal filesystem root (see Addon_development) or the Game's working directory (only with Arma_3_Startup_Parameters#Developer_Options -filePatching enabled)
You can define a path beginning with:
- drive (only with Arma_3_Startup_Parameters#Developer_Options -filePatching enabled):
#include "D:\file.txt"
- PBO with PBOPREFIX:
#include "\myMod\myAddon\file.txt"
- PBO (keep in mind that in this case, if the PBO's file name will be changed, all '#include' referencing it will need to be updated)
#include"\myMod\myAddon\file.txt" // Arma 3\@myMod\addons\myAddon.pbo\file.txt;
To move to parent directory use '..' (two dots) (Supported in Arma 3 since v1.49.131707):
#include "..\file.sqf"
Preprocessor does not support the use of macros for pre-defined file names.
#define path "codestrip.txt"
#include path //this will cause an error
#
'#' (single hash) operator wraps the text with quotation marks.
#define STRINGIFY(s) #s; #define FOO 123 test1 = STRINGIFY(123); //test1 = "123"; test2 = STRINGIFY(FOO); //test2 = "123";
##
'##' (double hash) operator concatenates what's before the ## with what's after it.
#define GLUE(g1,g2) g1##g2 #define FOO 123 #define BAR 456 test1 = GLUE(123,456); //test1 = 123456; test2 = GLUE(FOO,BAR); //test2 = 123456;
__EXEC
This config parser macro allows you to assign values to internal variables. These variables can be used to create complex macros with counters for example.
__EXEC(cat = 5 + 1; lev = 0)
This macro terminates at the first ')' it encounters, so the following will not be possible:
__EXEC(string1 = "if ((_this select 0) == 22) then {true}") //string1 returns "if ((_this select 0", which can cause unexpected results
The variables that receive expression result inside __EXEC are available in parsingNamespace:
_cat = parsingNamespace getVariable "cat"; //6 _lev = parsingNamespace getVariable "lev"; //0
NOTE: Config parser macros are not suitable for sqf/sqs scripts but can be used in configs, including description.ext.
__EVAL
With this config parser macro you can evaluate expressions, including previously assigned internal variables. Unlike with __EXEC, __EVAL supports multiple parentheses
w = __EVAL(safezoneW - (5 * ((1 / (getResolution select 2)) * 1.25 * 4)));
NOTE: Config parser macros are not suitable for sqf/sqs scripts but can be used in configs, including description.ext. Both global and local variables set in __EXEC are available in __EVAL.
__LINE__
This keyword gets replaced with the line number in the file where it is found. For example, if __LINE__ is found on the 10th line of a file, the word __LINE__ will be replaced with the number 10.
__FILE__
This keyword gets replaced with the CURRENT file being processed.