PreProcessor Commands: Difference between revisions
Killzone Kid (talk | contribs) (relative path support) |
Killzone Kid (talk | contribs) (→__EVAL: Variables set in __EXEC are available in __EVAL) |
||
Line 159: | Line 159: | ||
w = __EVAL(but_w / 10); | w = __EVAL(but_w / 10); | ||
This macro also terminates at the first '')'' it encounters. <br>'''NOTE:''' Config parser macros are not suitable for sqf/sqs scripts but can be used in configs, including [[description.ext]] | This macro also terminates at the first '')'' it encounters. <br>'''NOTE:''' Config parser macros are not suitable for sqf/sqs scripts but can be used in configs, including [[description.ext]]. Variables set in __EXEC are available in __EVAL. | ||
=== __LINE__ === | === __LINE__ === |
Revision as of 13:56, 15 August 2015
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 refer to OFP, some example don't work on 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 in your code that is not actually processed by the game engine. They are used to make your code more readable. The preprocessor removes all comments from the file, before it is processed. Therefore, any comments written in your code, will never actually be "seen" by the engine. They are for humans only.
There are two types of comments: single line comments and multi line comments.
//this is a single line comment mycode = something; //only this part of the line is commented out /* this is a multi line comment */
#define
Using the #define instruction you can define a keyword and assign a definition to it. An example:
#define true 1
The above means that whenever you use true in your config, the parser will replace this with the value 1.
Arguments
You can add arguments to your 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";.
#define BLASTOFF(UNIT,RATE) UNIT setVelocity [0,0,RATE];
Multiple arguments can also be used.
Passing arrays with more than one element as arguments into macros does not seem to be supported. To work around this issue, assign the array into a variable and then pass the variable into the macro. [1]
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. Each line, save the last one, ends with a space and \ character:
#define DRAWBUTTON(NAME) \ __EXEC(idcNav = idcNav + 4) \ ...
#undef
Undefine (delete) a macro previously set by the use of #define.
#undef NAME
#ifdef
You can use a simple if-then construction to for example 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, as the preprocessor will generate an error 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 "codestrip.hpp" #include <codestrip.txt>
Brackets are equal to quotation marks.
Source directory is:
- for description.ext, addon configs – game root folder (where exe file is)
- for global config and resource – their source folder
Alternatively you may write a path starting from drive:
#include "d:\temp\codestrip.txt"
To move to parent directory use '..' (two dots) (Supported in Arma 3 since v1.49.131707):
#include "..\codestrip.txt"
You can also include files from the installation dir:
#include "\myDirectory\codestrip.txt" // ArmA 2\myDirectory\codestrip.txt
Addon locations are saved to memory. To include a file from one of them write:
#include "<addon folder name>\<file>"
Preprocessor does not support computed includes (macro for file name).
#define path "codestrip.txt" #include path
This code will cause an error. Macros will be explained later.
#
'#' (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}")
When you evaluate string1 it returns "if ((_this select 0" and 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.
w = __EVAL(but_w / 10);
This macro also terminates at the first ) it encounters.
NOTE: Config parser macros are not suitable for sqf/sqs scripts but can be used in configs, including description.ext. 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.
External links
- ↑ "BI Forums post referencing array issue", also confirmed in Arma3 v1.38, using Arma3 Tools v0.82.0.5497, AddonBuilder v1.1.128872, )