Priorité des opérateurs booléens
La priorité des opérateurs booléens détermine l'ordre dans lequel les différentes parties d'une expression logique sont évaluées lorsqu'aucune parenthèse n'impose explicitement un autre ordre. Cette notion est essentielle pour interpréter correctement les expressions comportant plusieurs négations, conjonctions, disjonctions, comparaisons ou opérateurs dérivés.
Une expression comme :
| A OU B ET C |
peut sembler ambiguë. Elle pourrait théoriquement être comprise comme :
| (A OU B) ET C |
ou comme :
| A OU (B ET C) |
Dans la plupart des systèmes logiques et des langages de programmation, l'opérateur ET possède une priorité supérieure à celle de l'opérateur OU. L'expression est donc habituellement interprétée comme :
| A OU (B ET C) |
Cette interprétation peut modifier entièrement le résultat obtenu. La connaissance des règles de priorité évite ainsi les erreurs logiques, améliore la lisibilité des conditions et permet de concevoir des expressions dont le comportement correspond précisément à l'intention du programmeur.
Définition de la priorité
La priorité d'un opérateur indique à quel moment celui-ci doit être appliqué par rapport aux autres opérateurs présents dans une même expression.
Un opérateur de priorité élevée est évalué avant un opérateur de priorité plus faible.
Par exemple, dans l'expression :
| NON A ET B |
la négation possède généralement une priorité supérieure à la conjonction.
L'expression est donc interprétée comme :
| (NON A) ET B |
et non comme :
| NON(A ET B) |
Ordre de priorité booléen courant
Dans une expression booléenne classique, l'ordre suivant est généralement appliqué :
- Parenthèses
- NON
- ET
- XOR
- OU
- Implication
- Équivalence
Cet ordre constitue une convention fréquente, mais il ne représente pas une règle universelle pour tous les langages de programmation.
La documentation du langage utilisé demeure toujours la référence définitive.
Tableau général des priorités
| Niveau | Opération | Notations fréquentes | Priorité |
|---|---|---|---|
| 1 | Parenthèses | ( ) | La plus élevée |
| 2 | Négation | NON, NOT, !, ¬ | Très élevée |
| 3 | Conjonction | ET, AND, &&, ∧ | Élevée |
| 4 | Ou exclusif | XOR, ⊕ | Intermédiaire |
| 5 | Disjonction | OU, OR, ||, ∨ | Plus faible |
| 6 | Implication | → | Faible |
| 7 | Équivalence | ↔, XNOR | Très faible |
Ce tableau décrit principalement une convention logique générale. Certains langages omettent plusieurs de ces opérateurs ou leur attribuent une autre priorité.
Rôle des parenthèses
Les parenthèses permettent de définir explicitement l'ordre d'évaluation.
Dans :
| (A OU B) ET C |
la disjonction est évaluée avant la conjonction, même si l'opérateur ET possède normalement une priorité plus élevée.
Les parenthèses modifient donc l'ordre naturel :
| A OU B ET C |
qui serait normalement interprété comme :
| A OU (B ET C) |
Parenthèses imbriquées
Plusieurs niveaux de parenthèses peuvent être utilisés.
|
A ET ( B OU ( C ET NON D ) ) |
L'expression la plus profondément imbriquée est généralement évaluée en premier.
L'ordre conceptuel devient :
- NON D
- C ET NON D
- B OU (C ET NON D)
- A ET le résultat précédent
Priorité de la négation
La négation possède généralement la priorité booléenne la plus élevée après les parenthèses.
Ainsi :
| NON A ET B |
signifie :
| (NON A) ET B |
De même :
| NON A OU B |
signifie :
| (NON A) OU B |
Pour nier une expression complète, il faut employer des parenthèses :
| NON(A ET B) |
Différence produite par les parenthèses
Considérons :
|
A = VRAI B = FAUX |
L'expression :
| (NON A) ET B |
devient :
| FAUX ET FAUX |
et retourne :
| FAUX |
En revanche :
| NON(A ET B) |
devient :
| NON(VRAI ET FAUX) |
puis :
| NON FAUX |
et retourne :
| VRAI |
Les deux expressions produisent donc des résultats différents.
Priorité du ET
L'opérateur ET est habituellement évalué avant l'opérateur OU.
L'expression :
| A OU B ET C |
est interprétée comme :
| A OU (B ET C) |
Cette convention ressemble à celle de l'arithmétique, où la multiplication est évaluée avant l'addition.
Analogie avec l'arithmétique
En arithmétique :
| A + B × C |
est interprété comme :
| A + (B × C) |
En algèbre de Boole :
| A OU B ET C |
est généralement interprété comme :
| A OU (B ET C) |
L'opérateur ET joue donc un rôle de priorité comparable à celui de la multiplication, tandis que le OU possède une priorité comparable à celle de l'addition.
Exemple avec ET et OU
Considérons :
|
A = VRAI B = FAUX C = FAUX |
L'expression naturelle :
| A OU B ET C |
est évaluée comme :
| A OU (B ET C) |
On calcule :
|
B ET C = FAUX ET FAUX = FAUX |
Puis :
|
A OU FAUX = VRAI |
Le résultat est donc :
| VRAI |
Autre groupement possible
Si l'on écrivait :
| (A OU B) ET C |
on obtiendrait :
| (VRAI OU FAUX) ET FAUX |
puis :
|
VRAI ET FAUX = FAUX |
Le résultat serait alors différent.
Cet exemple montre que les parenthèses peuvent modifier la signification complète d'une condition.
Priorité du XOR
Le positionnement du XOR varie davantage selon les systèmes et les langages.
Dans une convention logique fréquente, l'ordre est :
|
ET XOR OU |
Ainsi :
| A OU B XOR C ET D |
peut être interprété comme :
| A OU (B XOR (C ET D)) |
Cependant, certains langages traitent le XOR différemment, notamment lorsqu'il est représenté par un opérateur bit à bit.
Ambiguïté du symbole XOR
Le symbole :
| ^ |
représente souvent le XOR bit à bit dans des langages comme C, C++, C# et Java.
Cependant, dans d'autres contextes, ce symbole peut représenter :
- une puissance ;
- une opération d'ensemble ;
- un opérateur logique particulier.
Il faut donc tenir compte du langage et du type des opérandes.
Implication logique
L'implication :
| A → B |
possède généralement une priorité plus faible que NON, ET et OU.
Ainsi :
| A ET B → C |
est habituellement compris comme :
| (A ET B) → C |
L'implication n'est cependant pas un opérateur natif dans la plupart des langages de programmation courants.
Elle peut être réécrite sous la forme :
| NON A OU B |
Équivalence logique
L'équivalence :
| A ↔ B |
possède généralement une priorité très faible.
Une expression comme :
| A ET B ↔ C OU D |
est typiquement interprétée comme :
| (A ET B) ↔ (C OU D) |
L'équivalence peut être représentée par une comparaison d'égalité lorsque les deux expressions sont booléennes.
Priorité et associativité
La priorité détermine quel opérateur est traité en premier lorsque les opérateurs sont différents.
L'associativité détermine le regroupement lorsque plusieurs opérateurs possèdent la même priorité.
Il s'agit donc de deux notions différentes.
Exemple d'associativité
Considérons :
| A ET B ET C |
Si l'opérateur ET est associatif à gauche, l'expression est regroupée comme :
| (A ET B) ET C |
Si elle était regroupée à droite, elle deviendrait :
| A ET (B ET C) |
Dans ce cas, le résultat est identique grâce à la propriété d'associativité du ET.
Associativité de ET et OU
Les opérateurs ET et OU sont associatifs en algèbre de Boole :
|
(A ET B) ET C = A ET (B ET C) |
et :
|
(A OU B) OU C = A OU (B OU C) |
Le regroupement ne modifie donc pas la valeur logique lorsque seul le même opérateur est utilisé.
Associativité du XOR
Le XOR est également associatif :
|
(A XOR B) XOR C = A XOR (B XOR C) |
Il peut donc être appliqué à plusieurs valeurs sans ambiguïté mathématique sur le résultat.
Toutefois, l'ordre d'évaluation peut encore avoir une importance pratique si les opérandes contiennent des appels de fonctions ou des effets secondaires.
Opérateurs non associatifs
Certaines opérations ne peuvent pas être regroupées arbitrairement.
L'implication logique n'est pas associative :
| (A → B) → C |
n'est pas généralement équivalente à :
| A → (B → C) |
Les parenthèses deviennent alors indispensables.
Priorité et ordre réel d'évaluation
La priorité détermine la structure grammaticale de l'expression, mais elle ne garantit pas toujours l'ordre chronologique exact dans lequel les opérandes seront calculés.
Par exemple, dans :
| FonctionA() ET FonctionB() |
la priorité indique que l'opération ET relie les deux résultats.
Toutefois, les règles du langage déterminent :
- quelle fonction est appelée en premier ;
- si la seconde fonction est appelée ;
- si le court-circuit est appliqué.
Évaluation en court-circuit
Avec un ET à court-circuit :
| A ET B |
si :
| A = FAUX |
le résultat final est déjà connu.
L'expression :
| B |
n'est donc pas évaluée.
Avec un OU à court-circuit :
| A OU B |
si :
| A = VRAI |
l'expression B n'est pas évaluée.
Court-circuit et priorité
Considérons :
| A OU B ET C |
Le ET est regroupé en premier :
| A OU (B ET C) |
Cependant, si l'évaluation du OU se fait de gauche à droite avec court-circuit et si :
| A = VRAI |
l'expression complète peut retourner vrai sans évaluer ni B ni C.
Le regroupement syntaxique et l'ordre d'exécution réel doivent donc être distingués.
Exemple de protection contre une valeur nulle
|
Objet ≠ NUL ET Objet.EstValide() |
La comparaison est évaluée en premier en raison de la priorité de l'opérateur de comparaison sur le ET logique dans la plupart des langages.
Si l'objet est nul, la seconde partie n'est pas évaluée grâce au court-circuit.
Cela évite un accès invalide.
Opérateur ET sans court-circuit
Certains langages distinguent :
- un ET avec court-circuit ;
- un ET évaluant toujours les deux opérandes.
Par exemple, selon le langage :
| A && B |
peut utiliser le court-circuit, tandis que :
| A & B |
peut évaluer systématiquement les deux côtés.
Ces opérateurs peuvent également posséder des niveaux de priorité différents.
Opérateur OU sans court-circuit
De façon similaire :
| A || B |
emploie généralement le court-circuit dans plusieurs langages.
L'opérateur :
| A | B |
peut évaluer les deux opérandes et servir également d'opérateur bit à bit.
La différence ne concerne donc pas seulement les performances, mais aussi les éventuels effets secondaires.
Priorité des comparaisons
Les expressions booléennes contiennent souvent des comparaisons :
| Âge >= 18 ET CompteActif |
La comparaison :
| Âge >= 18 |
doit produire une valeur booléenne avant que le ET puisse combiner cette valeur avec :
| CompteActif |
L'expression est donc comprise comme :
| (Âge >= 18) ET CompteActif |
Comparaisons et égalité
Considérons :
| A = B ET C = D |
Dans une notation où `=` représente la comparaison, cette expression est généralement comprise comme :
| (A = B) ET (C = D) |
Les deux comparaisons sont évaluées avant la conjonction.
Il est toutefois préférable d'ajouter les parenthèses pour rendre cette intention évidente.
Comparaisons chaînées
Certains langages autorisent une écriture comme :
| 0 < x < 10 |
et l'interprètent comme :
| 0 < x ET x < 10 |
D'autres langages évaluent d'abord :
| 0 < x |
puis comparent le résultat booléen avec `10`, ou refusent simplement l'expression.
Il ne faut donc pas supposer que les comparaisons chaînées sont portables entre les langages.
Priorité des opérateurs arithmétiques
Les expressions booléennes peuvent contenir des calculs arithmétiques.
Par exemple :
| A + B > C ET D |
L'ordre courant est :
- Addition
- Comparaison
- ET logique
L'expression devient donc :
| ((A + B) > C) ET D |
Exemple arithmétique et booléen
Considérons :
| x + 2 > y ET compteActif |
L'ordre conceptuel est :
- Calculer x + 2
- Comparer le résultat avec y
- Combiner la comparaison avec compteActif
Une écriture explicite serait :
| ((x + 2) > y) ET compteActif |
Ordre général dans une expression mixte
Dans de nombreux langages, l'ordre général ressemble à ceci :
- Parenthèses
- Accès aux membres et appels
- Opérateurs arithmétiques unaires
- Multiplication, division et modulo
- Addition et soustraction
- Décalages de bits
- Comparaisons
- Égalité et inégalité
- Opérateurs bit à bit
- Opérateurs logiques
- Opérateur conditionnel
- Affectation
Cet ordre varie selon les langages et ne doit pas être considéré comme universel.
Opérateurs logiques et bit à bit
Les opérateurs logiques travaillent sur des valeurs interprétées comme vraies ou fausses.
Les opérateurs bit à bit travaillent séparément sur chaque bit d'une valeur numérique.
Par exemple :
| A && B |
peut représenter un ET logique, tandis que :
| A & B |
peut représenter un ET bit à bit.
Leur priorité peut être différente.
Exemple de piège avec les bits
Considérons une expression de style C :
| x & masque == valeur |
L'intention peut être :
| (x & masque) == valeur |
Cependant, selon les règles de priorité du langage, elle peut être interprétée comme :
| x & (masque == valeur) |
Il est donc essentiel d'utiliser des parenthèses dans les expressions combinant opérations bit à bit et comparaisons.
Affectation et comparaison
Dans plusieurs langages, l'affectation possède une priorité très faible.
Par exemple :
| Résultat = A ET B |
est généralement interprété comme :
| Résultat = (A ET B) |
Le résultat de l'expression logique est d'abord calculé, puis affecté à la variable.
Piège de l'affectation dans une condition
Dans certains langages, l'écriture :
| SI x = 5 |
peut représenter une affectation plutôt qu'une comparaison.
La comparaison peut nécessiter :
| x == 5 |
Une erreur de symbole peut donc produire une condition incorrecte ou modifier accidentellement la valeur de la variable.
Opérateur conditionnel
Certains langages possèdent un opérateur conditionnel :
| Condition ? ValeurSiVrai : ValeurSiFaux |
La condition logique est évaluée avant le choix de l'une des deux valeurs.
Par exemple :
|
message = compteActif ? "Actif" : "Inactif" |
L'affectation possède généralement une priorité inférieure à celle de l'opérateur conditionnel.
Priorité dans la logique mathématique
En logique propositionnelle, une convention fréquente est :
|
¬ ∧ ∨ → ↔ |
Cela signifie que :
| ¬A ∧ B ∨ C → D ↔ E |
est généralement compris selon une structure proche de :
| ((((¬A) ∧ B) ∨ C) → D) ↔ E |
Une telle expression reste toutefois difficile à lire sans parenthèses.
Priorité dans les langages de programmation
Les langages de programmation ne suivent pas tous exactement la convention mathématique.
Ils ajoutent notamment :
- les comparaisons ;
- les affectations ;
- les opérateurs bit à bit ;
- les opérateurs conditionnels ;
- les appels de fonctions ;
- les conversions de types ;
- les opérateurs spécifiques au langage.
La priorité doit donc être étudiée dans le contexte du langage utilisé.
Priorité en Pascal et Delphi
Dans Pascal et Delphi, les opérateurs logiques textuels comprennent notamment :
- not
- and
- or
- xor
Une hiérarchie simplifiée courante est :
- not
- and
- or et xor
Cependant, les opérateurs Pascal peuvent aussi être utilisés sur des entiers comme opérations bit à bit.
Les comparaisons et les opérations arithmétiques présentes dans la même expression nécessitent une attention particulière.
Exemple en Pascal
- Autoriser :=
- CompteActif
- and MotDePasseValide
- or EstAdministrateur;
Cette expression est généralement comprise comme :
- Autoriser :=
- (CompteActif and MotDePasseValide)
- or EstAdministrateur;
Une écriture avec parenthèses reste préférable.
Priorité en C
Le langage C distingue notamment :
- !
pour la négation logique,
- &&
pour le ET logique à court-circuit,
et :
- ||
pour le OU logique à court-circuit.
L'ordre correspondant est :
- !
- &&
- ||
Les opérateurs bit à bit :
- &
- ^
- |
possèdent des niveaux distincts et s'insèrent entre les comparaisons et les opérateurs logiques dans la hiérarchie générale.
Exemple en C
- bool autoriser =
- compte_actif
- && mot_de_passe_valide
- || administrateur;
Cette expression est comprise comme :
- bool autoriser =
- (compte_actif && mot_de_passe_valide)
- || administrateur;
Même si les parenthèses ne sont pas obligatoires, elles rendent la règle métier plus visible.
Priorité en C++
C++ reprend largement l'ordre de priorité hérité du langage C.
Les opérateurs logiques courants sont :
- !
- &&
- ||
Les mots alternatifs suivants peuvent également être utilisés :
- not
- and
- or
Ils possèdent la même signification et la même priorité que leurs équivalents symboliques.
Priorité en Java
Java utilise notamment :
- !
- &&
- ||
pour les opérations logiques principales.
Il possède aussi :
- &
- ^
- |
qui peuvent être utilisés avec des booléens sans court-circuit ou comme opérateurs bit à bit avec des entiers.
L'ordre simplifié est généralement :
- !
- &
- ^
- |
- &&
- ||
Les opérateurs de comparaison et d'égalité s'insèrent également dans cette hiérarchie.
Exemple en Java
- boolean autoriser =
- compteActif
- && motDePasseValide
- || administrateur;
L'expression est interprétée comme :
- boolean autoriser =
- (compteActif && motDePasseValide)
- || administrateur;
Priorité en C#
C# utilise également :
- !
- &&
- ||
ainsi que :
- &
- ^
- |
pour les opérations booléennes sans court-circuit et les opérations bit à bit.
L'opérateur :
- ??
de coalescence nulle et les opérateurs conditionnels ajoutent d'autres niveaux de priorité propres au langage.
Il est recommandé de parenthéser les expressions combinant valeurs nullables et logique booléenne.
Priorité en Visual Basic
Visual Basic propose notamment :
- Not
- And
- AndAlso
- Or
- OrElse
- Xor
AndAlso et OrElse utilisent le court-circuit.
Une hiérarchie logique simplifiée place généralement :
- Not
avant :
- And / AndAlso
eux-mêmes placés avant :
- Or / OrElse / Xor
La documentation de la version utilisée doit être consultée pour les expressions plus complexes.
Exemple en Visual Basic
- Autoriser =
- CompteActif AndAlso
- MotDePasseValide OrElse
- EstAdministrateur
Cette expression est normalement regroupée comme :
- Autoriser =
- (CompteActif AndAlso MotDePasseValide) OrElse
- EstAdministrateur
Priorité en Python
Python utilise les opérateurs textuels :
- not
- and
- or
Leur ordre de priorité est :
- not
- and
- or
Ainsi :
- not a and b or c
est compris comme :
- ((not a) and b) or c
Comparaisons en Python
Les comparaisons sont évaluées avant :
- not
- and
- or
Par exemple :
- age >= 18 and compte_actif
signifie :
- (age >= 18) and compte_actif
Python permet également les comparaisons chaînées :
- 0 <= age < 120
Priorité en JavaScript
JavaScript utilise notamment :
- !
- &&
- ||
Il possède aussi l'opérateur de coalescence nulle :
- ??
Certaines combinaisons entre `??`, `&&` et `||` nécessitent explicitement des parenthèses.
JavaScript possède également de nombreuses conversions implicites qui peuvent influencer le résultat d'une expression logique.
Exemple en JavaScript
- const autoriser =
- compteActif
- && motDePasseValide
- || administrateur;
Cette expression est interprétée comme :
- const autoriser =
- (compteActif && motDePasseValide)
- || administrateur;
Résultats non strictement booléens
Dans certains langages comme JavaScript et Python, les opérateurs `and`, `or`, `&&` ou `||` peuvent retourner l'un des opérandes plutôt qu'une valeur strictement booléenne.
Par exemple, une expression peut servir à sélectionner une valeur par défaut.
Cette propriété dépasse l'algèbre de Boole classique et nécessite de comprendre les règles propres au langage.
Exemple conceptuel de sélection
| NomAffiché ← NomSaisi OU "Anonyme" |
Dans certains langages dynamiques, cette expression peut retourner :
- NomSaisi s'il est considéré comme vrai ;
- "Anonyme" dans le cas contraire.
Le OU ne produit alors pas nécessairement un booléen littéral.
Expressions longues
Une expression longue peut devenir difficile à interpréter même lorsque toutes les règles de priorité sont connues.
Par exemple :
| NON A ET B OU C ET D XOR E OU F |
Une écriture parenthésée est plus claire :
|
( (NON A) ET B ) OU ( (C ET D) XOR E ) OU F |
La forme exacte doit refléter l'intention réelle de l'algorithme.
Décomposition en variables intermédiaires
Une condition complexe peut être décomposée.
Au lieu de :
|
SI UtilisateurConnecté ET CompteActif ET NON CompteSuspendu ET ( EstAdministrateur OU PossèdePermission ) ALORS |
on peut écrire :
|
CompteUtilisable ← CompteActif ET NON CompteSuspendu PossèdeAccès ← EstAdministrateur OU PossèdePermission Autoriser ← UtilisateurConnecté ET CompteUtilisable ET PossèdeAccès |
Cette écriture réduit la dépendance envers la mémorisation des priorités.
Parenthèses redondantes
Des parenthèses peuvent être techniquement inutiles tout en améliorant la lisibilité.
Par exemple :
| (A ET B) OU C |
est généralement équivalent à :
| A ET B OU C |
Cependant, la première forme montre immédiatement que `A` et `B` constituent un groupe logique.
Trop de parenthèses
Un nombre excessif de parenthèses peut également nuire à la lisibilité.
| ((((A) ET (B))) OU ((C))) |
peut être simplifié en :
| (A ET B) OU C |
L'objectif consiste à rendre la structure évidente sans surcharger inutilement l'expression.
Parenthèses de sécurité
Les parenthèses sont particulièrement recommandées lorsque l'expression combine :
- des opérations booléennes différentes ;
- des opérations bit à bit ;
- des comparaisons ;
- des affectations ;
- des valeurs nullables ;
- des appels de fonctions ;
- des opérateurs conditionnels ;
- des effets secondaires.
Elles servent alors autant de documentation que de mécanisme syntaxique.
Erreur de regroupement
Supposons que la règle désirée soit :
|
Le compte doit être actif, et l'utilisateur doit être administrateur ou responsable. |
L'expression correcte est :
|
CompteActif ET ( EstAdministrateur OU EstResponsable ) |
Sans parenthèses :
|
CompteActif ET EstAdministrateur OU EstResponsable |
elle est généralement interprétée comme :
|
( CompteActif ET EstAdministrateur ) OU EstResponsable |
Un responsable pourrait alors être autorisé même si son compte est inactif.
Conséquence en sécurité
Une erreur de priorité dans une condition d'autorisation peut provoquer :
- un accès non autorisé ;
- un contournement de permission ;
- une divulgation de données ;
- une modification interdite ;
- une vulnérabilité de sécurité.
Les conditions de sécurité doivent donc être explicitement regroupées et accompagnées de tests.
Exemple d'autorisation correcte
|
CompteUtilisable ← CompteActif ET NON CompteSuspendu RôleAutorisé ← EstAdministrateur OU EstResponsable AccèsAutorisé ← UtilisateurAuthentifié ET CompteUtilisable ET RôleAutorisé |
Cette décomposition réduit le risque d'erreur d'interprétation.
Tables de vérité et priorité
Une table de vérité permet de comparer deux groupements différents.
Considérons :
| F1 = A OU (B ET C) |
et :
| F2 = (A OU B) ET C |
| A | B | C | A OU (B ET C) | (A OU B) ET C |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 1 | 0 | 0 |
| 0 | 1 | 0 | 0 | 0 |
| 0 | 1 | 1 | 1 | 1 |
| 1 | 0 | 0 | 1 | 0 |
| 1 | 0 | 1 | 1 | 1 |
| 1 | 1 | 0 | 1 | 0 |
| 1 | 1 | 1 | 1 | 1 |
Les différences apparaissent notamment lorsque :
|
A = 1 C = 0 |
Analyse pas à pas
Pour analyser une expression booléenne, on peut suivre cette méthode :
- Identifier les parenthèses
- Repérer les opérateurs unaires
- Évaluer les calculs arithmétiques
- Évaluer les comparaisons
- Appliquer les opérateurs booléens
- Respecter l'associativité
- Tenir compte du court-circuit
- Vérifier le résultat
Cette méthode évite d'évaluer l'expression uniquement de gauche à droite.
Algorithme conceptuel
|
MODULE ÉvaluerExpressionBooléenne(Expression) Résoudre les parenthèses les plus internes Appliquer les opérateurs unaires Calculer les expressions arithmétiques Évaluer les comparaisons Appliquer ET Appliquer XOR Appliquer OU Appliquer implication et équivalence RETOURNER résultat |
L'ordre exact doit être adapté aux règles du langage concerné.
Arbre syntaxique
Une expression peut être représentée sous la forme d'un arbre syntaxique.
Pour :
| A OU B ET C |
l'arbre possède le OU à la racine :
|
OU / \ A ET / \ B C |
Cette structure montre que :
| B ET C |
constitue une sous-expression évaluée avant d'être combinée avec A.
Arbre avec parenthèses
Pour :
| (A OU B) ET C |
l'arbre devient :
|
ET / \ OU C / \ A B |
Les parenthèses modifient donc directement la structure syntaxique de l'expression.
Analyse par compilateur
Un compilateur ou un interpréteur transforme généralement l'expression en une structure syntaxique selon :
- la grammaire du langage ;
- la priorité des opérateurs ;
- leur associativité ;
- les parenthèses explicites.
Cette structure détermine ensuite la génération du code ou l'évaluation de l'expression.
Ordre de priorité personnalisé
Certains langages permettent de définir ou de surcharger des opérateurs.
La priorité reste généralement attachée au symbole utilisé et ne peut pas être modifiée librement.
Un opérateur surchargé conserve donc habituellement la priorité syntaxique de son symbole, même si sa signification fonctionnelle change.
Langages sans priorité implicite complexe
Certains langages ou notations évitent les règles de priorité traditionnelles.
Ils peuvent exiger :
- des parenthèses explicites ;
- une notation préfixée ;
- une notation postfixée ;
- des appels de fonctions.
Par exemple, en notation fonctionnelle :
| OU(A, ET(B,C)) |
le regroupement est directement visible.
Notation préfixée
En notation préfixée :
| OU A ET B C |
l'opérateur apparaît avant ses opérandes.
Avec une syntaxe correctement définie, l'ordre peut être déterminé sans les mêmes règles de priorité que dans la notation infixée.
Notation postfixée
En notation postfixée :
| A B C ET OU |
les opérateurs apparaissent après leurs opérandes.
Cette notation est utilisée dans certaines machines à pile, calculatrices et représentations intermédiaires.
Conversion en notation postfixée
L'expression :
| A OU B ET C |
est d'abord comprise comme :
| A OU (B ET C) |
Sa forme postfixée devient :
| A B C ET OU |
Le ET est appliqué à `B` et `C`, puis le OU combine le résultat avec `A`.
Tests unitaires des priorités
Les expressions complexes devraient être accompagnées de tests couvrant :
- toutes les valeurs limites ;
- les combinaisons de rôles ;
- les états actifs et inactifs ;
- les valeurs nulles ;
- les cas où le court-circuit doit intervenir.
Les tests permettent de vérifier que le regroupement correspond réellement à la règle métier.
Exemple de cas de test
Pour la condition :
|
CompteActif ET ( EstAdministrateur OU EstResponsable ) |
il faut notamment tester :
| Compte actif | Administrateur | Responsable | Résultat attendu |
|---|---|---|---|
| 0 | 0 | 0 | 0 |
| 0 | 1 | 0 | 0 |
| 0 | 0 | 1 | 0 |
| 1 | 1 | 0 | 1 |
| 1 | 0 | 1 | 1 |
| 1 | 0 | 0 | 0 |
Ces tests détecteraient une expression mal parenthésée.
Formatage des expressions
Une expression complexe peut être répartie sur plusieurs lignes.
|
Autoriser ← UtilisateurAuthentifié ET CompteActif ET NON CompteSuspendu ET ( EstAdministrateur OU EstResponsable ) |
Le retrait visuel permet de représenter la structure logique.
Placement des opérateurs
Deux styles sont courants.
Opérateurs en fin de ligne :
|
A ET B ET C |
Opérateurs en début de ligne :
|
A ET B ET C |
Le choix dépend des conventions du projet, mais il doit rester uniforme.
Documentation des conditions
Une expression ne devrait pas nécessiter un commentaire répétant simplement sa syntaxe.
Un commentaire utile explique plutôt la règle métier :
|
Le compte doit être utilisable et l'utilisateur doit posséder au moins un rôle de gestion. |
Les noms des variables et les parenthèses doivent ensuite refléter cette règle.
Bonnes pratiques
Pour gérer correctement la priorité des opérateurs booléens, il est recommandé de :
- connaître la priorité définie par le langage ;
- ne pas supposer que tous les langages utilisent le même ordre ;
- ajouter des parenthèses lorsque plusieurs opérateurs sont combinés ;
- distinguer priorité, associativité et ordre d'évaluation ;
- tenir compte du court-circuit ;
- éviter de mélanger inutilement logique et opérations bit à bit ;
- décomposer les conditions longues en variables intermédiaires ;
- utiliser des noms de variables exprimant clairement les sous-conditions ;
- tester les combinaisons critiques ;
- parenthéser explicitement les règles de sécurité ;
- consulter la documentation pour les opérateurs moins courants.
Erreurs fréquentes
Les erreurs courantes comprennent :
- évaluer une expression uniquement de gauche à droite ;
- oublier que NON est prioritaire sur ET ;
- oublier que ET est prioritaire sur OU ;
- confondre l'associativité avec la priorité ;
- supposer que XOR possède la même priorité partout ;
- confondre opérateurs logiques et bit à bit ;
- croire que la priorité impose toujours l'ordre chronologique d'évaluation ;
- oublier le court-circuit ;
- introduire des effets secondaires dans les opérandes ;
- omettre les parenthèses dans une condition d'autorisation ;
- mélanger une affectation et une comparaison ;
- supposer que les comparaisons chaînées fonctionnent dans tous les langages.
Tableau récapitulatif
| Notion | Description |
|---|---|
| Priorité | Détermine quel opérateur est regroupé avant les autres |
| Associativité | Détermine le regroupement entre opérateurs de même priorité |
| Parenthèses | Imposent explicitement un regroupement |
| Court-circuit | Peut empêcher l'évaluation d'un opérande |
| Ordre d'évaluation | Détermine l'ordre réel des calculs |
| NON | Généralement prioritaire sur ET et OU |
| ET | Généralement prioritaire sur OU |
| XOR | Priorité variable selon le langage |
| Comparaison | Généralement évaluée avant les opérateurs logiques |
| Affectation | Généralement de priorité faible |
| Opération bit à bit | Possède souvent une priorité différente de la logique |
| Arbre syntaxique | Représente la structure imposée par les priorités |
Exemple complet en pseudocode
|
MODULE PeutModifierDossier(UtilisateurAuthentifié, CompteActif, CompteSuspendu, EstAdministrateur, EstGestionnaire, PossèdePermissionÉcriture) CompteUtilisable ← CompteActif ET NON CompteSuspendu RôleAutorisé ← EstAdministrateur OU EstGestionnaire AutorisationFonctionnelle ← RôleAutorisé OU PossèdePermissionÉcriture Résultat ← UtilisateurAuthentifié ET CompteUtilisable ET AutorisationFonctionnelle RETOURNER Résultat |
Forme condensée équivalente
L'expression précédente peut être condensée sous la forme :
|
UtilisateurAuthentifié ET CompteActif ET NON CompteSuspendu ET ( EstAdministrateur OU EstGestionnaire OU PossèdePermissionÉcriture ) |
Les parenthèses autour des différentes permissions sont essentielles pour que toutes les autorisations exigent un compte actif, non suspendu et authentifié.
Exemple en Java
- public static boolean peutModifierDossier(
- boolean utilisateurAuthentifie,
- boolean compteActif,
- boolean compteSuspendu,
- boolean administrateur,
- boolean gestionnaire,
- boolean permissionEcriture
- ) {
- return utilisateurAuthentifie
- && compteActif
- && !compteSuspendu
- && (
- administrateur
- || gestionnaire
- || permissionEcriture
- );
- }
Analyse de l'exemple Java
La négation :
- !compteSuspendu
est évaluée avant les opérations ET.
Les trois permissions sont regroupées par des parenthèses :
- administrateur
- || gestionnaire
- || permissionEcriture
Le résultat de ce groupe doit ensuite être vrai en même temps que toutes les conditions précédentes.
Exemple en Pascal
- function PeutModifierDossier(
- UtilisateurAuthentifie: Boolean;
- CompteActif: Boolean;
- CompteSuspendu: Boolean;
- Administrateur: Boolean;
- Gestionnaire: Boolean;
- PermissionEcriture: Boolean
- ): Boolean;
- begin
- Result :=
- UtilisateurAuthentifie
- and CompteActif
- and not CompteSuspendu
- and
- (
- Administrateur
- or Gestionnaire
- or PermissionEcriture
- );
- end;
Exemple en Python
Avantages d'une bonne gestion des priorités
Une bonne maîtrise de la priorité des opérateurs permet :
- d'interpréter correctement les expressions booléennes ;
- d'éviter les erreurs de regroupement ;
- de réduire les défauts dans les règles métier ;
- de sécuriser les conditions d'autorisation ;
- d'améliorer la lisibilité des programmes ;
- de comprendre les expressions générées par un compilateur ;
- de distinguer les opérations logiques des opérations bit à bit ;
- de prévoir l'effet du court-circuit ;
- de faciliter les tests et la maintenance ;
- de traduire correctement une formule logique dans un langage de programmation.
Limites et précautions
La priorité des opérateurs comporte plusieurs difficultés :
- l'ordre exact varie selon les langages ;
- un symbole peut avoir plusieurs significations ;
- la priorité ne détermine pas toujours l'ordre chronologique d'évaluation ;
- les effets secondaires peuvent rendre le court-circuit important ;
- les opérateurs surchargés peuvent avoir un comportement inhabituel ;
- les comparaisons chaînées ne sont pas interprétées uniformément ;
- les opérateurs bit à bit peuvent être confondus avec les opérateurs logiques ;
- une expression techniquement correcte peut rester difficile à lire ;
- les parenthèses inutiles sont préférables à une ambiguïté dangereuse, mais leur accumulation excessive peut aussi nuire à la clarté ;
- les règles de priorité ne remplacent pas une bonne décomposition des conditions.
Remarque
La priorité des opérateurs booléens permet au langage de déterminer la structure d'une expression lorsque les parenthèses ne sont pas présentes. La convention la plus courante place la négation avant la conjonction, puis la conjonction avant la disjonction. Cette règle correspond approximativement à la priorité de la multiplication sur l'addition en arithmétique.
La priorité ne doit cependant pas être confondue avec l'associativité, qui détermine le regroupement des opérateurs de même niveau, ni avec l'ordre réel d'évaluation, qui peut être influencé par le court-circuit et les règles propres au langage. Ces distinctions deviennent particulièrement importantes lorsque les expressions contiennent des appels de fonctions, des opérations bit à bit, des valeurs nullables ou des effets secondaires.
Même lorsqu'un programmeur connaît parfaitement les règles de priorité, l'utilisation de parenthèses explicites demeure recommandée dans les conditions complexes. Les parenthèses documentent l'intention, facilitent la maintenance et réduisent les risques d'erreurs, notamment dans les règles de validation, de sécurité et de contrôle d'accès.