La syntaxe du M¶
Programme M et applications¶
Un programme M est formé d’une suite de caractères codés sur 8 bits. Les 128 premiers codes de caractères correspondent aux codes ASCII. Un programme M est constitué d’une suite d’éléments parmi lesquels on compte :
des déclarations d’applications ;
des définitions de constantes ;
des déclarations d’enchaîneurs ;
des définitions de catégories de variables ;
des déclarations de variables ;
des déclarations d’erreurs ;
des déclarations de fonctions externes ;
des définitions de domaines de règles ;
des définitions de domaines de vérifications ;
des déclarations de sorties ;
des règles ;
des vérifications ;
des fonctions ;
des cibles.
Un programme M peut définir plusieurs applications. Pour être traité (compilation, interprétation, etc.), il nécessite la donnée d’une liste d’applications. Cette liste est typiquement fournie comme argument du compilateur, de l’interpréteur ou de tout autre outil de traitement. Cette liste sera appelée la liste des applications sélectionnées.
Définitions liminaires¶
Les formes de Backus-Naur étendues sont utilisées pour préciser la morphologie du langage. Un lexème est une suite de caractères et chaque forme est susceptible d’en reconnaître un ensemble.
Ces formes sont étendues avec les notations suivantes :
<non-terminal:identifiant>représente le non-terminal, pour lequel la chaîne de caractères qu’il reconnaît est représentée par identifiant ;forme 1 ^ … ^ forme nqui représente une suite de lexèmes correspondants aux formes 1 à n, dans n’importe quel ordre;et :
(forme 0) séparateur …qui représente une liste non-vide de lexèmes reeconnus par la forme 0, tous séparés par des lexèmes correspondants au séparateur.
Les lexèmes suivants sont les mots réservés : BOOLEEN, DATE_AAAA, DATE_JJMMAAAA, DATE_MM, ENTIER, REEL, afficher, afficher_erreur, aiguillage, ajouter, alias, alors, anomalie, application, apres, argument, arranger_evenements, attribut, autorise, avec, base, calculable, calculee, calculer, cas, categorie, champ_evenement, cible, const, dans, dans_domaine, discordance, domaine, enchaineur, entre, erreur, espace, espace_variables, et, evenement, evenements, exporte_erreurs, faire, filtrer, finalise_erreurs, finquand, finsi, fonction, increment, indefini, indenter, informative, iterer, leve_erreur, meme_variable, nb_anomalies, nb_bloquantes, nb_categorie, nb_discordances, nb_informatives, neant, nettoie_erreurs, nettoie_erreurs_finalisees, nom, non, numero_compl, numero_verif, ou, par_defaut, pour, puis_quand, quand, reference, regle, restaurer, restituee, resultat, saisie, si, sinon, sinon_si, sortie, specialise, stop, tableau, taille, trier, type, un, valeur variable, verif, verifiable, et verifier.
Les lexèmes numériques sont définis comme suit :
<naturel> ::= [0-9] [0-9 _]*<réel> ::= <naturel> (. <naturel>)?<symbole>est la forme[a-z A-Z 0-9 _]+dont sont exclus<naturel>s et les mots réservés ;<variable>est un<symbole>que l’on distingue pour représenter les mots pouvant prendre le nom d’une constante.
On définit également les atomes numériques, prenant une valeur soit par un nombre littéral, soit par un symbole représentant une constante ou une variable :
<atome naturel> ::= <naturel> | <variable><atome reel> ::= <réel> | <variable>
Les chaînes de caractères littérales ont la forme suivante :
<chaîne> :: = " [^ "]* "
Déclaration une d’application¶
Les déclarations d’applications ont la forme suivante :
application <symbole>;
où <symbole> est le nom de l’application
déclarée.
Définition d’une constante¶
Les définitions de constantes ont la forme suivante :
<symbole> : const = <atome réel> ;
Le symbole est le nom de la constante.
Déclaration d’un enchaîneur¶
Les déclarations d’enchaîneurs ont la forme suivante :
enchaineur <symbole> : <symboles> ;
avec :
<symboles> ::= <symbole> , … représente l’ensemble des applications incluant cet enchaîneur.
Le <symbole> de l’enchaineur est le nom de l’application déclarée.
Définition d’une catégorie de variables¶
Les définitions de catégories de variables ont la forme suivante :
variable (saisie | calculee) <nom> (: attribut <symboles>)? ;
avec :
<nom> ::= <symbole>+est le nom de la catégorie de variables;<symboles> ::= <symbole> , …représente l’ensemble de ses attributs.
Déclaration d’une variable¶
La forme des *types de variables *est comme suit :
<type variable> ::= BOOLEEN | DATE_AAAA | DATE_JJMMAAAA | DATE_MM | ENTIER | REEL
Variable saisie¶
Les déclarations de variables saisies ont la forme suivante :
<symbole> : saisie <catégorie> <attributs> alias <symbole> : <chaîne> type <type variable> ;
avec :
<catégorie> ::= <symbole>+<attributs> ::= <attribut> restituee? <attribut><attribut> ::= <symbole> = <atome naturel>
Le <symbole> est le nom de la variable.
Variable calculée¶
Les déclarations de variables calculées ont la forme suivante :
<symbole>
: (table [ <atome naturel> ])? calculee (base? ^ restituee?)
: <chaîne> type <type variable> ;
Le
Déclaration d’une erreur¶
Les déclarations d’erreurs ont la forme suivante :
<symbole> : <type erreur> : <chaîne> : <chaîne> : <chaîne> : <chaîne> : <chaîne> ;
avec :
<type erreur> ::= anomalie | discordance | informative
Le symbole est le nom de l’erreur.
Déclaration d’une fonction externe¶
Les déclarations de fonctions externes ont la forme suivante :
<symbole> : fonction <atome naturel> ;
Le <symbole> est le nom de la fonction, et l”
Définition d’un domaine de règles¶
Les défintions de domaines de règles ont la forme suivante :
domaine regle <nom> <paramètres> ;
avec :
<nom> ::= <symbole>+est le nom du domaine de règles.`<paramètres> ::= (: specialise
)? ^ (: calculable)? ^ (: par_defaut)? ::= , …` représente l’ensemble des domaines de règles que spécialise ce domaine.
Définition d’un domaine de vérifications¶
Les définitions de domaines de vérifications ont la forme suivante :
domaine verif <nom> <paramètres> ;
avec :
<nom> ::= <symbole>+est le nom domaine de vérifications que spécialise ce domaine.<paramètres> ::= (: specialise <noms>)? ^ (: autorise <catvars>)? ^ (: par_defaut)? ^ (: verifiable)?<noms> ::= <nom> , …<catvars> ::= * | saisie (* | <nom>) | calculee (* | base)?représente les catégories des variables autorisées à êtres utilisées dans les vérifications de ce domaine.
Déclaration d’une sortie¶
Les déclarations de sorties ont la forme suivante :
sortie ( <symbole> ) ;
Indices¶
Les indices ont la forme suivante :
<indices> ::= <indice> ; …
<indice> ::= <minuscule> = <intervalle> , …
avec :
<minuscule> ::= [a-z]<majuscule> ::= [A-Z]<intervalle> ::= <majuscule>+ | <majuscule> .. <majuscule> | <naturel> (.. <naturel> | - <variable>)?
Expressions¶
Les expressions atomiques ont la forme suivante :
<atomique booléen> ::=
( <expression booléenne> )
| <expression numérique> (<= | >= | < | > | != | =) <expression numérique>
| <expression numérique> non? dans ( <intervalles numériques> )
| (present | non_present) ( <symbole> ([ <expression numérique> ])? )
<atomique numérique> ::=
| <expression numerique>
| <atome réel>
| <symbole> [ <expression numérique> ]
| <symbole> ( (<expression numerique> , …)? )
| somme ( <indices> : <expression numerique> )
| si ( <expression boolenne> )
alors ( <expression numerique> )
(( sinon <expression numerique> ))?
finsi
avec :
<expression ou> ::= <expression et> | <expression ou> ou <expression ou><expression et> ::= <expression non> | <expression et> et <expression et><expression non> ::= <atomique booléen> | non <expression non><expression + -> ::= <expression * /> | <expression + -> (+ | -) <expression + -><expression * /> ::= <expression -> | <expression * /> (* | /) <expression * /><expression -> ::= <atomique numérique> | - <expression -><intervalles numériques> ::= <intervalle numérique> , …<intervalle numérique> ::= <expression numérique> (.. <expression numérique>)?
Les formules ont la forme suivante :
<formule> ::=
<symbole> ([ <expression numérique> ])? = <expression numérique>
Les multi-formules ont la forme suivante :
<multi-formule> ::= pour <indices> : <formule>
Instructions¶
Les instructions ont la forme suivante :
<instruction> ::=
<formule>
| <multi-formule>
| si <expression~booléenne>
alors <instruction>+
(sinon <instruction>+)?
finsi
| calculer domaine <symbole>+;
| calculer enchaineur <symbole>;
| calculer cible <symbole>
(: avec <atome~réel> , …)?;
| verifier domaine <symbole>+
(: avec <expression~booléenne>);
| (afficher | afficher__erreur) <affichable>+;
| iterer
: variable <symbole>
: categorie <symbole>+ , …
(: avec <expression~booléenne>)?
: dans ( <instruction>+ )
| restaurer
(
: <symbole> , …
| : variable <symbole> : categorie <symbole>+ , …
(: avec <expression~booléenne>)?
)+
: apres ( <instruction>+ )
| leve__erreur <symbole> <symbole>?;
| (
nettoie__erreurs
| exporte__erreurs
| finalise__erreurs
) ;
| aiguillage (nom)? (<symbole>) : (<multiple_cas>)
| stop <type_stop>?
avec :
<affichable> ::=
<chaîne>
| `*(*` <expression~numérique> `*)*`
(`*:*` <atome~naturel> (`*..*` <atome~naturel>)?)?
| (`*nom*` | `*alias*`) `*(*` <symbole> `*)*`
| `*indenter*` `*(*` <atome~naturel> `*)*`
<multiple cas> ::= <cas>*
<cas> ::=
cas <atome reel> : <instruction>+
| cas indefini : <instruction>+
| cas <symbole> : <instruction>+
| par_default : <instruction>+
<type_stop> ::=
application
| cible
| fonction
| <symbole>
Les instructions simples ont la forme suivante :
<instruction simple> ::=
<formule>
| <multi-formule>
| `*si*` <expression~booléenne>
`*alors*` <instruction~simple>+
(`*sinon*` <instruction~simple>+)?
`*finsi*`
| (`*afficher*` | `*afficher__erreur*`) <affichable>+ `*;*`
Définition d’une règle¶
Les règles ont la forme suivante :
<regle> ::=
regle <symbole>.. <naturel> :
(
application : <symbole> , … ;
^^ (enchaineur : <symbole> , … ;)?
^^ (variable temporaire : <déclaration> , … ;)?
)
<instruction~simple>+
avec :
<déclaration> ::= <symbole> ([ <atome~naturel> ])?
Définition d’une vérification¶
Les vérifications ont la forme suivante :
<vérification> ::=
verif <symbole> <naturel> :
application : <symbole> , … ;
si <expression~booléenne>
alors erreur <symbole> <symbole>?
;
Définition d’une fonction¶
Les fonctions ont la forme suivante :
<fonction> ::=
fonction <symbole> :
(
application : <symbole> , … ;
^^ (variable temporaire : <déclaration> , … ;)?
^^ (argument : <symbole> , … ;)?
^^ resultat : <symbole> ;
)
<instruction~simple>+
avec :
<déclaration> ::= <symbole> ([ <atome~naturel> ])?
Définition d’une cible¶
Les cibles ont la forme suivante :
<cible> ::=
cible <symbole> :
(
application : <symbole> , … ;
^^ (enchaineur : <symbole> , … ;)?
^^ (variable temporaire : <déclaration> , … ;)?
^^ (argument : <symbole> , … ;)?
)
<instruction>+
avec :
<déclaration> ::= <symbole> ([ <atome~naturel> ])?
Commentaires¶
Les commentaires sont précédés du caractère #.
Il est possible d’inclure des commentaires multi-ligne avec les délimiteurs #{ et
}#.
Exemple:
# Ceci est un commentaire sur une ligne
#{ Ceci est un commentaire
sur plusieurs lignes. }#
Les valeurs¶
Les variables en M prennent soit leur valeur sur les flottants, soit ont la
valeur indefini.
Les valeurs de type booléen sont représentées par les flottants 0 et
1, respectivement pour faux et vrai.
Les résultats suivants peuvent être observés en exécutant le script disponible dans l’exemple sur le Calcul des valeurs.
Calcul booléen¶
Les opérations booléennes standard (et, ou, non) comportent sur les
flottants de façon standard.
Toute valeur flottante différente de 0 sera considerée comme vraie dans
le cas d’un calcul booléen (10 ou 0 = 1).
Les calculs booléens impliquant la valeur indefini ont un comportement
spécifique :
indefini ou indefini = indefiniindefini ou b = (0 si b = 0, 1 sinon)b ou indefini = (0 si b = 0, 1 sinon)indefini et indefini = indefinib et indefini = indefiniindefini et b = indefininon indefini = indefini
Les comparaisons (=, <, >, <=, >=) renvoient soit 0 soit 1
lorsque des valeurs definies sont comparées.
Si l’une des valeurs comparée est indéfinie, alors le résultat est également
indefini.
Note: même l’égalité indefini = indefini renvoie indefini.
Pour vérifier si une valeur est définie ou non, il faut utiliser la fonction
present qui renvoie 0 si la valeur est indéfinie et 1 sinon.
Calcul numérique¶
Les opérations arithmétiques standard (+, -, *, /) se comportent sur
les flottants de façon standard, à l’exception de la division d’un flottant par
zero qui renvoie toujours 0.
Les calculs impliquant la valeur indefini ont un comportement spécifique :
indefini + indefini = indefiniindefini + n = nn + indefini = nindefini - indefini = indefiniindefini - n = -nn - indefini = nindefini * indefini = indefiniindefini * n = indefinin * indefini = indefiniindefini / indefini = indefiniindefini / n = indefinin / indefini = indefini
Pour résumer, seules les opérations d’addition et de soustraction avec une
valeur renvoient autre chose que indefini.