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 :

  1. Production — le code EBNF (ISO 14977)
  2. 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

  1. Contraintes — ce que l’EBNF ne peut pas exprimer (invariants, cohérence inter-productions)
  2. Source — référence au code C de BP3 quand pertinent (fichier:lignes)
  3. 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 mode TEM.

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érences gram#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, SUB1 et POSLONG interdisent les flags /flag/, les directives _goto, et la commande « Produce all items » (CompileGrammar.c:613-695, ProduceItems.c:757).
  • Le mode TEM n’a pas de logique de sélection propre dans le moteur de calcul (TEMtype défini mais non référencé dans Compute.c) — le comportement est déterminé par la direction TEMP.

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 si FLAG_OP pré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 si section vaut 1
  • /count+1/ — incrémentation : count augmente 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 rule utilise ARROW = --> (production uniquement).
  • Règle 1 : weight = <50-10> (initial 50, décrément 10), flag = /section=1/ (active si section == 1).
  • Règle 2 : weight = <30> (fixe), flag = /section>2/ (active si section > 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, #wildcard ou #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 :

TikZ diagram

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 (09). 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, , 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=0 dans FillPhaseDiagram.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

Voir aussi : B6, B8

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. #INT seul = entier, #INT/#INT = fraction.
  • voice (1..n) — séquence de #rhs_element constituant 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 *)

 

Voir aussi : B5, B12

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 #(}) comme context_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 comme key + 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 des rhs_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, #IDENT ou STRING).

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’index N. #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 : chiffre 09.
  • "_" : underscore autorisé dans le corps.

UPPER_IDENT

 

UPPER_IDENT = upper_letter , { letter | digit | "_" } ;

 

  • upper_letter : lettre majuscule (AZ). Première position obligatoirement majuscule.

Utilisé pour les non-terminaux.

INT

 

INT = digit+ ;

 

  • digit (1..n) : un ou plusieurs chiffres 09.

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 chiffre 09.

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 LanguagesL9).

TikZ diagram

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 du MODE du 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

Suite directe

  • B11 — L’AST de BP3 : anatomie d’un code intermédiaire musical

Connexions

Retour


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