B10) L’EBNF de BP3
Grammaire formelle d’un langage musical
Dans L3, nous avons appris à lire des grammaires EBNF. Dans B1 à B6, nous avons découvert les constructions de BP3 une par une. Cet article assemble le tout : la grammaire complète du langage BP3 en ~83 productions, documentée dans un format de référence systématique.
Où se situe cet article ?
Cet article est le point de convergence formelle de la série B. Chaque construction explorée individuellement — les probabilités (B1), les alphabets (B2), la dérivation (B3), les flags (B4), la polymétrie (B5), les homomorphismes (B6) — trouve ici sa place exacte dans une grammaire formelle unique.
C’est aussi l’application directe de L3 : là où L3 présentait la notation EBNF comme un outil abstrait, B10 l’utilise pour spécifier un langage réel. Le lecteur qui maîtrise les conventions EBNF de L3 peut lire les productions de cet article sans explication supplémentaire.
B10 prépare B11 (l’AST de BP3) : chaque production EBNF correspond à un ou plusieurs types de nœuds dans l’arbre de syntaxe abstraite. L’EBNF définit ce qui peut être écrit ; l’AST définit comment c’est représenté en mémoire.
Pourquoi c’est important ?
BP3 (Bol Processor 3, cf. I2) existe depuis 1990, mais sa syntaxe n’a jamais été formalisée dans une grammaire EBNF complète. La documentation historique de Bernard Bel décrit les constructions par l’exemple et par le code source C — une approche pragmatique mais insuffisante pour :
- Implémenter un parseur alternatif : sans grammaire formelle, il faut lire le code source C pour comprendre ce qui est syntaxiquement valide
- Comparer BP3 avec d’autres langages : sans spécification, on ne peut pas mesurer précisément l’expressivité syntaxique de BP3 face à LilyPond, ABC notation ou TidalCycles
- Classifier BP3 dans Chomsky : la question « à quel niveau de la hiérarchie se situe BP3 ? » exige de distinguer la grammaire de BP3 (sa syntaxe) des grammaires dans BP3 (ce que l’utilisateur écrit)
L’EBNF que nous présentons ici est, à notre connaissance, la première spécification formelle complète de BP3 — et l’une des rares grammaires EBNF publiées pour un langage de composition algorithmique.
L’idée en une phrase
La syntaxe de BP3 se décrit en ~83 productions EBNF organisées en 8 couches — structure globale, blocs de grammaire, règles, 23 types d’éléments, fonctions spéciales, templates, lexèmes et fichiers de référence — documentées ici dans un format de référence systématique (EBNFdoc).
Convention de lecture (format EBNFdoc)
Cet article utilise un format de documentation systématique inspiré des références d’API (Javadoc, MDN, Rust docs), adapté aux productions EBNF. Pour chaque production :
- Production — le code EBNF (ISO 14977)
- Composants — chaque terminal et non-terminal documenté individuellement :
– Nom exact tel qu’il apparaît dans la production
– Type (INT, IDENT, non-terminal, littéral)
– Cardinalité : requis, optionnel ([ ]), répétable ({ }, +)
– Description précise
- Contraintes — ce que l’EBNF ne peut pas exprimer (invariants, cohérence inter-productions)
- Source — référence au code C de BP3 quand pertinent (
fichier:lignes) - Exemple — tiré des fichiers de test (
bp3-ctests/) quand disponible
Notation EBNF utilisée (ISO 14977) :
| Notation | Signification |
|---|---|
= |
Définition |
, |
Concaténation |
| $\vert$ | Alternative |
[ ... ] |
Optionnel (0 ou 1) |
{ ... } |
Répétition (0 ou plus) |
... + |
Répétition (1 ou plus) — extension courante |
"..." |
Terminal littéral |
(* ... *) |
Commentaire |
Couche 1 — Structure globale
bp_file
bp_file = { header } , grammar_section+ , [ template_section ] ;
- #
header(0..n) — en-têtes précédant les blocs de grammaire (commentaires, références de fichiers, directives d’initialisation). - #
grammar_section(1..n) — blocs de grammaire contenant les règles de production. Au moins un bloc requis. - #
template_section(optionnel) — bloc de templates structurels. Présent uniquement si au moins une sous-grammaire utilise le modeTEM.
Contrainte : template_section ne peut apparaître que si hasTEMP == TRUE (CompileGrammar.c:190).
header
header = comment | file_ref | init_directive ;
Un header est exactement l’un des trois types suivants :
- #
comment— commentaire textuel ignoré par le parseur. - #
file_ref— référence à un fichier externe (alphabet, settings, etc.). - #
init_directive— directive d’initialisation.
comment
comment = "//" , TEXT ;
"//"— marqueur de début de commentaire.TEXT— contenu libre jusqu’à la fin de ligne. Ignoré par le parseur.
file_ref
file_ref = "-" , prefix , "." , name ;
"-"— marqueur de référence de fichier.prefix:IDENT— préfixe identifiant le type de fichier (voir table ci-dessous)."."— séparateur.name:IDENT— nom du fichier référencé (sans extension).
Source : -BP3main.h:386-401 (FilePrefix[], FileExtension[], DocumentTypeName[])
Préfixes documentés (10) :
| Préfixe | DocumentTypeName |
Contenu | Occurrences tests |
|---|---|---|---|
gr |
Grammar | Fichier de grammaire principal (implicite) | 52 |
se |
Settings | Tempo, canaux MIDI, configuration globale | 72 |
al |
Alphabet | Terminaux et mappings MIDI ou SynthDef | 12 |
ho |
Homomorphisms | Tables de substitution note → note | 1 |
cs |
Csound | Scores Csound (format externe) | — |
to |
Time-objects | Références à des objets temporels (son, vidéo, robot) | — |
tb |
Tables/talas | Structures rythmiques prédéfinies | 20 |
so |
Sound objects | Définitions de sound-objects | 7 |
sc/+sc |
Scripts | Scripts de contrôle externe | 3 |
da |
Data/items | Données internes (items) | 26 |
Préfixes internes (6) :
| Préfixe | DocumentTypeName |
Contenu | Source |
|---|---|---|---|
kb |
Keyboard | Mapping du clavier physique vers les fonctions BP3 | -BP3main.h:398 |
gl |
Glossary | Glossaire de termes et abréviations | -BP3main.h:398 |
in |
Interaction | Paramètres interactifs K (poids dynamiques <K1>, <K1=5>) |
-BP3main.h:398 |
md |
MIDI driver | Configuration du driver MIDI (ports, canaux, timing) | -BP3main.h:398 |
tr |
Trace | Journal de débogage (dérivations, applications de règles) | -BP3main.h:398 |
wg |
Weights | Tables de poids prédéfinies pour les modes RND/LIN | -BP3main.h:398 |
Exemple :
-se.Tihai (* charge le fichier settings "Tihai" *)
-al.Tabla (* charge l'alphabet "Tabla" *)
init_directive
init_directive = "INIT:" , TEXT ;
"INIT:"— marqueur de bloc d’initialisation.TEXT— commande de script exécutée avant la dérivation pour initialiser l’environnement (instrument MIDI, tempo, lecture de fichier, etc.). Le contenu est passé àExecScriptLine(CompileGrammar.c:222).
Contrainte : certaines commandes de script sont interdites dans INIT: (ex. ouvrir un nouveau projet — ScriptUtils.c:102).
Exemples :
INIT: MIDI program 110 (* sélectionne l'instrument MIDI 110 *)
INIT: Play I46 (* joue le fichier d'interaction I46 avant la dérivation *)
Exemple complet de structure globale :
// Tihai simple en mode ORD ← comment
-se.Tihai ← file_ref (prefix=se, name=Tihai)
-al.Tabla ← file_ref (prefix=al, name=Tabla)
ORD[1] ← début grammar_section
gram#1[1] S --> |x| - |x| - |x| ← rule
gram#1[2] |x| --> dha tirakita dhin ← rule
Couche 2 — Blocs de grammaire
grammar_section
grammar_section = mode_line , [ preamble ] , [ separator ] , rule+ ;
- #
mode_line— requis. Déclaration du mode de dérivation et de l’index du bloc. - #
preamble(optionnel) — fonctions spéciales appliquées globalement au bloc entier avant toute règle. - #
separator(optionnel) — ligne de tirets séparant le préambule des règles. - #
rule(1..n) — règles de production du bloc. Au moins une règle requise.
mode_line
mode_line = MODE , "[" , INT , "]" , [ IDENT ] ;
- #
MODE— requis. Mode de dérivation du bloc. "[","]"— délimiteurs de l’index.- #
INT— requis. Index numérique du bloc (≥ 1). Identifie le bloc dans les référencesgram#N. - #
IDENT(optionnel) — label libre attaché au bloc. N’affecte pas la dérivation.
Contrainte : l’INT de mode_line doit correspondre au N dans les rule_prefix (gram#N) des règles contenues dans ce bloc.
Exemple : RND[2] MyBlock → mode RND, index 2, label MyBlock.
MODE
MODE = "ORD" | "RND" | "LIN" | "SUB" | "SUB1" | "TEM" | "POSLONG" ;
7 valeurs possibles :
| Valeur | Nom complet | Stratégie de sélection des règles | Article |
|---|---|---|---|
ORD |
Ordered | Séquentiel, dans l’ordre de déclaration | B3 |
RND |
Random | Aléatoire pondéré selon les poids <N> des règles |
B1, B3 |
LIN |
Linear | Cyclique (wrap-around : retour à la première règle après la dernière) | B3 |
SUB |
Substitute | Substitution simultanée de toutes les occurrences d’un non-terminal | B3 |
SUB1 |
Substitute first | Substitution de la première occurrence uniquement (leftmost) | B3 |
TEM |
Templates | Sous-grammaire destinée à l’appariement via le bloc TEMPLATES: |
B3 |
POSLONG |
Positional longest | Comme SUB1, mais sélectionne la dérivation la plus longue (leftmost-longest match) |
B3 |
Source : -BP3main.h:125 (SubgramType[]), -BP3.h:875-881 (RNDtype=0 à POSLONGtype=6)
Contraintes :
- Les modes
SUB,SUB1etPOSLONGinterdisent les flags/flag/, les directives_goto, et la commande « Produce all items » (CompileGrammar.c:613-695,ProduceItems.c:757). - Le mode
TEMn’a pas de logique de sélection propre dans le moteur de calcul (TEMtypedéfini mais non référencé dansCompute.c) — le comportement est déterminé par la directionTEMP.
preamble
preamble = special_fn+ ;
- #
special_fn(1..n) — fonctions spéciales appliquées globalement avant les règles du bloc (ex :_mm(120),_ins(Tabla)).
separator
separator = "----" , { "-" } ;
"----"— 4 tirets minimum."-"(0..n) — tirets supplémentaires optionnels (longueur libre).
Couche 3 — Règles
rule
rule = rule_prefix , [ weight ] , [ DERIVATION_MODE ] , { flag } , lhs , ARROW , rhs , [ comment ] ;
- #
rule_prefix— requis. Identifiant unique de la règle (gram#N[M]). - #
weight(optionnel) — poids probabiliste de la règle. - #
DERIVATION_MODE(optionnel) — sens de parcours pour cette règle (défaut :RND). - #
flag(0..n) — conditions et modifications de variables. - #
lhs— requis. Côté gauche (ce qui est réécrit). - #
ARROW— requis. Type de flèche (direction de la règle). - #
rhs— requis. Côté droit (résultat de la réécriture). Peut être vide. - #
comment(optionnel) — commentaire en fin de ligne.
Ordre des composants : l’ordre est strict. Le DERIVATION_MODE vient après le poids et avant les flags.
Source : Encode.c:103-725 (encodage des règles)
Exemple : gram#3[1] <100> LEFT /x=1/ M16 <-> V16 // commentaire
rule_prefix
rule_prefix = "gram#" , INT , "[" , INT , "]" ;
"gram#"— marqueur de règle.- #
INT(1er) — requis. Numéro de grammaire (N). Identifie le bloc parent. "[","]"— délimiteurs.- #
INT(2e) — requis. Numéro de règle dans le bloc (M).
Contrainte : le 1er INT doit correspondre à l’index du grammar_section parent (celui de mode_line).
Exemple : gram#3[47] → 47e règle du 3e bloc.
ARROW
ARROW = "-->" | "<->" | "<--" ;
3 valeurs possibles :
| Valeur | Nom | Direction | Actif en PROD | Actif en ANAL |
|---|---|---|---|---|
--> |
Production | Gauche → droite | oui | non |
<-> |
Bidirectionnel | Les deux | oui | oui |
<-- |
Analyse | Droite → gauche | non | oui |
Source : -BP3main.h:114 (MAXARROW=3), -BP3.h:886 (ARROWLENGTH=4)
Contrainte : <-> est la valeur la plus courante (217 occurrences dans bp3-ctests). <-- n’apparaît dans aucun fichier de test — son usage réel est une question ouverte (cf. §13, Q4).
Voir aussi : B8 (directions PROD, ANAL, TEMP)
DERIVATION_MODE
DERIVATION_MODE = "LEFT" | "RIGHT" | "RND" ;
3 valeurs possibles. Ce mode est distinct du MODE du bloc (couche 2) :
MODE(bloc) = quelle stratégie de sélection ? (ORD, RND, LIN, SUB, SUB1, TEM, POSLONG)DERIVATION_MODE(règle) = dans quel sens parcourir ? (LEFT, RIGHT, RND)
| Valeur | Sens du parcours |
|---|---|
LEFT |
Gauche à droite (leftmost) |
RIGHT |
Droite à gauche (rightmost) |
RND |
Position aléatoire (défaut si omis) |
Source : Encode.c:478-508, -gr.dhati:49, -gr.look-and-say
Exemple : gram#3[1] <100> LEFT M16 <-> V16 → dérivation de gauche à droite.
weight
weight = "<" , weight_expr , ">" ;
weight_expr = INT , [ "-" , INT ]
| "K" , IDENT , [ "=" , INT ] ;
"<",">": littéraux — délimiteurs du poids.weight_expr: l’une des formes suivantes :
| Forme | Composants | Sémantique | Exemple |
|---|---|---|---|
INT |
poids simple | Poids fixe. Raccourci pour INT-0. |
<3> |
INT - INT |
poids décrémenté | 1er = valeur initiale, 2e = décrément à chaque usage. | <50-12> |
K IDENT |
K nu | Poids interactif — l’utilisateur choisit dynamiquement. | <K1> |
K IDENT = INT |
K avec valeur | Règle active seulement si le K-paramètre IDENT vaut INT. |
<K1=5> |
Source : -gr.Mozart:34-44 (K avec et sans valeur)
Voir aussi : B4
flag
flag = "/" , IDENT , [ FLAG_OP , flag_value ] , "/" ;
FLAG_OP = "=" | "+" | "-" | ">" | "<"
| "≥" | "≤" | "≠" ;
flag_value = INT | FLOAT
| "K" , IDENT
| IDENT ;
"/"— délimiteurs du flag.- #
IDENT— requis. Nom de la variable (flag). FLAG_OP(optionnel) : opérateur. Absent = interrupteur booléen.flag_value(optionnel, requis siFLAG_OPprésent) : valeur de l’opération.
Opérateurs :
FLAG_OP |
Sémantique |
|---|---|
= |
Assignation ou test d’égalité |
+ |
Incrémentation |
- |
Décrémentation |
>, < |
Comparaison stricte |
≥, ≤, ≠ |
Comparaison (Unicode) |
Formes de flag_value :
| Forme | Type | Sémantique | Exemple |
|---|---|---|---|
INT |
INT |
Valeur littérale entière | /x=5/ |
FLOAT |
FLOAT |
Valeur littérale flottante | /tempo=0.8/ |
K IDENT |
"K" + IDENT |
Référence à un K-paramètre interactif | /a=Kb/ |
IDENT |
IDENT |
Référence directe à un autre flag (flag→flag) | /a=otherflag/ |
Source : Encode.c:478-508 (flag-to-flag assignment avec needsK et needsflag)
Exemples :
/stop/— interrupteur booléen (pas d’opérateur)/section=1/— test : la règle s’applique seulement sisectionvaut 1/count+1/— incrémentation :countaugmente de 1 à chaque application/a=Kb/— assignation croisée via K-paramètre/a=otherflag/— assignation directe flag→flag
Voir aussi : B4
Exemple combinant bloc, règle et contrôle :
RND[2] ← MODE=RND, INT=2
gram#2[1] <50-10> /section=1/ A --> do ré mi fa
gram#2[2] <30> /section>2/ A --> sol la si do5
gram#2[3] <20> A --> - - - -
- Bloc en mode
RND(sélection aléatoire pondérée, couche 2). - Chaque
ruleutiliseARROW=-->(production uniquement). - Règle 1 :
weight=<50-10>(initial 50, décrément 10),flag=/section=1/(active sisection== 1). - Règle 2 :
weight=<30>(fixe),flag=/section>2/(active sisection> 2). - Règle 3 :
weight=<20>(fixe), pas de flag (toujours disponible).
Couche 4 — Éléments LHS et RHS
lhs
lhs = lhs_element+ ;
lhs_element = non_terminal | variable | wildcard | context_marker ;
lhs_element(1..n) — le côté gauche doit contenir au moins un élément. Chaque élément est un #non_terminal, #variable, #wildcardou #context_marker.
Contrainte : quand lhs contient plus d’un élément, la règle devient context-sensitive (Type 1 de Chomsky). Le premier élément est le symbole réécrit, les suivants sont le contexte requis.
Exemple context-sensitive :
gram#3[47] |o| |miny| --> |o1| |miny|
|o| n’est réécrit en |o1| que si |miny| est adjacent. Le |miny| dans le RHS est un pass-through — il est transmis sans modification. C’est ce mécanisme qui pousse BP3 au-delà du Type 2 (L1).
rhs
rhs = rhs_element* ;
- #
rhs_element(0..n) — le côté droit peut être vide (*), ce qui correspond à l’effacement d’un symbole (production ε).
rhs_element
rhs_element = note | rest | prolongation | undetermined_rest
| non_terminal | variable | wildcard
| polymetric | special_fn | nil_string
| pattern_expr | time_sig | annotation
| quoted_symbol | tie
| context_marker | goto_directive
| out_time_object | sync_tag
| speed_ratio | negation
| beat_separator | start_symbol ;
23 types possibles, organisés en 4 familles :

Figure 1 — Les 23 types d’éléments RHS de BP3, organisés en 4 familles.
4.1 Terminaux
note
note = NOTE_NAME , [ OCTAVE ] ;
- #
NOTE_NAME— requis. Nom de la note dans l’un des 4 systèmes de notation. - #
OCTAVE(optionnel) — chiffre indiquant l’octave (0–9). Défaut : l’octave définie dans les settings.
4 systèmes de notation (-BP3.h:478-483) :
| Système | Exemples | Altérations |
|---|---|---|
| Français | do, ré, mi, fa, sol, la, si |
# (dièse), b (bémol) |
| Anglo-saxon | C, D, E, F, G, A, B |
#, b |
| Indien | sa, re, ga, ma, pa, dha, ni |
p (komal), d (tivra) |
| Keys (MIDI) | 60, 72, 48 |
— (numéros MIDI directs 0-127) |
BP3 supporte jusqu’à 100 gammes personnalisées (MAXCONVENTIONS=100) via _scale().
Contrainte : les notes anglo-saxonnes (C4, A8) sont syntaxiquement identiques à des non-terminaux (UPPER_IDENT). La distinction est résolue à l’émission : les identifiants majuscules non définis qui correspondent au pattern [A-G][#b]?\d sont traités comme des notes. C’est une ambiguïté syntaxique résolue par le contexte sémantique.
rest
rest = "-" ;
"-"— silence déterminé. Sa durée est calculée par le contexte temporel.
Source : token T3/1 (BP2-info.txt)
prolongation
prolongation = "_" ;
"_"— prolongation. Étend l’événement précédent sans nouvelle attaque. Le son continue, pas de silence. Code interne :kobj=0dansFillPhaseDiagram.c.
Source : token T3/0 (BP2-info.txt)
undetermined_rest
undetermined_rest = "..." ;
"..."— repos indéterminé. Durée calculée par l’algorithme PolyMake pour équilibrer les voix polymétriques.
Source : token T3/0 (BP2-info.txt)
Voir aussi : B5, B13
non_terminal
non_terminal = UPPER_IDENT ;
- #
UPPER_IDENT— requis. Identifiant commençant par une majuscule (S,Phrase,Tihai,A8).
4.2 Extensions context-sensitive
variable
variable = "|" , IDENT , "|" ;
"|"— délimiteurs.- #
IDENT— requis. Nom de la variable.
Quand |x| apparaît plusieurs fois dans le RHS, chaque occurrence est remplacée par la même valeur — copie synchronisée. C’est le mécanisme qui pousse BP3 au-delà du Type 2 (B6).
wildcard
wildcard = "?" , [ INT ] ;
"?"— marqueur de wildcard.- #
INT(optionnel) — index de capture nommée. Absent = wildcard anonyme.
| Forme | Mode PROD | Mode ANAL |
|---|---|---|
? |
Placeholder anonyme | Accepte n’importe quel terminal |
?1 |
Capture nommée — génère un motif | Capture un motif et vérifie sa cohérence |
?1 ... ?1 |
Réplication du motif capturé | Vérifie que le même motif apparaît aux deux positions |
nil_string
nil_string = "lambda" | "nil" | "empty" | "null" ;
4 formes équivalentes pour la production vide ε (effacement d’un non-terminal).
Source : -BP3main.h:112
pattern_expr
pattern_expr = "(=" , rhs_element+ , ")"
| "(:" , rhs_element+ , ")"
| HOMO_REF ;
(= ...)— master : dérive son contenu normalement et fige le résultat pour les slaves liés.(: ...)— slave : copie le résultat déjà dérivé du master(= ...)le plus proche à gauche dont le contenu syntaxique est identique. Si un homomorphisme*est défini dans l’alphabet, le slave applique la transformation avant de copier (→ pseudo-répétition).HOMO_REF— référence à un fichier d’homomorphismes externe (-ho.).
Mécanisme. La liaison master/slave est résolue à la compilation par recherche linéaire gauche-droite. L’imbrication directe n’est pas supportée — utiliser des non-terminaux intermédiaires pour les patterns imbriqués (ex. chakkardar tihai).
Exemples :
S --> (= A)(= B)(: A)(: B)(: A) (* tihai : produit aabba si A→a, B→b *)
S --> (= A) (: A) (* copie stricte : produit {ww} *)
Voir aussi : B6
4.3 Constructions structurelles
polymetric
polymetric = "{" , [ ratio , "," ] , voice , { "," , voice } , "}" ;
ratio = INT | INT "/" INT ;
voice = rhs_element+ ;
"{","}"— délimiteurs de bloc polymétrique.ratio(optionnel) — facteur de tempo. #INTseul = entier, #INT/#INT= fraction.voice(1..n) — séquence de #rhs_elementconstituant une voix. Plusieurs voix séparées par",".
Exemples :
{do ré mi, sol la si do5} (* 2 voix simultanées, durée égale *)
{3, do ré mi fa sol la si} (* ratio de tempo : 3× *)
{2/3, mi fa sol} (* ratio fractionnaire *)
time_sig
time_sig = TIME_SIG_PATTERN ;
- #
TIME_SIG_PATTERN— signature temporelle.
annotation
annotation = "[" , TEXT , "]" ;
"[","]"— délimiteurs.TEXT— contenu libre. Métadonnée attachée au flux musical.
quoted_symbol
quoted_symbol = "'" , TEXT , "'" ;
"'"— délimiteurs.TEXT— symbole littéral transmis tel quel.
tie
tie = note , "&" | "&" , note ;
note &: début de liaison — la note est prolongée.& note: continuation de liaison — la note est connectée à la précédente.
Équivalent de la liaison de prolongation en notation musicale occidentale.
4.4 Contrôle de flux
context_marker
context_marker = "LEFT" ;
LEFT: force le parseur à ne considérer que le contexte gauche.
[!warning] Correction
La version originale de cet article incluait
(|symbole|),#({)et#(})commecontext_markerétendus. Ces constructions n’existent pas dans le code source de BP3. Elles ont été retirées.
goto_directive
goto_directive = "_goto(" , INT , "," , INT , ")" ;
- #
INT(1er) — requis. Numéro de bloc cible (N). - #
INT(2e) — requis. Numéro de règle cible (M).
Saut impératif vers la règle M du bloc N. Mécanisme de contrôle de flux impératif au sein d’un formalisme déclaratif.
Contrainte : interdit dans les blocs SUB, SUB1 et POSLONG (Encode.c:363-365).
Source : 8 occurrences dans bp3-ctests.
out_time_object
out_time_object = "<<" , ( note | IDENT ) , ">>" ;
"<<",">>"— délimiteurs d’objet hors-temps.- #
note— note MIDI jouée immédiatement hors du flux temporel (encodée commekey + 16384). - #
IDENT— référence à un sound-object dans l’alphabet (encodé comme index).
Source : Encode.c:574-725 (token T7). Le seuil 16384 distingue les notes (x ≥ 16384 → x - 16384 = MIDI key) des sound-objects (x < 16384 → index).
sync_tag
sync_tag = "<<" , "W" , INT , ">>" ;
"<<",">>"— délimiteurs."W"— marqueur de synchronisation.- #
INT— requis. Index du point de synchronisation.
Mécanisme de rendez-vous entre voix polymétriques : <<W1>> dans une voix attend <<W1>> dans une autre voix avant de continuer.
Source : token T8 (BP2-info.txt)
speed_ratio
speed_ratio = "/" , INT , "/"
| "*" , INT
| "**" , INT
| "\" , INT ;
4 opérateurs de vitesse :
| Forme | Token | Sémantique |
|---|---|---|
/N/ |
T0/11 | Speed up — accélération de facteur N |
*N |
T0/21 | Scale up — mise à l’échelle (augmentation) |
**N |
T0/24 | Scale down — mise à l’échelle (diminution) |
\N |
T0/25 | Speed down — ralentissement de facteur N |
Source : BP2-info.txt:22,32,35, Encode.c:103-118
negation
negation = "#" ;
"#"— opérateur de négation.
beat_separator
beat_separator = "." ;
"."— séparateur de battement.
Source : token T0/7 (BP2-info.txt:18)
start_symbol
start_symbol = "S" ;
"S"— symbole de départ de la grammaire.
Source : token T0/10 (BP2-info.txt:21)
~~concatenation~~ — RETIRÉ
[!warning] Correction
Le
+n’est pas un opérateur de concaténation entre symboles dans le RHS. Il n’existe que dans le contexte des flags (/flag+1/), où il sert d’incrément. Il ne fait pas partie desrhs_element. Erreur d’interprétation du token T0/3 dans la version originale de cet article.
Couche 5 — Fonctions spéciales
special_fn
special_fn = "_" , IDENT , [ "(" , args , ")" ] ;
args = arg , { "," , arg } ;
arg = INT | FLOAT | IDENT | STRING ;
"_"— préfixe obligatoire qui distingue les fonctions spéciales des éléments grammaticaux.- #
IDENT— requis. Nom de la fonction. args(optionnel) — liste d’arguments séparés par",".arg— un argument typé (#INT, #FLOAT, #IDENTouSTRING).
BP3 définit 68 performance controls (tokens T10-T46 et T12/0-30) et 17 grammar procedures. Elles se répartissent en 8 catégories :
| Catégorie | Fonctions principales | Nb args | Couche* |
|---|---|---|---|
| Hauteur | _transpose(N), _scale(name,base), _pitchbend(N), _pitchrange(N), _keyxpand(N1,N2) |
1-2 | 4 |
| Vélocité | _vel(N), _volume(N), _rndvel(N) |
1 | 3 |
| Articulation | _staccato(N), _legato(N) |
1 | 3 |
| Timing | _mm(N), _tempo(ratio), _rndtime(N), _striated, _smooth |
0-1 | 5 |
| Instruments | _ins(name), _script(name), _chan(N), _part(N), _capture(N) |
1 | 2 |
| MIDI | _mod(N), _pitchbend(N), _press(N), _pan(N), _switchon(cc,value), _switchoff(cc,value) |
1-2 | 2 |
| Structure | _retro, _rotate(N), _randomize, _destru, _srand(N) |
0-1 | 4 |
| Dérivation | _goto(N,M), _failed(N,M), _repeat(N), _stop |
0-2 | 5 |
*Les numéros de couche renvoient au modèle d’abstraction musicale (M12).
Source : StringLists.h:265-335 (déclaration des fonctions avec nombre d’arguments)
Contrainte : chaque contrôle continu (vélocité, modulation, pitch bend, etc.) existe en 3 variantes : _xxxstep (palier), _xxxcont (interpolation), _xxxfixed (valeur fixe). Ces variantes sont des détails d’implémentation MIDI.
Exemple :
ORD[1]
_mm(120) ← preamble : tempo global 120 BPM
_ins(Tabla) ← preamble : instrument Tabla
gram#1[1] S --> _vel(80) Tihai ← _vel(80) s'applique localement
Couche 6 — Templates
template_section
template_section = "TEMPLATES:" , template_def+ ;
"TEMPLATES:"— marqueur de début de section.- #
template_def(1..n) — définitions de templates.
Contrainte : n’apparaît que si au moins une sous-grammaire a le mode TEM et si hasTEMP == TRUE (CompileGrammar.c:190).
template_def
template_def = "[" , INT , "]" , template_pattern ;
"[","]"— délimiteurs de l’index.- #
INT— requis. Index du template. - #
template_pattern— le squelette structurel.
template_pattern
template_pattern = { time_sig | speed_ratio | placeholder
| "(" , "@" , INT , template_body , ")"
| rhs_element } ;
- #
time_sig(0..n) — signature temporelle. - #
speed_ratio(0..n) — ratio de vitesse (*1/1,*1/2). - #
placeholder(0..n) — position de substitution. (@N ...)(0..n) — groupe référençant la sous-grammaire d’indexN. #INT= index de la sous-grammaire, #template_body= contenu.- #
rhs_element(0..n) — éléments RHS ordinaires.
placeholder
placeholder = "_"+ ;
"_"(1..n) : un ou plusieurs underscores consécutifs. Dans le contexte des templates,_conserve sa sémantique de prolongation (T3/0,kobj=0) — même sémantique que partout ailleurs dans le langage. Il n’y a pas de double sémantique.
[!note] La section
TEMPLATES:est ignorée par le compilateur (CompileGrammar.c:437-443). Elle sert de documentation structurelle, pas de code exécutable.
template_body
template_body = { placeholder | rhs_element } ;
Source : -gr.checktemplates, -gr.dhin-- (bp3-ctests)
Exemple :
TEMPLATES:
[1] *1/1 __*1/2 _
[5] *1/1 (@0 _)(@1 )
[1] 4+4*1/6 (@0 (@0 (@0 ______) * (@1 ))(@2 ))____ * (@3 )____
Couche 7 — Lexèmes
IDENT
IDENT = letter , { letter | digit | "_" } ;
letter: lettre minuscule ou majuscule.digit: chiffre0–9."_": underscore autorisé dans le corps.
UPPER_IDENT
UPPER_IDENT = upper_letter , { letter | digit | "_" } ;
upper_letter: lettre majuscule (A–Z). Première position obligatoirement majuscule.
Utilisé pour les non-terminaux.
INT
INT = digit+ ;
digit(1..n) : un ou plusieurs chiffres0–9.
FLOAT
FLOAT = [ "-" ] , digit+ , "." , digit+ ;
"-"(optionnel) : signe négatif.digit+: partie entière.".": séparateur décimal.digit+: partie fractionnaire.
NOTE_NAME
NOTE_NAME = FRENCH_NOTE | ANGLO_NOTE | INDIAN_NOTE | KEY_NOTE ;
KEY_NOTE = INT ;
FRENCH_NOTE = ("do"|"ré"|"re"|"mi"|"fa"|"sol"|"la"|"si") , [alteration] ;
ANGLO_NOTE = ("C"|"D"|"E"|"F"|"G"|"A"|"B") , [alteration] ;
INDIAN_NOTE = ("sa"|"re"|"ga"|"ma"|"pa"|"dha"|"ni") , [alteration_in] ;
alteration = "#" | "b" ;
alteration_in = "p" | "d" ;
4 systèmes de notation qui produisent le même type de nœud AST (Note). Le parseur doit reconnaître 4 alphabets musicaux simultanément.
OCTAVE
OCTAVE = digit ;
digit: un seul chiffre0–9.
TIME_SIG_PATTERN
TIME_SIG_PATTERN = INT , { "+" , INT } , "/" , INT ;
- #
INT(1..n) — numérateur(s). Plusieurs numérateurs additionnés séparés par"+". "/"— séparateur.- #
INT— dénominateur.
Exemple : 4+4*1/6 → signature temporelle composite.
Couche 8 — Fichiers de référence
Formalisation préliminaire des 5 formats les plus utilisés. Ces EBNF sont dérivées de l’analyse du code source C et des 213 fichiers de test — elles n’ont pas été validées exhaustivement.
settings_file (-se.)
settings_file = { settings_line } ;
settings_line = key , ":" , value ;
key = "tempo" | "channel" | "velocity" | "transpose"
| "pitchbend_range" | IDENT ;
value = INT | FLOAT | STRING ;
Paires clé-valeur configurant les paramètres globaux (tempo, canal MIDI, vélocité initiale, transposition).
alphabet_file (-al.)
alphabet_file = { alphabet_entry } ;
alphabet_entry = terminal , mapping ;
terminal = NOTE_NAME | IDENT ;
mapping = midi_mapping | synthdef_mapping ;
midi_mapping = INT ;
synthdef_mapping = "SynthDef(" , STRING , ")" ;
Correspondance entre terminaux et événements sonores (MIDI ou SynthDefs SuperCollider).
homo_file (-ho.)
homo_file = { homo_entry } ;
homo_entry = source_note , "-->" , target_note ;
source_note = NOTE_NAME ;
target_note = NOTE_NAME ;
Tables de substitution note → note (B6).
csound_file (-cs.)
csound_file = CSOUND_SCORE ;
Format externe Csound — transmis directement au moteur de synthèse, non parsé par BP3.
timeobj_file (-to.)
timeobj_file = { timeobj_entry } ;
timeobj_entry = IDENT , ":" , resource_ref ;
resource_ref = file_path | url | device_ref ;
Correspondance entre identifiants et ressources externes (fichiers audio, vidéos, commandes robotiques). Voir B9.
Note : la formalisation des fichiers de référence constitue une contribution originale : aucun document publié ne fournit de grammaire formelle pour ces formats auxiliaires. Ces EBNF sont préliminaires.
Méta — Grammaire de BP3 vs grammaires dans BP3
L’EBNF ci-dessus (~83 productions) est la grammaire du langage BP3 — elle décrit ce qu’un fichier BP3 peut syntaxiquement contenir. C’est une grammaire context-free (Type 2 de Chomsky, L1).
Les fichiers BP3 eux-mêmes contiennent des grammaires — les règles gram#N[M] écrites par l’utilisateur. Ces grammaires internes, grâce aux variables, wildcards, homomorphismes et règles à LHS multi-symboles, sont plus puissantes que le Type 2 : elles atteignent le niveau MCSL (Mildly Context-Sensitive Languages — L9).

Figure 2 — Deux niveaux de grammaire : la grammaire de BP3 (méta-niveau, Type 2) et les grammaires dans BP3 (niveau objet, Type 2+).
Limites de l’EBNF
Une grammaire EBNF spécifie la syntaxe — ce qui est un fichier BP3 bien formé. Elle ne couvre pas :
Sémantique. L’EBNF dit que <50-12> est un poids valide, mais pas ce que signifie « décrémenter de 12 ». Voir L6 (sémantique opérationnelle), L7 (sémantique dénotationnelle).
Stratégie de dérivation. L’EBNF dit que ORD et RND sont des modes valides, mais pas comment le moteur choisit et applique les règles. Voir B3.
Contraintes inter-productions. L’EBNF ne peut pas exprimer que le INT de rule_prefix doit correspondre à l’index du grammar_section parent. Ces invariants relèvent de la spécification AST (B11).
L’EBNF est une condition nécessaire mais pas suffisante : un fichier peut être syntaxiquement correct et pourtant invalide (numéros incohérents, terminaux non définis, variables non liées). Un parseur réel a besoin d’une phase de validation après le parsing — la 4e phase du pipeline (B7).
Récapitulatif
| Couche | Productions | Contenu | Articles |
|---|---|---|---|
| 1. Structure globale | 5 | Fichier, headers, 16 préfixes, directives | B7 |
| 2. Blocs de grammaire | 5 | 7 modes, préambule, séparateur | B3 |
| 3. Règles | 8 | 3 flèches, 3 modes dérivation, poids (K), flags (Unicode) | B1, B4 |
| 4. Éléments LHS/RHS | 23 | Notes, silences, polymétrie, variables, wildcards, out-time, sync, T0 ops | B2 à B6 |
| 5. Fonctions spéciales | 3 | 68 perf controls + 17 grammar procedures en 8 catégories | M12 |
| 6. Templates | 5 | Section TEMPLATES:, placeholders, groupes (@N) | B8 |
| 7. Lexèmes | ~14 | Identifiants, 4 systèmes de notes, nombres | B2 |
| 8. Fichiers de référence | ~10 | Settings, alphabet, homo, Csound, time-objects | B9 |
| Total | ~83 |
Ce qu’il faut retenir
- BP3 se décrit en ~83 productions EBNF organisées en 8 couches : structure globale, blocs de grammaire, règles, éléments LHS/RHS, fonctions spéciales, templates, lexèmes, fichiers de référence.
- Le format EBNFdoc documente chaque production systématiquement : composants typés, cardinalité, contraintes, source C, exemples.
- 7 modes de sous-grammaire (ORD, RND, LIN, SUB, SUB1, TEM, POSLONG) déterminent la stratégie de sélection des règles au niveau du bloc.
- 3 flèches (
-->,<->,<--) contrôlent dans quelles directions (PROD, ANAL) chaque règle est active. - 3 modes de dérivation par règle (LEFT, RIGHT, RND) contrôlent le sens de parcours — un niveau distinct du mode du bloc.
- 23 types d’éléments RHS donnent au langage sa flexibilité : des notes et silences aux variables context-sensitive, en passant par la polymétrie, les sync tags et les fonctions spéciales.
- 68 performance controls et 17 grammar procedures forment une couche performative qui opère sur 4 niveaux d’abstraction.
- La grammaire de BP3 (cette EBNF) est context-free (Type 2). Les grammaires dans BP3 (écrites par l’utilisateur) sont Type 2+ (MCSL) grâce aux variables, wildcards et règles context-sensitive.
- L’EBNF est une condition nécessaire mais pas suffisante : un parseur réel a besoin d’invariants supplémentaires (B11) et d’une phase de validation (B7).
Et après ?
L’EBNF est le plan d’architecte — elle dit quelles pièces existent et comment elles s’agencent. L’étape suivante est de comprendre ce que le parseur construit à partir de ce plan : l’arbre de syntaxe abstraite (AST), avec ses 29 types de nœuds, ses invariants, et sa correspondance production par production avec l’EBNF. C’est l’objet de B11.
Glossaire
- ARROW : Type de flèche d’une règle BP3 (
-->,<->,<--). Détermine dans quelles directions (PROD, ANAL) la règle est active. - DERIVATION_MODE : Sens de parcours pour une règle individuelle (
LEFT,RIGHT,RND). Distinct duMODEdu bloc. - EBNFdoc : Format de documentation systématique des productions EBNF, inspiré des références d’API (Javadoc, MDN). Chaque production est documentée avec ses composants typés, contraintes, source C et exemples.
- Flag : Variable conditionnelle attachée à une règle (
/nom=valeur/). Contrôle l’activation et modifie l’état de la dérivation. - grammar_section : Bloc de grammaire contenant un mode, un préambule optionnel et des règles.
- K-paramètre : Poids interactif (
<K1>,<K1=5>) permettant à l’utilisateur de contrôler dynamiquement la sélection des règles. - LHS (Left-Hand Side) : Côté gauche d’une règle — ce qui est réécrit. Doit contenir au moins un élément.
- MCSL (Mildly Context-Sensitive Languages) : Classe de langages entre le Type 2 (context-free) et le Type 1 (context-sensitive). Position des grammaires écrites dans BP3.
- MODE : Mode de dérivation d’un bloc de grammaire (ORD, RND, LIN, SUB, SUB1, TEM, POSLONG). Détermine la stratégie de sélection des règles.
- Out-time object : Élément
<<...>>joué immédiatement, hors du flux temporel normal. Peut être une note MIDI ou un sound-object. - Performance control : Fonction spéciale (
_nom(args)) contrôlant le rendu sonore (hauteur, vélocité, timing, etc.). 68 fonctions définies dans BP3. - Poids : Valeur numérique
<N>ou<N-M>contrôlant la probabilité de sélection d’une règle en mode RND. - RHS (Right-Hand Side) : Côté droit d’une règle — le résultat de la réécriture. Peut être vide (production ε). 23 types d’éléments possibles.
- rule_prefix : Identifiant unique d’une règle (
gram#N[M]).N= index du bloc,M= index de la règle dans le bloc. - Sync tag : Point de synchronisation
<<WN>>entre voix polymétriques. Mécanisme de rendez-vous. - Template : Squelette structurel pré-calculé par la direction TEMP. Stocké dans le bloc
TEMPLATES:.
Liens
Prérequis
- L3 — EBNF : la notation standard pour écrire des grammaires
- B1 — PCFG : grammaires probabilistes à B6 — Homomorphismes, variables et contexte
Suite directe
- B11 — L’AST de BP3 : anatomie d’un code intermédiaire musical
Connexions
- B7 — De BP3 à SuperCollider : anatomie du transpileur (pipeline complet)
- B8 — Deux directions, trois modes (PROD, ANAL, TEMP)
- B9 — Time-objects : quand BP3 dépasse la musique (fichiers
-to.) - B12 — Les trois temps de BP3 (temps symbolique et
_tempo()) - L1 — La hiérarchie de Chomsky (classification)
- L9 — Au-delà de Chomsky (MCSL)
- M12 — De la structure au son (couches d’abstraction)
- R2 — Spécification formelle de BP3 (version technique détaillée)
Retour
- Index des séries
- Glossaire
Références
[Bel1990] Bel, B. (1990). Bol Processor BP1 and its music features. Rapport de recherche GRTC, Marseille.
[Bel1992] Bel, B. (1992). Symbolic and Sonic Representations of Sound-Object Structures. In M. Balaban, K. Ebcioğlu & O. Laske (Eds.), Understanding Music with AI, AAAI Press.
[Bel1998] Bel, B. (1998). Migrating musical concepts: an overview of the Bol Processor. Computer Music Journal, 22(2), 56-64.
[Bel2001] Bel, B. (2001). Rationalizing Musical Time: Syntactic and Symbolic-Numeric Approaches. In C. Music (Ed.), The Ratio Book, Den Haag: Royal Conservatory.
[ISO14977] ISO/IEC 14977:1996. Information technology — Syntactic metalanguage — Extended BNF.
[Chomsky1956] Chomsky, N. (1956). Three Models for the Description of Language. IRE Transactions on Information Theory, 2(3), 113-124.
[Kippen1992] Kippen, J. & Bel, B. (1992). Modelling Music with Grammars: Formal Language Representation in the Bol Processor. In A. Marsden & A. Pople (Eds.), Computer Representations and Models in Music, Academic Press.
[AhoUllman1972] Aho, A. V. & Ullman, J. D. (1972). The Theory of Parsing, Translation, and Compiling. Prentice-Hall.
Prérequis : L3 (EBNF), B1 à B6 (constructions BP3)
Temps de lecture : 20 min
Tags : #EBNF #BP3 #spécification #référence #EBNFdoc #grammaire-formelle
← Retour à l’index