More on Symbols

A symbol is just a name, a simple identifier used for instance to denote the receiver of a message. They have a syntax, there are some constraints in their use, and they can be substituted using user-defined rules.


Symbol identifier

The identifier accepted for naming a symbol are matched by the following regular expression:

    [[:alpha:]_#'!~\xc3\xe2\x80-\xbf][[:alnum:]_#'/.?!+~>\-\xc3\xe2\x80-\xbf]*

In other words, a symbol starts with an alphabetic character and then is possibly followed by an underscore, a sharp, a quote, etc.. Characters \0xc3and \xe2 followed by a character in the range \x80-\xbf refer to some UTF-8 two bytes encoded characters in the latin family largely accessible on standard keyboards (like or the accented latin characters).

In order to facilitate the interaction with existing Max or PD patches, the identifier of a message can be extended to start with a numeric character, using the two additional regular expressions:

    [0-9]+[[:alpha:]_'\xc3\xe2\x80-\xbf-]{2,}[[:alnum:]_#?'!~*/+.\-\xc3\xe2\x80-\xbf]*
    [0-9]+[a-rA-Rt-zT-Z]+

These extended identifiers cann be used only as a message receivers.

Because reserved keywords are indistinguishable of symbols, they are some additional constraints on a symbol identifier:

  • the following identifiers cannot be the identifier of a symbol at any place: expr, true, false

  • the following identifiers cannot be used as symbols in the argument list of a function application, (including tab or map enumeration): in, and, with, let, tab, map and nim.

  • a reserved keyword (at the exception of the previous ones) can name a symbol if the symbol is in a message argument or in an argument of a function application.


Appearance of a symbol in the score

Symbols cannot be written anywhere a value is expected. Symbols can be written:

  • in a tab definition,

  • in a map definition,

  • as a message argument

  • as a function argument

  • anywhere an expression is expected if the symbol is between parenthesis.

Here are some examples of accepted use of a symbol:

    print A_Symbol       ; symbol 'A_Symbol' as a message argument
    $x := [A6, B4, D3]   ; symbols in a tab definition
    @f(pi)               ; symbol 'pi' as the argument of a function
    $2pi = 2 * (pi)      ; symbol 'pi' enclosed in parenthesis in an arbitrary expression
    print 1 2 3          ; symbol 'print' as a message receiver

If you need to use a reserved keyword as a symbol, for instance if you need to denote a message receiver which is a reserved keyword, use a string instead.


Expression on Symbols

They are few predefined functions or operators that handle directly symbols. Symbols can be compared or they can be tested with the predicate @is_symbol. For instance expression

    (foo) == (foo)

returns true.

Most of the predefined functions in the library accept a symbol where they accepts a string: the symbol is implicitly converted into the string associated to its identifier. So, a symbol can be tested against a string and expression:

    (foo) == "foo"

also returns true.


Symbol expansion

A symbols is a value, so its value is itself. However, there is a mechanism similar to macro-expansion, that can be used to evaluate a symbol into another value.

The rule used to replace a symbols by a value are introduced in a @symbol_def section. This section gathers a comma-separated list of symbol rules. A symbol rule takes two forms.

Literal rules

The first kind of rule associates a symbol with an expression:

    symbol -> expression

when symbol is evaluated, it is replaced by the evaluation of expression. For example

    @symbol_def {
          pi -> 3.141592635,
    }

        $tmp := [ pi ]
    print pi $tmp

will print

    3.14159 [ 3.14159 ]

Expression is not necessarily a constant expression. It may include global variables (but not local one, the @symbol_def appears only at score top-level). The expression is evaluated when evaluating the symbol occurence. So two occurence of the same symbol may lead to different values:

    @symbol_def {
          pi -> 3.141592635,
          xxx -> $x
    }

        $tmp := [ xxx ]
    print $tmp
    $x := 2
    print ((pi) * (xxx))
    $x := 3
    print ((pi) * (xxx))

Notice the symbols in parenthesis when they are in an expression but may appear without them when they are elements of a tab. The previous program fragment will print:

    [ <undef> ]
    6.2832
    9.4248

because when $tmp is evaluated, the variable $x has no value and then the value of $x is updated.

Parameterized rules

The left hand side (lhs) of a parameterized rule is a regular expression (given as a string) and its right hand side (rhs) is a named function. If the symbol name matches the lhs, then the value of the symbol if the application of the rhs to the string associated with the symbol name.

For example, the following definition can be used to denote midi notes through their symbolic name:

    @symbol_def {
        sil -> 0,
        "[A-Ga-g]([#bx]|bb|##)?[0-9]([+-][0-9]+)?" -> @symb2midicent
    }

For the symbolic name of midi pitches, see Pitch specification and function @symb2midicent.

With this definition, one may write expressions like:

    $translated_pitch := (C4) + 3               ; gives 6003.0 because C4 gives 6000.0
    $pitch_list := [C4, D#3, Ab4+1, sil, B##3]  ; gives [6000.0, 5100.0, 6801.0, 0, 6100.0]