Aller au contenu
roomi fields

Le langage BP3 · B10 · Référence

L'EBNF de BP3

Découvrez la première spécification formelle complète de BP3 : 83 productions EBNF détaillées dans un format de référence unique (EBNFdoc).

Publié le 24 mars 2026 · Read in English

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
  3. Contraintes — ce que l’EBNF ne peut pas exprimer (invariants, cohérence inter-productions)
  4. Source — référence au code C de BP3 quand pertinent (fichier:lignes)
  5. Exemple — tiré des fichiers de test (bp3-ctests/) quand disponible

Notation EBNF utilisée (ISO 14977) :

NotationSignification
=Définition
,Concaténation
∣\vertAlternative
[ ... ]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 = 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éfixeDocumentTypeNameContenuOccurrences tests
grGrammarFichier de grammaire principal (implicite)52
seSettingsTempo, canaux MIDI, configuration globale72
alAlphabetTerminaux et mappings MIDI ou SynthDef12
hoHomomorphismsTables de substitution note → note1
csCsoundScores Csound (format externe)—
toTime-objectsRéférences à des objets temporels (son, vidéo, robot)—
tbTables/talasStructures rythmiques prédéfinies20
soSound objectsDéfinitions de sound-objects7
sc/+scScriptsScripts de contrôle externe3
daData/itemsDonnées internes (items)26

Préfixes internes (6) :

PréfixeDocumentTypeNameContenuSource
kbKeyboardMapping du clavier physique vers les fonctions BP3-BP3main.h:398
glGlossaryGlossaire de termes et abréviations-BP3main.h:398
inInteractionParamètres interactifs K (poids dynamiques <K1>, <K1=5>)-BP3main.h:398
mdMIDI driverConfiguration du driver MIDI (ports, canaux, timing)-BP3main.h:398
trTraceJournal de débogage (dérivations, applications de règles)-BP3main.h:398
wgWeightsTables 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 :

ValeurNom completStratégie de sélection des règlesArticle
ORDOrderedSéquentiel, dans l’ordre de déclarationB3
RNDRandomAléatoire pondéré selon les poids <N> des règlesB1, B3
LINLinearCyclique (wrap-around : retour à la première règle après la dernière)B3
SUBSubstituteSubstitution simultanée de toutes les occurrences d’un non-terminalB3
SUB1Substitute firstSubstitution de la première occurrence uniquement (leftmost)B3
TEMTemplatesSous-grammaire destinée à l’appariement via le bloc TEMPLATES:B3
POSLONGPositional longestComme 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 :

ValeurNomDirectionActif en PRODActif en ANAL
-->ProductionGauche → droiteouinon
<->BidirectionnelLes deuxouioui
<--AnalyseDroite → gauchenonoui

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)
ValeurSens du parcours
LEFTGauche à droite (leftmost)
RIGHTDroite à gauche (rightmost)
RNDPosition 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 :
FormeComposantsSémantiqueExemple
INTpoids simplePoids fixe. Raccourci pour INT-0.<3>
INT - INTpoids décrémenté1er = valeur initiale, 2e = décrément à chaque usage.<50-12>
K IDENTK nuPoids interactif — l’utilisateur choisit dynamiquement.<K1>
K IDENT = INTK avec valeurRè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_OPSémantique
=Assignation ou test d’égalité
+Incrémentation
-Décrémentation
>, <Comparaison stricte
≥, ≤, ≠Comparaison (Unicode)

Formes de flag_value :

FormeTypeSémantiqueExemple
INTINTValeur littérale entière/x=5/
FLOATFLOATValeur littérale flottante/tempo=0.8/
K IDENT"K" + IDENTRéférence à un K-paramètre interactif/a=Kb/
IDENTIDENTRé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 :

Les23typesderhselementTerminauxStructurelsExtensionsContr^olenoterestundeterminedrestnonterminalpolymetrictimesigannotationquotedsymboltievariablewildcardpatternexprnilstringspecialfncontextmarkergotodirectiveouttimeobjectsynctagspeedrationegationbeatseparatorstartsymbol

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èmeExemplesAltérations
Françaisdo, ré, mi, fa, sol, la, si# (dièse), b (bémol)
Anglo-saxonC, D, E, F, G, A, B#, b
Indiensa, re, ga, ma, pa, dha, nip (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.
FormeMode PRODMode ANAL
?Placeholder anonymeAccepte n’importe quel terminal
?1Capture nommée — génère un motifCapture un motif et vérifie sa cohérence
?1 ... ?1Ré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.

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 :

FormeTokenSémantique
/N/T0/11Speed up — accélération de facteur N
*NT0/21Scale up — mise à l’échelle (augmentation)
**NT0/24Scale down — mise à l’échelle (diminution)
\NT0/25Speed 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É


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égorieFonctions principalesNb argsCouche*
Hauteur_transpose(N), _scale(name,base), _pitchbend(N), _pitchrange(N), _keyxpand(N1,N2)1-24
Vélocité_vel(N), _volume(N), _rndvel(N)13
Articulation_staccato(N), _legato(N)13
Timing_mm(N), _tempo(ratio), _rndtime(N), _striated, _smooth0-15
Instruments_ins(name), _script(name), _chan(N), _part(N), _capture(N)12
MIDI_mod(N), _pitchbend(N), _press(N), _pan(N), _switchon(cc,value), _switchoff(cc,value)1-22
Structure_retro, _rotate(N), _randomize, _destru, _srand(N)0-14
Dérivation_goto(N,M), _failed(N,M), _repeat(N), _stop0-25

*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.

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 0-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 chiffres 0-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 chiffre 0-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).

GrammaireDEBP3(cetteEBNF)GrammairesDANSBP3(les¯chiers.bp)Type2(context-free)Type2+(MCSL)parseL'EBNF(Type2)estlasyntaxequipermetd'ECRIREdesgrammairesBP3(Type2+)

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

CoucheProductionsContenuArticles
1. Structure globale5Fichier, headers, 16 préfixes, directivesB7
2. Blocs de grammaire57 modes, préambule, séparateurB3
3. Règles83 flèches, 3 modes dérivation, poids (K), flags (Unicode)B1, B4
4. Éléments LHS/RHS23Notes, silences, polymétrie, variables, wildcards, out-time, sync, T0 opsB2 à B6
5. Fonctions spéciales368 perf controls + 17 grammar procedures en 8 catégoriesM12
6. Templates5Section TEMPLATES:, placeholders, groupes (@N)B8
7. Lexèmes~14Identifiants, 4 systèmes de notes, nombresB2
8. Fichiers de référence~10Settings, alphabet, homo, Csound, time-objectsB9
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

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