<-- previous page     Table of Contents    Index    next page -->

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

if condition then Mup statements else Mup statements endif

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:

 if defined(FULL_SCORE) && defined(TRANSPOSE_UP) && ! defined(MIDI) then

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 that 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 multiply 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.
operators operations associativity
( ) grouping left to right
! ~ - + not, one's complement, unary minus, unary plus right to left
* / % multiply, divide, modulo left to right
+ - add, subtract left to right
<< >> left shift, right shift left to right
< <= > >= less than, less or equal, greater than, greater or equal left to right
== != equal, not equal left to right
& bitwise AND left to right
^ bitwise XOR left to right
| bitwise OR left to right
&& logical AND left to right
|| logical OR left to right
? : interrogation right to left


   <-- previous page    Table of Contents    Index    next page -->