Generalized conditionals

Mup also supports more general "if" clauses. If you happen to be
familiar with the preprocessors for the C and C++ programming
languages, Mup "if" clauses are very similar.
If you're not, that's okay, since things are explained below.
Also, some of the operations are really very rarely needed, so if
you find some of them confusing, you just can skip past this section;
you'll likely never have a need for the complicated operations anyway.

The general form is

ifconditionthenMup statementselseMup statementsendif

As with the "ifdef," the "else" and second set of Mup statements is optional.

One form of "if" is really just a variation of ifdef. It uses the
keyword "defined" followed by a macro name. So

ifdef DUET

could also be written

if defined DUET then

You may put a set of parentheses around the macro name for clarity
if you wish:

if defined(DUET) then

The ! is used to mean "not," so

ifndef TRIO

could also be written as

if ! defined(TRIO) then

So far, this just looks longer, so what's the advantage?
The difference is that ifdef and ifndef can only be used to check if a single
macro is defined or not, whereas the "if" condition is much more general,
and therefore much more powerful.
Decisions can be based on the values of macros, not just whether they are
defined or not, and can also be based on more than one macro at a time,
Here is an example of a condition based on several macros at once:

would be true only if both FULL_SCORE and TRANSPOSE_UP were defined,
but MIDI was not defined. The && means "and."
There is also || which means "or," so

if defined(CELLO) || defined(STRINGBASS)

would be true as long as at least one of the macros was defined.

The condition can also include numbers and macros used as numeric values
in arithmetic and comparisons. For example,

define STAFFS 3 @
define S 5 @
if STAFFS > 5 then
// ... this would not be executed, since 3 is not greater than 5
endif
if 2 <= STAFFS then
// ... This would be executed, since 2 is less than or equal to 3
endif
if STAFFS + 1 == S - 1 then
// ... This would be executed, since 3+1 equals 5-1
endif

Note that the symbol to test for "equals" is two equals signs, not just
one. This is to be consistent with what is used in the C and C++ languages.
The operators for comparisons are:

<

less than

>

greater than

<=

less than or equal

>=

greater than or equal

==

equal

!=

not equal

Note that the values in the conditions can only be either literal numbers
or macros whose values evaluate to a number. They cannot be things like
Mup parameters.
A macro which is not defined is treated as having a value of zero.
Macro values are substituted for macro names just as elsewhere in Mup,
so if you use a macro whose resulting value does not evaulate to a number,
you may get an error or other unexpected result.

If you are familiar with "octal" and "hexadecimal" numbers, they can be
used, following the C language convention of a leading zero for octal
or a leading 0x for hexadecimal. (If you're not familiar with these
numbers or conventions, don't worry about it; it's never really necessary
to use them. Just make sure you don't accidentally start a number other
than a zero with a zero).

Values are limited to 32-bit signed whole numbers. (If you don't know
what that means, what you need to know is that you
can only use numbers between -2147483648 and 2147483647, and cannot
use fractions.) Results of arithmetic on values will also be whole
numbers, so division will result in either rounding
or truncation to a whole number,
and the exact characteristics may be system dependent.

Before we introduce the remaining operators, it would be good to discuss
two concepts, called precedence and associativity. These determine the
order in which operations are done. Consider the following expression:

5 + 3 * 8

What is its value? If we just went left to right, we would add 5 and 3,
getting 8, then multiple by 8, for a final value of 64. However,
multiplication is generally considered to have higher "precedence"
than addition, meaning that multiplications should be done before additions.
In other words, the expression should actually be treated as

5 + (3 * 8)

so we would first multiply 3 by 8, getting 24, and then add 5 and 24,
obtaining a final answer of 29.

If you really intended the 64 meaning, that could be shown by parentheses,
indicating you want the addition to be done first:

(5 + 3) * 8

Associativity determines whether operators of equal precedence are done
left to right or right to left. Parentheses and
all of the operators that have two
operands associate left to right, while all the others
associate right to left. For example, since addition and subtraction
associate left to right, the expression

10 - 6 - 1

would be evaluated by first subtracting 6 from 10 to get 4,
then subtracting 1, yielding 3.
If they associated right to left, first 1 would be subtracted from 6
to get 5, which would then be subtracted from 10, yielding 5.
So using different associativity can lead to different answers!

Since the "not" operator and unary minus associate right to left,
in the expression

! - (5)

the unary minus would be applied first to get -5, then the "not" would be
applied. But what does "not -5" mean? The "not" operator will treat its
operand as a boolean value, with a value of zero meaning false, and
any non-zero value being true. Since -5 is not zero, it represents "true,"
and "not true" would be "false," or zero. By the way,
any operator that yields a boolean result
(not, logical and, logical or, less than, greater than,
less than or equal, greater than or equal, equal, or not equal) will
always yield 1 for true, even though any non-zero value could mean true.

The operators are listed below. Those on the same line have the same
precedence, with those on each line having higher precedence than the
lines below.