Inno Setup Preprocessor: Expression Syntax

Inno Setup Preprocessor

Inno Setup Preprocessor: Expression Syntax

ISPP uses C/C++-like expression syntax. It supports simple and compound assignment operators, conditional operator, and sequential evaluation operator. Although ISPP is an interpreter, it does support short circuit boolean evaluation and never evaluates expressions (nor calls any macros mentioned in those expressions) that should not be evaluated due to specific rules (for example, when conditional operator is used, always only 2 out of 3 operands are evaluated).

The ISPPBuiltins.iss file contains many example expressions.

Differences between C and ISPP expression syntax

  • ISPP does not support a number of operators (reference, dereference, namespace resolution, member selection, etc.).
  • ISPP treats an identifier and the equality sign as a name of an argument, if it is used in argument list.
  • Arithmetic division operator (slash) performs integer division, since ISPP does not support floating point math.
  • ISPP does not check for validity of expressions is certain cases. For example, in conditional expression, "true" operand can be of string type, whereas "false" operand can be of integer type.
  • String literals can be quoted by both single and double quotes (in both modes – C-style or Pascal-style). If a literal begins with a single quote, it must also end with a single quote. Double quotes may be used in single quoted string without any escaping, and vice versa. Within a string the character used to quote the string must be escaped (the manner depends on current state of "Pascal-style string literals" parser option, see pragma).

Data types

There are three types in ISPP: void, integer, and string. Variable of void type is declared by just specifying its name after define directive without any value. Such variables should be used with ifdef directive or Defined function.

If "allow undeclared identifiers" parser option is off (the default state, see pragma), an error is raised when undefined variable is mentioned. Otherwise, it will be treated as a value of type void.

Void is compatible with integer and string in expressions. For example, you can use addition operator with void and integer operands, in this case void operand will be treated as zero. In conjunction with string, void operand is treated as an empty string.

Comments

Comments may be embedded in expression by using a slash and an asterisk. For example:

#emit Var1 /* this is a comment */ + Var2 /* this is a comment */

Also one line comments are supported. Those comments must begin with a semicolon. Whole text after the semicolon up to the end of a line is considered comment.

#emit Var1 + Var2 ; this is a comment

Please note that line spanning feature is triggered before any further processing, thus a comment may occupy more than one line:

#emit Var1 + Var2 ; this is \
  a comment

Extended Macro Call Syntax

In ISPP it is possible to use named arguments when calling user defined macro. Given the declaration:

#define MyMacro(int A = 2, int B = 2) A + B

This macro can be called specifying argument names:

#emit MyMacro(A = 5, B = 10)
#emit MyMacro(B = 3)
#emit MyMacro(B = 10, A = 5)

  • If a name is specified for one argument, then all (required) arguments in the list must also be named.
  • The order of named arguments does not matter.
  • Because of this extension, an assignment expression must be enclosed in parentheses, if not using extended call syntax, to avoid ambiguity:

    #emit MyMacro((MyVar = 5), 10)

    In the above example, the equality sign is treated as a direct assignment operator.

    Although functions do not have named arguments, it is still required to enclose assignment expressions in parentheses when calling those functions.

  • By standard rule comma is used to separate actual parameters. If you need to use sequential evaluation operator, you must include the expression in paretheses:

    #emit MyMacro((SaveToFile("script.txt"), 5), 10)

    In the above example, the first comma is treated as the sequential evaluation operator, whereas the second one as the argument delimitter.