SQF Syntax: Difference between revisions

From Bohemia Interactive Community
Jump to navigation Jump to search
m (Text replacement - "Operation Flashpoint: Resistance" to "[[{{ofpr}}]]")
(Remove Rules of Precedence (in Operators now))
Line 1: Line 1:
{{SideTOC}}
{{SideTOC}}
'''SQF''' stands for '''S'''tatus '''Q'''uo '''F'''unction - a successor of [[SQS_syntax|'''S'''tatus '''Q'''uo '''S'''cript]], which is deprecated since [[Armed Assault]] but could still be used in Arma 3. "Status Quo" was a code name for [https://en.wikipedia.org/wiki/Operation_Flashpoint Operation Flash Point], just like "Combined Arms" was a code name for [https://en.wikipedia.org/wiki/ARMA_(series) Arma] and "Futura" was a code name for [https://en.wikipedia.org/wiki/ARMA_3 Arma 3]. SQF was first introduced in [[{{ofpr}}]] together with the [[call]] operator in [[:Category:Introduced_with_Operation_Flashpoint:_Resistance_version_1.85|update 1.85]].
'''SQF''' stands for '''S'''tatus '''Q'''uo '''F'''unction - a successor of [[SQS_syntax|'''S'''tatus '''Q'''uo '''S'''cript]], which is deprecated since [[{{arma}}]] but could still be used in {{arma3}}. "Status Quo" was a code name for [https://en.wikipedia.org/wiki/Operation_Flashpoint Operation Flash Point], just like "Combined Arms" was a code name for [https://en.wikipedia.org/wiki/ARMA_(series) {{armaSeries}}] and "Futura" was a code name for [https://en.wikipedia.org/wiki/ARMA_3 {{arma3}}]. SQF was first introduced in [[{{ofpr}}]] together with the [[call]] operator in [[:Category:Introduced with Operation Flashpoint: Resistance version 1.85|update 1.85]].


An SQF expression has to be terminated via either {{Inline code|;}} or {{Inline code|,}}.
An SQF expression has to be terminated via either {{Inline code|;}} (preferred by convention!) or {{Inline code|,}}.
Example:
Example:
  _num = 10;
  _num = 10;
Line 20: Line 20:


== Language Structure ==
== Language Structure ==
The SQF Language is fairly simple in how it is built.
The SQF Language is fairly simple in how it is built.
In fact: there are barely any actual language structures at all.
In fact: there are barely any actual language structures at all.
Line 27: Line 28:


=== Comments ===
=== Comments ===
A comment is additional text that gets ignored when a script is parsed.
A comment is additional text that gets ignored when a script is parsed.
They serve as future reference and are often used to explain a specific part of the code.
They serve as future reference and are often used to explain a specific part of the code.


In SQF, there are two kind of comments:
In SQF, there are two kind of comments:
  {{codecomment|// In-line comment that ends on new line}}
  {{cc|In-line comment that ends on new line}}
   
   
  {{codecomment|/* Block Comment that can span above multiple lines
  {{codecomment|/* Block Comment that can span above multiple lines
Line 43: Line 45:
Another way to make a ''comment'' that way, is to just place a [[String|string]]: {{Inline code|[...]; "i can be considered as a comment but should not be used"; [...]}}
Another way to make a ''comment'' that way, is to just place a [[String|string]]: {{Inline code|[...]; "i can be considered as a comment but should not be used"; [...]}}


''Comments are removed during the [[PreProcessor_Commands|preprocessing]] phase.'' This is important to know as that prevents usage in eg. a [[String|string]] that gets compiled using the [[compile]] unary [[:Category:Scripting_Commands_Arma_3|operator]] or when only using [[loadFile]].
''Comments are removed during the [[PreProcessor_Commands|preprocessing]] phase.'' This is important to know as that prevents usage in e.g a [[String|string]] that gets compiled using the [[compile]] unary [[:Category:Scripting Commands|operator]] or when only using [[loadFile]].


=== Nular Operators ===
=== Nular Operators ===
{{Important|This page uses the in-engine name which is assumed to have the wrong type names for theese. Correct spelling thus is `Nullary` and not `Nulary` as it is written in here. }}
{{Important|This page uses the in-engine name which is assumed to have the wrong type names for theese. Correct spelling thus is `Nullary` and not `Nulary` as it is written in here. }}


Line 52: Line 55:


Consider following example in a mission with eg. 5 units:
Consider following example in a mission with eg. 5 units:
  {{codecomment|// Put the result of [[allUnits]] into a [[Variables|variable]].}}
  {{cc|Put the result of [[allUnits]] into a [[Variables|variable]].}}
  _unitsArray = [[allUnits]];
  _unitsArray = [[allUnits]];
   
   
  {{codecomment|// Display the current [[Array|array]] size using [[systemChat]].}}
  {{cc|Display the current [[Array|array]] size using [[systemChat]].}}
  [[systemChat]] [[str]] [[count]] _unitsArray;
  [[systemChat]] [[str]] [[count]] _unitsArray;
   
   
  {{codecomment|// Create a new unit in the player group.}}
  {{cc|Create a new unit in the player group.}}
  [[group]] [[player]] [[createUnit]] ["B_RangeMaster_F", [[position]] [[player]], [], 0, "FORM"];
  [[group]] [[player]] [[createUnit]] ["B_RangeMaster_F", [[position]] [[player]], [], 0, "FORM"];
   
   
  {{codecomment|// Output the [[Array|array]] size again}}
  {{cc|Output the [[Array|array]] size again}}
  [[systemChat]] [[str]] [[count]] _unitsArray;
  [[systemChat]] [[str]] [[count]] _unitsArray;
   
   
  {{codecomment|// Output the size of [[allUnits]]}}
  {{cc|Output the size of [[allUnits]]}}
  [[systemChat]] [[str]] [[count]] [[allUnits]];
  [[systemChat]] [[str]] [[count]] [[allUnits]];


Line 77: Line 80:


=== Unary Operators ===
=== Unary Operators ===
The unary [[:Category:Scripting_Commands_Arma_3|operators]] are [[:Category:Scripting_Commands_Arma_3|operators]] that expect an argument on their right side ({{Inline code|unary <argument>}}). They always will take the first argument that occurs.
The unary [[:Category:Scripting_Commands_Arma_3|operators]] are [[:Category:Scripting_Commands_Arma_3|operators]] that expect an argument on their right side ({{Inline code|unary <argument>}}). They always will take the first argument that occurs.


A common mistake would be the following:
A common mistake would be the following:
  {{codecomment|// Create some [[Array|array]] containing three arrays.}}
  {{cc|Create some [[Array|array]] containing three arrays.}}
  _arr = [[1, 2, 3, 4, 5], [1, 2, 3, 4], [1, 2]];
  _arr = [[1, 2, 3, 4, 5], [1, 2, 3, 4], [1, 2]];
   
   
  {{codecomment|// Wrongly use the [[select]] operator to get the count of the third array.}}
  {{cc|Wrongly use the [[select]] operator to get the count of the third array.}}
  [[count]] _arr [[select]] 2; <span style="color: Red;">// Error</span>
  [[count]] _arr [[select]] 2; <span style="color: Red;">// Error</span>


Line 96: Line 100:
To do it correctly, one would have to put the {{Inline code|_arr select 2}} in brackets.
To do it correctly, one would have to put the {{Inline code|_arr select 2}} in brackets.
The correct code thus would be:
The correct code thus would be:
  {{codecomment|// Create an [[Array|array]] containing three [[Array|arrays]].}}
  {{cc|Create an [[Array|array]] containing three [[Array|arrays]].}}
  _arr = [[1, 2, 3, 4, 5], [1, 2, 3, 4], [1, 2]];
  _arr = [[1, 2, 3, 4, 5], [1, 2, 3, 4], [1, 2]];
   
   
  {{codecomment|// Use Brackets to correctly get count of the third [[Array|array]].}}
  {{cc|Use Brackets to correctly get count of the third [[Array|array]].}}
  [[count]] (_arr [[select]] 2); {{codecomment|// Good :) will evaluate to 2}}
  [[count]] (_arr [[select]] 2); {{cc|Good :) will evaluate to 2}}


=== Binary Operators ===
=== Binary Operators ===
Line 106: Line 110:


As example, we will look into the following expression:
As example, we will look into the following expression:
  {{codecomment|// Create a nested [[Array|array]] with 5 levels.}}
  {{cc|Create a nested [[Array|array]] with 5 levels.}}
  _arr = [[[[[1]]]]];
  _arr = [[[[[1]]]]];
   
   
  {{codecomment|// Receive the nested number with some random math expressions.}}
  {{cc|Receive the nested number with some random math expressions.}}
  _arr [[select]] 0 [[select]] 1 [[-]] 1 [[select]] 15 [[a_/_b|/]]  3 [[-]] 5 [[select]] 0 [[select]] 10 [[a_*_b|*]] 10 [[+]] 4 [[a_*_b|*]] 0 [[-]] 100{{codecomment|// Evaluates to 1.}}
  _arr [[select]] 0 [[select]] 1 [[-]] 1 [[select]] 15 [[a_/_b|/]]  3 [[-]] 5 [[select]] 0 [[select]] 10 [[a_*_b|*]] 10 [[+]] 4 [[a_*_b|*]] 0 [[-]] 100 {{cc|Evaluates to 1.}}


Now, let us analyze why this is happening for the first few expressions:
Now, let us analyze why this is happening for the first few expressions:
Line 125: Line 129:
  ((((_arr [[select]] 0) [[select]] (1 [[-]] 1)) [[select]] ((15 [[a_/_b|/]]  3) [[-]] 5)) [[select]] 0) [[select]] (((10 [[a_*_b|*]] 10) [[+]] (4 [[a_*_b|*]] 0)) [[-]] 100)
  ((((_arr [[select]] 0) [[select]] (1 [[-]] 1)) [[select]] ((15 [[a_/_b|/]]  3) [[-]] 5)) [[select]] 0) [[select]] (((10 [[a_*_b|*]] 10) [[+]] (4 [[a_*_b|*]] 0)) [[-]] 100)


As you can see the [[a_*_b|*]] and [[a_/_b|/]] are executed first which matches their [[#precedence|precedence]]. Afterwards, the [[+]] and [[-]] [[:Category:Scripting_Commands_Arma_3|operators]] will get executed followed by our [[select]] operator, which are executed from the left to the right.
As you can see the [[a_*_b|*]] and [[a_/_b|/]] are executed first which matches their [[Operators|#Rules of Precedence|precedence]]. Afterwards, the [[+]] and [[-]] [[:Category:Scripting Commands|operators]] will get executed followed by our [[select]] operator, which are executed from the left to the right.


=== Rules of Precedence ===
See {{HashLink|Operators#Rules of Precedence}} for more information about precedence.
{| class="wikitable"
|-
!#
!Precedence
!Type of Operator
!Associativity
|-
|11
|<tt>HIGHEST</tt>
|
Nular operators (commands with no arguments):
* <tt>commandName</tt>
Other:
* Variables
* Values
* Braced expressions
| Left-to-right
|-
|10
|
|
Unary operators (commands with 1 argument):
* <tt>commandName</tt> a<br>
Unary plus and minus:
* [[+ |+a]]
* [[- | -a]]
[[Array]] copy operator:
* [[+ | +array]]
Logical <tt>NOT</tt> operator:
* [[!_a | !b]]
* [[not | not b]]
| Left-to-right
|-
|9
|
|
The new select operator:
* [[a_hash_b| array # index]]
| Left-to-right
|-
|8
|
|
Power operator:
* [[a ^ b]]
| Left-to-right
|-
|7
|
|
[[Number]] multiplication, division and remainder:
*[[a * b]]
* [[a / b]]
* [[a % b]]
* [[mod | a mod b]]
[[Config]] access:
* [[config / name]]
<tt>atan2</tt> command:
* [[atan2| a atan2 b]]
| Left-to-right
|-
|6
|
|
[[Number]] addition and subtraction:
* [[+ | a + b]]
* [[- | a - b]]
[[Array]] addition and subtraction:
* [[+ |  arr1 + arr2]]
* [[- | arr1 - arr2]]
[[String]] addition:
* [[+ | str1 + str2]]
<tt>min</tt> and <tt>max</tt> commands:
* [[min | a min b]]
* [[max | a max b]]
| Left-to-right
|-
|5
|
|
<tt>else</tt> operator:
* [[else]]
| Left-to-right
|-
|4
|
|
Binary operators (commands with 2 arguments):
* a <tt>commandName</tt> b
<tt>switch</tt> colon operator:
* [[a_:_b | : ]]
| Left-to-right
|-
|3
|
|
[[Number]] comparison:
* [[a == b]]
* [[a != b]]
* [[a_greater_b| a &gt; b]]
* [[a_less_b| a &lt; b]]
* [[a_less=_b| a &gt;= b]]
* [[a_less=_b| a &lt;= b]]
[[String]] comparison:
* [[a == b | str1 == str2]]
* [[a != b | str1 != str2]]
[[Group]], [[Side]], [[Object]], [[Structured Text]], [[Config]], [[Display]], [[Control]] or [[Location]] comparison:
* [[a == b]]
* [[a != b]]
[[Config]] access:
* [[config_greater_greater_name | config >> name]]
| Left-to-right
|-
|2
|
|
Logical <tt>AND</tt> operator:
* [[and| a && b]]
* [[and | a and b]]
| Left-to-right
|-
|1
|<tt>LOWEST</tt>
|
Logical <tt>OR</tt> operator:
* [[a or b| a <nowiki>||</nowiki> b]]
* [[a or b| a or b]]
| Left-to-right
|}




== See also ==
== See also ==
* [[Operators]]
* [[Control Structures]]
* [[Control Structures]]
* [[SQS syntax]]
* [[SQS syntax]]

Revision as of 14:05, 23 October 2020

Template:SideTOC SQF stands for Status Quo Function - a successor of Status Quo Script, which is deprecated since Arma but could still be used in Arma 3. "Status Quo" was a code name for Operation Flash Point, just like "Combined Arms" was a code name for Template:armaSeries and "Futura" was a code name for Arma 3. SQF was first introduced in Operation Flashpoint: Resistance together with the call operator in update 1.85.

An SQF expression has to be terminated via either ; (preferred by convention!) or ,. Example:

_num = 10;
_num = _num + 20; systemChat str _num;

In the above example, there are three expressions.

  1. _num = 10
  2. _num = _num + 20
  3. systemChat str _num

All get separated, not via a new line but the ;.

SQF also allows arrays and codeblocks to have expressions inside of them.

An array will always start with [ and ends with ]. The array may contain another value type including other arrays.

A codeblock is a separate value type containing numerous SQF expressions. It will be executed when used with eg. call and can be assigned to a variable just like any other value type. Codeblocks start with { and end with }


Language Structure

The SQF Language is fairly simple in how it is built. In fact: there are barely any actual language structures at all.

The functionality is provided via so called operators (or more commonly known scripting commands). Those operators are one of the following types: Nular, Unary, or Binary.

Comments

A comment is additional text that gets ignored when a script is parsed. They serve as future reference and are often used to explain a specific part of the code.

In SQF, there are two kind of comments:

// In-line comment that ends on new line

/* Block Comment that can span above multiple lines
and ends on the following character combination: */

A comment can occur anywhere but inside a string. For example, the following would be valid:

1 + /* Some random comment in an expression. */ 1

It should be mentioned that there is a comment unary operator that should not be used as it will actually be executed (thus taking time to execute) but does nothing besides consuming a string. There is no benefit in using it and the reason it exists is solely for backward compatibility. Another way to make a comment that way, is to just place a string: [...]; "i can be considered as a comment but should not be used"; [...]

Comments are removed during the preprocessing phase. This is important to know as that prevents usage in e.g a string that gets compiled using the compile unary operator or when only using loadFile.

Nular Operators

This page uses the in-engine name which is assumed to have the wrong type names for theese. Correct spelling thus is `Nullary` and not `Nulary` as it is written in here.

A nular operator is more or less a computed variable. Each time accessed, it will return the current state of something. It is tempting to think of a nular operator as nothing more but a magic global variable, but it is important to differentiate!

Consider following example in a mission with eg. 5 units:

// Put the result of allUnits into a variable.
_unitsArray = allUnits;

// Display the current array size using systemChat.
systemChat str count _unitsArray;

// Create a new unit in the player group.
group player createUnit ["B_RangeMaster_F", position player, [], 0, "FORM"];

// Output the array size again
systemChat str count _unitsArray;

// Output the size of allUnits
systemChat str count allUnits;

Now, what would the output of this look like?

System: 5
System: 5
System: 6

As you can see, _unitsArray was not automatically updated as it would have been if it was not generated each time. If allUnits was just a global variable with a reference to some internal managed array, our private variable should have had reflected the change as value types are passed by reference. The reason for this is because allUnits and other nular operators just return the current state of something and do not return a reference to eg. an array containing all units. It is generated each time, which is why some of theese operators are more expensive to run then just using a variable.

Unary Operators

The unary operators are operators that expect an argument on their right side (unary <argument>). They always will take the first argument that occurs.

A common mistake would be the following:

// Create some array containing three arrays.
_arr = [[1, 2, 3, 4, 5], [1, 2, 3, 4], [1, 2]];

// Wrongly use the select operator to get the count of the third array.
count _arr select 2; // Error

Now, what went wrong?

Let's put some brackets in the right places to make the mistake understandable:

(count _arr) select 2; // Error

Due to the nature of unary operators, count instantly consumes our variable _arr and returns the number 3. The 3 then is passed to select which does not knows what to do with a number as left argument and thus errors out.

To do it correctly, one would have to put the _arr select 2 in brackets. The correct code thus would be:

// Create an array containing three arrays.
_arr = [[1, 2, 3, 4, 5], [1, 2, 3, 4], [1, 2]];

// Use Brackets to correctly get count of the third array.
count (_arr select 2); // Good :) will evaluate to 2

Binary Operators

Binary operators expect two arguments (<1st argument> binary <2nd argument>) and are executed according to their precedence. If their precedence is equal, they are executed left to right.

As example, we will look into the following expression:

// Create a nested array with 5 levels.
_arr = [[[[[1]]]]];

// Receive the nested number with some random math expressions.
_arr select 0 select 1 - 1 select 15 /  3 - 5 select 0 select 10 * 10 + 4 * 0 - 100 // Evaluates to 1.

Now, let us analyze why this is happening for the first few expressions:

  1. _arr is loaded
  2. 0 is loaded
  3. select is executed with the result of 1. & 2.
  4. 1 is loaded
  5. 1 is loaded
  6. - is executed with the result of 4. & 5.
  7. select is executed with the result of 3. & 6.
  8. ...

If we now would put brackets at the correct spots, the expression will get clearer:

((((_arr select 0) select (1 - 1)) select ((15 /  3) - 5)) select 0) select (((10 * 10) + (4 * 0)) - 100)

As you can see the * and / are executed first which matches their #Rules of Precedence|precedence. Afterwards, the + and - operators will get executed followed by our select operator, which are executed from the left to the right.

See Operators - Rules of Precedence for more information about precedence.


See also