From 61acd20d8d698b7e9f7b3802d0326464812742df Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Thu, 13 Nov 2025 17:12:56 +0100 Subject: [PATCH 01/26] Start of a M documentation --- Makefile | 3 ++ source-doc/conf.py | 27 ++++++++++++ source-doc/index.md | 1 + source-doc/index.rst | 23 ++++++++++ source-doc/mlang.rst | 6 +++ source-doc/syntax.rst | 92 +++++++++++++++++++++++++++++++++++++++ source-doc/syntax_irj.rst | 17 ++++++++ 7 files changed, 169 insertions(+) create mode 100644 source-doc/conf.py create mode 100644 source-doc/index.md create mode 100644 source-doc/index.rst create mode 100644 source-doc/mlang.rst create mode 100644 source-doc/syntax.rst create mode 100644 source-doc/syntax_irj.rst diff --git a/Makefile b/Makefile index 755ed41af..5c730aea2 100644 --- a/Makefile +++ b/Makefile @@ -39,3 +39,6 @@ clean: FORCE remise_a_zero_versionnage rm -f doc/doc.html dune clean +sphinx-doc: FORCE + cp -rf source-doc/* _build/default/source-doc/ + sphinx-build -M html _build/default/source-doc/ doc/sphinx/ diff --git a/source-doc/conf.py b/source-doc/conf.py new file mode 100644 index 000000000..be4b329d8 --- /dev/null +++ b/source-doc/conf.py @@ -0,0 +1,27 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = 'MLang' +copyright = '2025, Steven de Oliveira' +author = 'Steven de Oliveira' + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [] + +templates_path = ['_templates'] +exclude_patterns = [] + +language = 'fr' + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = 'alabaster' +html_static_path = ['_static'] diff --git a/source-doc/index.md b/source-doc/index.md new file mode 100644 index 000000000..ea9bdef41 --- /dev/null +++ b/source-doc/index.md @@ -0,0 +1 @@ +# Welcome to MLang's documentation! diff --git a/source-doc/index.rst b/source-doc/index.rst new file mode 100644 index 000000000..770287dde --- /dev/null +++ b/source-doc/index.rst @@ -0,0 +1,23 @@ +.. MLang documentation master file, created by + sphinx-quickstart on Thu Nov 13 14:51:45 2025. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Bienvenue dans la documentation du langage M ! +============================================== + +.. toctree:: + :maxdepth: 2 + :caption: Table des matières: + + syntax + syntax_irj + mlang + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/source-doc/mlang.rst b/source-doc/mlang.rst new file mode 100644 index 000000000..cc713cdc8 --- /dev/null +++ b/source-doc/mlang.rst @@ -0,0 +1,6 @@ +.. _mlang: + +Le compilateur MLang +==================== + +Il y a plein de choses à dire sur MLang diff --git a/source-doc/syntax.rst b/source-doc/syntax.rst new file mode 100644 index 000000000..678cc23ad --- /dev/null +++ b/source-doc/syntax.rst @@ -0,0 +1,92 @@ +.. _syntax_m: + +Le langage M +============ + +Le M basique +------------ + +Un programme M se caracterise par la définition successive : +* de types de variable avec leurs attributs ; +* de domaines et d'événements ; +* d'espaces de variables ; +* d'applications ; +* de variables et de constantes ; +* de règles de calcul associées ou non à une application. + +L'exécution d'un tel programme pour une application donnée correspond à +exécuter l'ensemble des règles de calcul associée la dite application. +.. +L'ordre d'exécution des règles de calcul dépend des dépendances entre les +variables. Si une variable est affectée dans une règle, alors cette règle +sera exécutée avant toutes celles utilisant la valeur de la dite variable. +.. +Si une variable est lue et écrite cycliquement, l'ordre d'exécution des règles +n'est pas garanti. + +Définitions par défaut +---------------------- + +Les types de variables, leurs attributs, les domaines et les événements +sont historiquement des mots clés propres au langage M. +.. +Il est aujourd'hui possible de les définir à la main. + +Aperçu de la syntaxe +-------------------- + +Voici un exemple simple de programme M minimal. + +.. code-block:: + + # Fichier: test.m + + # On définit deux domaines obligatoires: + # * un domaine pour les règles; + # * un domaine pour les vérificateurs. + domaine regle mon_domaine_de_regle: par_defaut; + domaine verif mon_domaine_de_verifications: par_defaut; + + # On définit une ou plusiseurs application pour nos règles. + application mon_application; + + # On définit un espace de variable global dans lequel nos variables + # seront stockées par défaut. + espace_variables GLOBAL : par_defaut; + + # On définit une cible, un ensemble d'instructions à exécuter. + cible hello_world: + application : mon_application; + afficher "Bonjour, monde!\n"; + +Cet exemple jouet n'utilise ni ne définit aucune variable, les domaines +et les espaces de variables ne sont pas utilisés ici mais ils seront nécessaires +plus tard. +.. +Pour essayer notre exemple, nous allons créer un fichier 'test.irj' avec le +contenu suivant : + +.. code-block:: + + #NOM + MON-TEST + #ENTREES-PRIMITIF + #CONTROLES-PRIMITIF + #RESULTATS-PRIMITIF + #ENTREES-CORRECTIF + #CONTROLES-CORRECTIF + #RESULTATS-CORRECTIF + ## + +Le détail de la syntaxe irj peut être sur la page dédiée : :ref:`syntax_irj` + +Enfin, on peut lancer mlang. + .. code-block:: + + $ mlang --without_dfgip_m test.m -A mon_application --mpp_function hello_world --run_test test.irj + Parsing: completed! + Bonjour, monde! + [RESULT] my-examples/m/scratch/fuzzer_1210z.m_test + [RESULT] No failure! + [RESULT] Test passed! + diff --git a/source-doc/syntax_irj.rst b/source-doc/syntax_irj.rst new file mode 100644 index 000000000..cfc554752 --- /dev/null +++ b/source-doc/syntax_irj.rst @@ -0,0 +1,17 @@ + +.. _syntax_irj: + +Les fichiers IRJ +================ + +.. code-block:: + + #NOM + MON-TEST + #ENTREES-PRIMITIF + #CONTROLES-PRIMITIF + #RESULTATS-PRIMITIF + #ENTREES-CORRECTIF + #CONTROLES-CORRECTIF + #RESULTATS-CORRECTIF + ## From bd817d86595ff4430c930f22b4a08e00e673d261 Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Wed, 3 Dec 2025 13:44:00 +0100 Subject: [PATCH 02/26] =?UTF-8?q?D=C3=A9finition=20de=20variables?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 1 + source-doc/arithmetique.md | 3 + source-doc/conf.py | 2 +- source-doc/index.md | 1 - source-doc/index.rst | 1 + source-doc/syntax.md | 143 +++++++++++++++++++++++++++++++++++++ source-doc/syntax.rst | 92 ------------------------ 7 files changed, 149 insertions(+), 94 deletions(-) create mode 100644 source-doc/arithmetique.md delete mode 100644 source-doc/index.md create mode 100644 source-doc/syntax.md delete mode 100644 source-doc/syntax.rst diff --git a/Makefile b/Makefile index 5c730aea2..c6295ecf8 100644 --- a/Makefile +++ b/Makefile @@ -40,5 +40,6 @@ clean: FORCE remise_a_zero_versionnage dune clean sphinx-doc: FORCE + rm -rf _build/default/source-doc/* cp -rf source-doc/* _build/default/source-doc/ sphinx-build -M html _build/default/source-doc/ doc/sphinx/ diff --git a/source-doc/arithmetique.md b/source-doc/arithmetique.md new file mode 100644 index 000000000..2f05a9851 --- /dev/null +++ b/source-doc/arithmetique.md @@ -0,0 +1,3 @@ +(arithmetique)= + +# L'arithmetique en M \ No newline at end of file diff --git a/source-doc/conf.py b/source-doc/conf.py index be4b329d8..8f5b50ebd 100644 --- a/source-doc/conf.py +++ b/source-doc/conf.py @@ -13,7 +13,7 @@ # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration -extensions = [] +extensions = ['myst_parser'] templates_path = ['_templates'] exclude_patterns = [] diff --git a/source-doc/index.md b/source-doc/index.md deleted file mode 100644 index ea9bdef41..000000000 --- a/source-doc/index.md +++ /dev/null @@ -1 +0,0 @@ -# Welcome to MLang's documentation! diff --git a/source-doc/index.rst b/source-doc/index.rst index 770287dde..a1ee95d1b 100644 --- a/source-doc/index.rst +++ b/source-doc/index.rst @@ -13,6 +13,7 @@ Bienvenue dans la documentation du langage M ! syntax syntax_irj mlang + arithmetique Indices and tables diff --git a/source-doc/syntax.md b/source-doc/syntax.md new file mode 100644 index 000000000..95be4b713 --- /dev/null +++ b/source-doc/syntax.md @@ -0,0 +1,143 @@ +(syntax_m)= + +# Le langage M + +## Introduction + +Un programme M se caracterise par la définition successive : +* de types de variable avec leurs attributs ; +* de domaines et d'événements ; +* d'espaces de variables ; +* d'applications ; +* de variables et de constantes ; +* de règles de calcul associées ou non à une application. + +L'exécution d'un tel programme pour une application donnée correspond à +exécuter l'ensemble des règles de calcul associée la dite application. +%% +L'ordre d'exécution des règles de calcul dépend des dépendances entre les +variables. Si une variable est affectée dans une règle, alors cette règle +sera exécutée avant toutes celles utilisant la valeur de la dite variable. +%% +Si une variable est lue et écrite cycliquement, l'ordre d'exécution des règles +n'est pas garanti. + +## Définitions par défaut + +Les types de variables, leurs attributs, les domaines et les événements +sont historiquement des mots clés propres au langage M. +%% +Il est aujourd'hui possible de les définir à la main. + +## Aperçu de la syntaxe + +Voici un exemple simple de programme M minimal. + +``` +# Fichier: test.m + +# On définit un espace de variable global dans lequel nos variables +# seront stockées par défaut. +espace_variables GLOBAL : par_defaut; + +# On définit deux domaines obligatoires: +# * un domaine pour les règles; +# * un domaine pour les vérificateurs. +domaine regle mon_domaine_de_regle: par_defaut; +domaine verif mon_domaine_de_verifications: par_defaut; + +# On définit une ou plusiseurs application pour nos règles. +application mon_application; + +# On définit une cible, un ensemble d'instructions à exécuter. +cible hello_world: +application : mon_application; +afficher "Bonjour, monde!\n"; +``` + +Cet exemple jouet n'utilise ni ne définit aucune variable, les domaines +et les espaces de variables ne sont pas utilisés ici mais ils seront nécessaires +plus tard. +%% +Pour essayer notre exemple, nous allons créer un fichier 'test.irj' avec le +contenu suivant : +%% +``` +#NOM +MON-TEST +#ENTREES-PRIMITIF +#CONTROLES-PRIMITIF +#RESULTATS-PRIMITIF +#ENTREES-CORRECTIF +#CONTROLES-CORRECTIF +#RESULTATS-CORRECTIF +## +``` +Le détail de la syntaxe irj peut être sur la page dédiée : {ref}`syntax_irj` + +Enfin, on peut lancer mlang. + +``` + $ mlang --without_dfgip_m test.m -A mon_application --mpp_function hello_world --run_test test.irj + Parsing: completed! + Bonjour, monde! + [RESULT] my-examples/m/scratch/fuzzer_1210z.m_test + [RESULT] No failure! + [RESULT] Test passed! +``` + +## Définition de variables + +Les variables sont divisées en deux catégories. +* Les variables `saisie`s sont les variables d'entrées du +programme M. +* Les variables `calculee`s sont les variables sur lesquelles seront +calculées les données. + +Chacune de ces catégories principales doivent être dotées d'attributs, +un ensemble d'entiers constants pour une variable donnée. +%% +Ainsi, on peut rajouter à notre programme test les lignes suivantes : +``` +variable saisie : attribut mon_attribut; +variable calculee : attribut mon_attribut; +X : saisie mon_attribut = 0 alias ALIAS_DE_X : "Cette variable s'appelle X"; +Y : calculee mon_attribut = 1 : "Cette variable s'appelle Y"; +``` + +Notez que la variable `X` a un alias `ALIAS_DE_X`. +%% +Toutes les variables saisies doivent être parées d'un alias qui peut être +utilisé de la même façon que son nom original. +%% +Cet alias existe initialement pour faire le lien entre la variable utilisée +dans le M (nom original) et le code de la variable dans le formulaire de +déclaration de l'impot sur le revenu tel qu'on le retrouve aujourd'hui sur +le site de déclaration (1AP, 8TV, ...). + +Ajoutons une nouvelle cible à notre calcul : +``` +cible hello_world2: +application : mon_application; +afficher "Bonjour, monde, X = "; +afficher (X); +afficher " !\n"; +Y = X + 1; +afficher "Y = "; +afficher (Y); +afficher " !\n"; +``` + +Et lançons le calcul : +``` + $ mlang --without_dfgip_m test.m -A mon_application --mpp_function hello_world2 --run_test test.irj +Parsing: completed! +Bonjour, monde, X = indefini ! +Y = 1 ! +[RESULT] fuzzer_1210z.m_test +[RESULT] No failure! +[RESULT] Test passed! +``` + +Pour comprendre la valeur finale de Y, référez-vous à la +section {ref}`arithmetique`. \ No newline at end of file diff --git a/source-doc/syntax.rst b/source-doc/syntax.rst deleted file mode 100644 index 678cc23ad..000000000 --- a/source-doc/syntax.rst +++ /dev/null @@ -1,92 +0,0 @@ -.. _syntax_m: - -Le langage M -============ - -Le M basique ------------- - -Un programme M se caracterise par la définition successive : -* de types de variable avec leurs attributs ; -* de domaines et d'événements ; -* d'espaces de variables ; -* d'applications ; -* de variables et de constantes ; -* de règles de calcul associées ou non à une application. - -L'exécution d'un tel programme pour une application donnée correspond à -exécuter l'ensemble des règles de calcul associée la dite application. -.. -L'ordre d'exécution des règles de calcul dépend des dépendances entre les -variables. Si une variable est affectée dans une règle, alors cette règle -sera exécutée avant toutes celles utilisant la valeur de la dite variable. -.. -Si une variable est lue et écrite cycliquement, l'ordre d'exécution des règles -n'est pas garanti. - -Définitions par défaut ----------------------- - -Les types de variables, leurs attributs, les domaines et les événements -sont historiquement des mots clés propres au langage M. -.. -Il est aujourd'hui possible de les définir à la main. - -Aperçu de la syntaxe --------------------- - -Voici un exemple simple de programme M minimal. - -.. code-block:: - - # Fichier: test.m - - # On définit deux domaines obligatoires: - # * un domaine pour les règles; - # * un domaine pour les vérificateurs. - domaine regle mon_domaine_de_regle: par_defaut; - domaine verif mon_domaine_de_verifications: par_defaut; - - # On définit une ou plusiseurs application pour nos règles. - application mon_application; - - # On définit un espace de variable global dans lequel nos variables - # seront stockées par défaut. - espace_variables GLOBAL : par_defaut; - - # On définit une cible, un ensemble d'instructions à exécuter. - cible hello_world: - application : mon_application; - afficher "Bonjour, monde!\n"; - -Cet exemple jouet n'utilise ni ne définit aucune variable, les domaines -et les espaces de variables ne sont pas utilisés ici mais ils seront nécessaires -plus tard. -.. -Pour essayer notre exemple, nous allons créer un fichier 'test.irj' avec le -contenu suivant : - -.. code-block:: - - #NOM - MON-TEST - #ENTREES-PRIMITIF - #CONTROLES-PRIMITIF - #RESULTATS-PRIMITIF - #ENTREES-CORRECTIF - #CONTROLES-CORRECTIF - #RESULTATS-CORRECTIF - ## - -Le détail de la syntaxe irj peut être sur la page dédiée : :ref:`syntax_irj` - -Enfin, on peut lancer mlang. - .. code-block:: - - $ mlang --without_dfgip_m test.m -A mon_application --mpp_function hello_world --run_test test.irj - Parsing: completed! - Bonjour, monde! - [RESULT] my-examples/m/scratch/fuzzer_1210z.m_test - [RESULT] No failure! - [RESULT] Test passed! - From 743ce198f17fd1b68151afbe75c673ca8e852c85 Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Wed, 3 Dec 2025 16:06:01 +0100 Subject: [PATCH 03/26] Arith --- source-doc/arithmetique.md | 40 +++++++++++++++++++++++++++++++++++++- source-doc/syntax.md | 7 ++++--- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/source-doc/arithmetique.md b/source-doc/arithmetique.md index 2f05a9851..7f66f5d32 100644 --- a/source-doc/arithmetique.md +++ b/source-doc/arithmetique.md @@ -1,3 +1,41 @@ (arithmetique)= -# L'arithmetique en M \ No newline at end of file +# L'arithmetique en M + +Les variables en M prennent soit leur valeur sur les flottants, soit ont la +valeur `indefini`. +%% +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 = indefini` +* `indefini + n = n` +* `n + indefini = n` +* `indefini - indefini = indefini` +* `indefini - n = -n` +* `n - indefini = n` +* `indefini * indefini = indefini` +* `indefini * n = indefini` +* `n * indefini = indefini` +* `indefini / indefini` = indefini` +* `indefini / n` = indefini` +* `n / indefini = indefini` + +Pour résumer, seules les opérations d'addition et de soustraction avec une +valeur renvoient autre chose que `indefini`. +%% + +Les comparaisons (=, <, >, ...) renvoient soit `0` soit `1` lorsque des +valeurs definies sont comparées. +% +Toutes les les opérations booléennes renvoient `indefini` si un de ses +membres est `indefini` (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. + diff --git a/source-doc/syntax.md b/source-doc/syntax.md index 95be4b713..2e894241b 100644 --- a/source-doc/syntax.md +++ b/source-doc/syntax.md @@ -81,7 +81,7 @@ Enfin, on peut lancer mlang. $ mlang --without_dfgip_m test.m -A mon_application --mpp_function hello_world --run_test test.irj Parsing: completed! Bonjour, monde! - [RESULT] my-examples/m/scratch/fuzzer_1210z.m_test + [RESULT] test.irj [RESULT] No failure! [RESULT] Test passed! ``` @@ -134,10 +134,11 @@ Et lançons le calcul : Parsing: completed! Bonjour, monde, X = indefini ! Y = 1 ! -[RESULT] fuzzer_1210z.m_test +[RESULT] test.irj [RESULT] No failure! [RESULT] Test passed! ``` Pour comprendre la valeur finale de Y, référez-vous à la -section {ref}`arithmetique`. \ No newline at end of file +section {ref}`arithmetique`. + From 0bcaa63f493e688be7d9c13198ef0594294e92f8 Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Fri, 5 Dec 2025 18:03:30 +0100 Subject: [PATCH 04/26] More syntax info --- source-doc/syntax.md | 64 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/source-doc/syntax.md b/source-doc/syntax.md index 2e894241b..e7f9f6faf 100644 --- a/source-doc/syntax.md +++ b/source-doc/syntax.md @@ -5,11 +5,12 @@ ## Introduction Un programme M se caracterise par la définition successive : -* de types de variable avec leurs attributs ; +* de types de variables avec leurs attributs ; * de domaines et d'événements ; * d'espaces de variables ; * d'applications ; * de variables et de constantes ; +* des fonctions ; * de règles de calcul associées ou non à une application. L'exécution d'un tel programme pour une application donnée correspond à @@ -43,7 +44,7 @@ espace_variables GLOBAL : par_defaut; # On définit deux domaines obligatoires: # * un domaine pour les règles; # * un domaine pour les vérificateurs. -domaine regle mon_domaine_de_regle: par_defaut; +domaine regle mon_domaine_de_regle: par_defaut: calculable; domaine verif mon_domaine_de_verifications: par_defaut; # On définit une ou plusiseurs application pour nos règles. @@ -142,3 +143,62 @@ Y = 1 ! Pour comprendre la valeur finale de Y, référez-vous à la section {ref}`arithmetique`. +## Règles de calcul + +Les règles en M sont des unités de calcul de variables associées à une ou +plusieurs application et optionnellement à un domaine de règles. +%% +Elles sont composées d'une successions d'affectations. +%% +Voici la définition de deux règles simples que nous rajoutons à notre fichier test : +``` +Z : calculee mon_attribut = 1 : "Cette variable s'appelle Z"; + +regle mon_domaine_de_regles 1: +application : mon_application; +Z = Y + 1; + +regle 2: +application : mon_application; +Y = X + 1; +``` + +La première règle est associée au domaine `mon_domaine_de_regles` tandis que la +seconde n'étant pas spécifié, sera associée au domaine de règle par défaut. +%% +Dans notre exemple, il s'agissait également de `mon_domaine_de_regles`. + +Le calcul d'un domaine correspond au calcul de l'ensemble de ses règles. +%% +L'ordre d'application des règles dépend de l'ordre d'affectation des variables. +%% +Dans notre cas, `X` est une entrée dont `Y` dépend (règle 2), et `Z` dépend de +`Y`. +%% +Par conséquent, la règle 2 sera appliquée avant la règle 1. +%% +On peut ainsi rajouter une cible qui calcule le domaine de règles : +``` +cible calc_test: +application : mon_application; +calculer domaine mon_domaine_de_regles; +afficher "X = "; +afficher (X); +afficher "\nY = "; +afficher (Y); +afficher "\nZ = "; +afficher (Z); +afficher "\n"; +``` + +Et lancer le calcul : +``` + $ mlang --without_dfgip_m test.m -A mon_application --mpp_function calc_test --run_test test.irj + Parsing: completed! + X = indefini + Y = 1 + Z = 2 + [RESULT] test.irj + [RESULT] No failure! + [RESULT] Test passed! +``` \ No newline at end of file From 05cac915bab921888fe20e0a07603d6c8da358dd Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Tue, 9 Dec 2025 10:55:18 +0100 Subject: [PATCH 05/26] Minimal doc for IRJ files --- source-doc/syntax_irj.md | 32 ++++++++++++++++++++++++++++++++ source-doc/syntax_irj.rst | 17 ----------------- 2 files changed, 32 insertions(+), 17 deletions(-) create mode 100644 source-doc/syntax_irj.md delete mode 100644 source-doc/syntax_irj.rst diff --git a/source-doc/syntax_irj.md b/source-doc/syntax_irj.md new file mode 100644 index 000000000..940f9bc23 --- /dev/null +++ b/source-doc/syntax_irj.md @@ -0,0 +1,32 @@ +(syntax_irj)= + +# Les fichiers IRJ + +Les fichiers IRJ sont des fichiers de test faisant corespondre entrées et +sorties du calcul d'un programme M. +%% +Il sont divisés en 7 parties. + +* `NOM` : le nom du test. +* `ENTREES-PRIMITIF` : les valeurs des variables d'entrées au début du calcul. A chaque variable `VAR` est associée une valeur `val` entière ou décimale sur une ligne de la forme `VAR/val`. Les variables d'entrées qui ne sont pas définies dans le fichier IRJ seront initialisées à `indefini`. +* `CONTROLES-PRIMITIF` : à documenter +* `RESULTATS-PRIMITIF` : les valeurs des variables restituées à la fin du calcul. Comme pour les variables d'entrées, elles sont décrites sous la forme `VAR/val`. Les valeurs restituées absentes du fichiers IRJ sont supposées avoir la valeur `indefini` à la fin du calcul. +* `ENTREES-CORRECTIF` : à documenter +* `CONTROLES-CORRECTIF` : à documenter +* `RESULTATS-CORRECTIF` : à documenter + +Voici un exemple de fichier IRJ minimal +``` + #NOM + MON-TEST + #ENTREES-PRIMITIF + X/0.0 + #CONTROLES-PRIMITIF + #RESULTATS-PRIMITIF + Y/1 + Z/2.0 + #ENTREES-CORRECTIF + #CONTROLES-CORRECTIF + #RESULTATS-CORRECTIF + ## +``` diff --git a/source-doc/syntax_irj.rst b/source-doc/syntax_irj.rst deleted file mode 100644 index cfc554752..000000000 --- a/source-doc/syntax_irj.rst +++ /dev/null @@ -1,17 +0,0 @@ - -.. _syntax_irj: - -Les fichiers IRJ -================ - -.. code-block:: - - #NOM - MON-TEST - #ENTREES-PRIMITIF - #CONTROLES-PRIMITIF - #RESULTATS-PRIMITIF - #ENTREES-CORRECTIF - #CONTROLES-CORRECTIF - #RESULTATS-CORRECTIF - ## From 33b3c6317a5858766a3e7a6780d3c812f166cf18 Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Tue, 9 Dec 2025 12:11:29 +0100 Subject: [PATCH 06/26] Documentation de l'utilisation des fichiers IRJ --- source-doc/syntax_irj.md | 64 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/source-doc/syntax_irj.md b/source-doc/syntax_irj.md index 940f9bc23..5da345348 100644 --- a/source-doc/syntax_irj.md +++ b/source-doc/syntax_irj.md @@ -2,10 +2,13 @@ # Les fichiers IRJ +## Syntaxe + Les fichiers IRJ sont des fichiers de test faisant corespondre entrées et sorties du calcul d'un programme M. %% -Il sont divisés en 7 parties. +Il sont divisés en 7 parties, plus 3 parties optionnelles, et est terminé par la +ligne `##`. * `NOM` : le nom du test. * `ENTREES-PRIMITIF` : les valeurs des variables d'entrées au début du calcul. A chaque variable `VAR` est associée une valeur `val` entière ou décimale sur une ligne de la forme `VAR/val`. Les variables d'entrées qui ne sont pas définies dans le fichier IRJ seront initialisées à `indefini`. @@ -14,6 +17,9 @@ Il sont divisés en 7 parties. * `ENTREES-CORRECTIF` : à documenter * `CONTROLES-CORRECTIF` : à documenter * `RESULTATS-CORRECTIF` : à documenter +* `ENTREES-RAPPELS` : partie optionnelle, à documenter +* `CONTROLES-RAPPELS` : partie optionnelle, à documenter +* `RESULTATS-RAPPELS` : partie optionnelle, à documenter Voici un exemple de fichier IRJ minimal ``` @@ -30,3 +36,59 @@ Voici un exemple de fichier IRJ minimal #RESULTATS-CORRECTIF ## ``` + +De nombreux exemples de fichiers IRJ sont disponibles dans le dossier `tests/`. + +## Utilisation + +Trois utilitaires sont dédiés à l'utilisation des fichiers IRJ. + +### IRJ checker + +Les sources de mlang mettent à disposition un code de vérification de fichiers +IRJ. +%% +Après compilation, il peut être exécuté via la commande : +``` +$ dune exec -- irj_checker +``` + +### Interpreteur + +Le binaire mlang intègre un interpreteur de M qui prend en entrée un ou +plusieurs fichiers M ainsi qu'un fichier IRJ. +%% +Après compilation, l'interpreteur peut être exécuté via la commande : +``` +$ dune exec -- mlang test.m -A application -b interpreter --mpp_function cible_dentree --dgfip_options='' -r test.irj +``` + +L'option `-r` peut être remplacée par `-R` pour tester l'ensemble des tests d'un +dossier complet. + +### Fichiers C + +Il est également possible d'utiliser les fichiers IRJ comme entrée du code C +généré à partir d'une compilation de code M par `mlang`. +%% +Ce traitement est effectué dans le cas du backend `dgfip_c` de mlang, dont +le code est disponible dans `examples/dgfip_c/ml_primitif`. +%% +La calculette d'une année donnée peut êter compilée via : +``` +$ make YEAR=year compile_dgfip_c_backend +``` + +Les scripts présents dans `examples/dgfip_c/ml_primitif/ml_driver` permettent +d'interfacer les fichiers IRJ avec les valeurs `C` de type `T_irdata` contenant +le TGV (Tableau Général des Variables). +%% +La commande suivante permet de tester la calculette d'une année sur l'ensemble +des tests fuzzés de la dite année. + +``` +$ make test_dgfip_c_backend +``` + +L'utilisation du script `cal` utilisé dans cette règle est documentée dans +`examples/dgfip_c/README.md`. \ No newline at end of file From f9a58d20177331732c2a82ebbbefd4989a8cf6f5 Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Tue, 9 Dec 2025 17:21:25 +0100 Subject: [PATCH 07/26] =?UTF-8?q?Documentation=20d=C3=A9taill=C3=A9e=20de?= =?UTF-8?q?=20la=20syntaxe=20de=20David?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source-doc/index.rst | 1 + source-doc/intro.md | 204 +++++++++++ source-doc/syntax.md | 789 ++++++++++++++++++++++++++++++++++--------- 3 files changed, 840 insertions(+), 154 deletions(-) create mode 100644 source-doc/intro.md diff --git a/source-doc/index.rst b/source-doc/index.rst index a1ee95d1b..6964150c3 100644 --- a/source-doc/index.rst +++ b/source-doc/index.rst @@ -10,6 +10,7 @@ Bienvenue dans la documentation du langage M ! :maxdepth: 2 :caption: Table des matières: + intro syntax syntax_irj mlang diff --git a/source-doc/intro.md b/source-doc/intro.md new file mode 100644 index 000000000..657b01e0c --- /dev/null +++ b/source-doc/intro.md @@ -0,0 +1,204 @@ +(intro_m)= + +# Introduction au langage M + +## Les éléments de base + +Un programme M se caracterise par la définition successive : +* de types de variables avec leurs attributs ; +* de domaines et d'événements ; +* d'espaces de variables ; +* d'applications ; +* de variables et de constantes ; +* des fonctions ; +* de règles de calcul associées ou non à une application. + +L'exécution d'un tel programme pour une application donnée correspond à +exécuter l'ensemble des règles de calcul associée la dite application. +%% +L'ordre d'exécution des règles de calcul dépend des dépendances entre les +variables. Si une variable est affectée dans une règle, alors cette règle +sera exécutée avant toutes celles utilisant la valeur de la dite variable. +%% +Si une variable est lue et écrite cycliquement, l'ordre d'exécution des règles +n'est pas garanti. + +## Définitions par défaut + +Les types de variables, leurs attributs, les domaines et les événements +sont historiquement des mots clés propres au langage M. +%% +Il est aujourd'hui possible de les définir à la main. + +## Aperçu de la syntaxe + +Voici un exemple simple de programme M minimal. + +``` +# Fichier: test.m + +# On définit un espace de variable global dans lequel nos variables +# seront stockées par défaut. +espace_variables GLOBAL : par_defaut; + +# On définit deux domaines obligatoires: +# * un domaine pour les règles; +# * un domaine pour les vérificateurs. +domaine regle mon_domaine_de_regle: par_defaut: calculable; +domaine verif mon_domaine_de_verifications: par_defaut; + +# On définit une ou plusiseurs application pour nos règles. +application mon_application; + +# On définit une cible, un ensemble d'instructions à exécuter. +cible hello_world: +application : mon_application; +afficher "Bonjour, monde!\n"; +``` + +Cet exemple jouet n'utilise ni ne définit aucune variable, les domaines +et les espaces de variables ne sont pas utilisés ici mais ils seront nécessaires +plus tard. +%% +Pour essayer notre exemple, nous allons créer un fichier 'test.irj' avec le +contenu suivant : +%% +``` +#NOM +MON-TEST +#ENTREES-PRIMITIF +#CONTROLES-PRIMITIF +#RESULTATS-PRIMITIF +#ENTREES-CORRECTIF +#CONTROLES-CORRECTIF +#RESULTATS-CORRECTIF +## +``` +Le détail de la syntaxe irj peut être sur la page dédiée : {ref}`syntax_irj` + +Enfin, on peut lancer mlang. + +``` + $ mlang --without_dfgip_m test.m -A mon_application --mpp_function hello_world --run_test test.irj + Parsing: completed! + Bonjour, monde! + [RESULT] test.irj + [RESULT] No failure! + [RESULT] Test passed! +``` + +## Définition de variables + +Les variables sont divisées en deux catégories. +* Les variables `saisie`s sont les variables d'entrées du +programme M. +* Les variables `calculee`s sont les variables sur lesquelles seront +calculées les données. + +Chacune de ces catégories principales doivent être dotées d'attributs, +un ensemble d'entiers constants pour une variable donnée. +%% +Ainsi, on peut rajouter à notre programme test les lignes suivantes : +``` +variable saisie : attribut mon_attribut; +variable calculee : attribut mon_attribut; +X : saisie mon_attribut = 0 alias ALIAS_DE_X : "Cette variable s'appelle X"; +Y : calculee mon_attribut = 1 : "Cette variable s'appelle Y"; +``` + +Notez que la variable `X` a un alias `ALIAS_DE_X`. +%% +Toutes les variables saisies doivent être parées d'un alias qui peut être +utilisé de la même façon que son nom original. +%% +Cet alias existe initialement pour faire le lien entre la variable utilisée +dans le M (nom original) et le code de la variable dans le formulaire de +déclaration de l'impot sur le revenu tel qu'on le retrouve aujourd'hui sur +le site de déclaration (1AP, 8TV, ...). + +Ajoutons une nouvelle cible à notre calcul : +``` +cible hello_world2: +application : mon_application; +afficher "Bonjour, monde, X = "; +afficher (X); +afficher " !\n"; +Y = X + 1; +afficher "Y = "; +afficher (Y); +afficher " !\n"; +``` + +Et lançons le calcul : +``` + $ mlang --without_dfgip_m test.m -A mon_application --mpp_function hello_world2 --run_test test.irj +Parsing: completed! +Bonjour, monde, X = indefini ! +Y = 1 ! +[RESULT] test.irj +[RESULT] No failure! +[RESULT] Test passed! +``` + +Pour comprendre la valeur finale de Y, référez-vous à la +section {ref}`arithmetique`. + +## Règles de calcul + +Les règles en M sont des unités de calcul de variables associées à une ou +plusieurs application et optionnellement à un domaine de règles. +%% +Elles sont composées d'une successions d'affectations. +%% +Voici la définition de deux règles simples que nous rajoutons à notre fichier test : +``` +Z : calculee mon_attribut = 1 : "Cette variable s'appelle Z"; + +regle mon_domaine_de_regles 1: +application : mon_application; +Z = Y + 1; + +regle 2: +application : mon_application; +Y = X + 1; +``` + +La première règle est associée au domaine `mon_domaine_de_regles` tandis que la +seconde n'étant pas spécifié, sera associée au domaine de règle par défaut. +%% +Dans notre exemple, il s'agissait également de `mon_domaine_de_regles`. + +Le calcul d'un domaine correspond au calcul de l'ensemble de ses règles. +%% +L'ordre d'application des règles dépend de l'ordre d'affectation des variables. +%% +Dans notre cas, `X` est une entrée dont `Y` dépend (règle 2), et `Z` dépend de +`Y`. +%% +Par conséquent, la règle 2 sera appliquée avant la règle 1. +%% +On peut ainsi rajouter une cible qui calcule le domaine de règles : +``` +cible calc_test: +application : mon_application; +calculer domaine mon_domaine_de_regles; +afficher "X = "; +afficher (X); +afficher "\nY = "; +afficher (Y); +afficher "\nZ = "; +afficher (Z); +afficher "\n"; +``` + +Et lancer le calcul : +``` + $ mlang --without_dfgip_m test.m -A mon_application --mpp_function calc_test --run_test test.irj + Parsing: completed! + X = indefini + Y = 1 + Z = 2 + [RESULT] test.irj + [RESULT] No failure! + [RESULT] Test passed! +``` \ No newline at end of file diff --git a/source-doc/syntax.md b/source-doc/syntax.md index e7f9f6faf..ef1572685 100644 --- a/source-doc/syntax.md +++ b/source-doc/syntax.md @@ -1,204 +1,685 @@ -(syntax_m)= +(syntax)= -# Le langage M +# La syntaxe du M -## Introduction +## Morphologie -Un programme M se caracterise par la définition successive : -* de types de variables avec leurs attributs ; -* de domaines et d'événements ; -* d'espaces de variables ; -* d'applications ; -* de variables et de constantes ; -* des fonctions ; -* de règles de calcul associées ou non à une application. +### Programme M et applications -L'exécution d'un tel programme pour une application donnée correspond à -exécuter l'ensemble des règles de calcul associée la dite application. +Un programme M est formé d'une suite de caractères codés sur 8 bits. %% -L'ordre d'exécution des règles de calcul dépend des dépendances entre les -variables. Si une variable est affectée dans une règle, alors cette règle -sera exécutée avant toutes celles utilisant la valeur de la dite variable. +Les 128 premiers codes de caractères correspondent aux codes ASCII. %% -Si une variable est lue et écrite cycliquement, l'ordre d'exécution des règles -n'est pas garanti. +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. -## Définitions par défaut +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. -Les types de variables, leurs attributs, les domaines et les événements -sont historiquement des mots clés propres au langage M. +Ces formes sont étendues avec les notations suivantes : + +* `` 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 n` qui représente une suite de lexèmes correspondants +aux formes 1 à n, dans n'importe quel ordre; %% -Il est aujourd'hui possible de les définir à la main. +* 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**, +**alias**, +**alors**, +**anomalie**, +**application**, +**apres**, +**argument**, +**attribut**, +**autorise**, +**avec**, +**base**, +**calculable**, +**calculee**, +**calculer**, +**categorie**, +**cible**, +**const**, +**dans**, +**discordance**, +**domaine**, +**enchaineur**, +**erreur**, +**et**, +**exporte_erreurs**, +**finsi**, +**finalise_erreurs**, +**fonction**, +**indefini**, +**indenter**, +**informative**, +**iterer**, +**leve_erreur**, +**nb_bloquantes**, +**nb_categorie**, +**nb_anomalies**, +**nb_discordances**, +**nb_informatives**, +**nettoie_erreurs**, +**nom**, +**non**, +**numero_compl**, +**numero_verif**, +**ou**, +**par_defaut**, +**pour**, +**regle**, +**restaurer**, +**restituee**, +**saisie**, +**si**, +**sinon_si**, +**sinon**, +**sortie**, +**specialise**, +**tableau**, +**taille**, +**temporaire**, +**type**, +**un**, +**variable**, +**verif**, +**verifiable**, +et **verifier**. + +Les lexèmes numériques sont définis comme suit : +* ` ::= [0-9] [0-9 _]*` +* ` ::= (. )?` +* `` est la forme [a-z A-Z 0-9 _]+ dont sont exclus `` et +les mots réservés. +* `` est un `` 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 : -## Aperçu de la syntaxe +* ` ::= | ` +* ` ::= | ` -Voici un exemple simple de programme M minimal. +Les chaînes de caractères littérales ont la forme suivante : +* ` :: = " [^ "]* "` +### Déclaration une d'application + +Les *déclarations d'applications* ont la forme suivante : +``` +application ; ``` -# Fichier: test.m -# On définit un espace de variable global dans lequel nos variables -# seront stockées par défaut. -espace_variables GLOBAL : par_defaut; +où est le nom de l'application +déclarée. + +### Définition d'une constante -# On définit deux domaines obligatoires: -# * un domaine pour les règles; -# * un domaine pour les vérificateurs. -domaine regle mon_domaine_de_regle: par_defaut: calculable; -domaine verif mon_domaine_de_verifications: par_defaut; +Les *définitions de constantes* ont la forme suivante : +``` + : const = ; +``` -# On définit une ou plusiseurs application pour nos règles. -application mon_application; +Le symbole est le nom de la constante. -# On définit une cible, un ensemble d'instructions à exécuter. -cible hello_world: -application : mon_application; -afficher "Bonjour, monde!\n"; +### Déclaration d'un enchaîneur +Les *déclarations d'enchaîneurs* ont la forme suivante : +``` +enchaineur : ; ``` -Cet exemple jouet n'utilise ni ne définit aucune variable, les domaines -et les espaces de variables ne sont pas utilisés ici mais ils seront nécessaires -plus tard. -%% -Pour essayer notre exemple, nous allons créer un fichier 'test.irj' avec le -contenu suivant : +avec : +` ::= , …` représente l'ensemble des applications incluant cet enchaîneur. %% +Le `` 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 : ``` -#NOM -MON-TEST -#ENTREES-PRIMITIF -#CONTROLES-PRIMITIF -#RESULTATS-PRIMITIF -#ENTREES-CORRECTIF -#CONTROLES-CORRECTIF -#RESULTATS-CORRECTIF -## +variable (saisie | calculee) (: attribut )? ; ``` -Le détail de la syntaxe irj peut être sur la page dédiée : {ref}`syntax_irj` -Enfin, on peut lancer mlang. +avec : + +* ` ::= +` est le nom de la catégorie de variables; +* ` ::= , …` représente l'ensemble de ses attributs. + +### Déclaration d'une variable + +La forme des *types de variables *est comme suit : ``` - $ mlang --without_dfgip_m test.m -A mon_application --mpp_function hello_world --run_test test.irj - Parsing: completed! - Bonjour, monde! - [RESULT] test.irj - [RESULT] No failure! - [RESULT] Test passed! + ::= BOOLEEN | DATE_AAAA | DATE_JJMMAAAA | DATE_MM | ENTIER | REEL ``` -## Définition de variables +#### Variable saisie -Les variables sont divisées en deux catégories. -* Les variables `saisie`s sont les variables d'entrées du -programme M. -* Les variables `calculee`s sont les variables sur lesquelles seront -calculées les données. +Les *déclarations de variables saisies* ont la forme suivante : -Chacune de ces catégories principales doivent être dotées d'attributs, -un ensemble d'entiers constants pour une variable donnée. -%% -Ainsi, on peut rajouter à notre programme test les lignes suivantes : ``` -variable saisie : attribut mon_attribut; -variable calculee : attribut mon_attribut; -X : saisie mon_attribut = 0 alias ALIAS_DE_X : "Cette variable s'appelle X"; -Y : calculee mon_attribut = 1 : "Cette variable s'appelle Y"; + : saisie alias : type ; ``` -Notez que la variable `X` a un alias `ALIAS_DE_X`. -%% -Toutes les variables saisies doivent être parées d'un alias qui peut être -utilisé de la même façon que son nom original. +avec : + +* ` ::= +` +* ` ::= restituee? ` +* ` ::= = ` + +Le `` est le nom de la variable. + +#### Variable calculée + +Les *déclarations de variables calculées* ont la forme suivante : +``` + +: (table [ ])? calculee (base? ^ restituee?) +: type ; +``` + +Le est le nom de la variable. Si c'est un tableau, l' +est sa taille. + +### Déclaration d'une erreur + +Les *déclarations d'erreurs* ont la forme suivante : +``` + : : : : : : ; +``` +avec : +* ` ::= anomalie | discordance | informative` + +Le symbole est le nom de l'erreur. %% -Cet alias existe initialement pour faire le lien entre la variable utilisée -dans le M (nom original) et le code de la variable dans le formulaire de -déclaration de l'impot sur le revenu tel qu'on le retrouve aujourd'hui sur -le site de déclaration (1AP, 8TV, ...). +% A faire: documenter les s ! + +### Déclaration d'une fonction externe + +Les *déclarations de fonctions* externes ont la forme suivante : + +``` + : fonction ; +``` + +Le `` est le nom de la fonction, et l' son arité. + +### Définition d'un domaine de règles + +Les *défintions de domaines de règles* ont la forme suivante : -Ajoutons une nouvelle cible à notre calcul : ``` -cible hello_world2: -application : mon_application; -afficher "Bonjour, monde, X = "; -afficher (X); -afficher " !\n"; -Y = X + 1; -afficher "Y = "; -afficher (Y); -afficher " !\n"; +domaine regle ; ``` -Et lançons le calcul : +avec : +* ` ::= +` est le nom du domaine de règles. +* ` ::= (: 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 : + ``` - $ mlang --without_dfgip_m test.m -A mon_application --mpp_function hello_world2 --run_test test.irj -Parsing: completed! -Bonjour, monde, X = indefini ! -Y = 1 ! -[RESULT] test.irj -[RESULT] No failure! -[RESULT] Test passed! +domaine verif ; ``` -Pour comprendre la valeur finale de Y, référez-vous à la -section {ref}`arithmetique`. +avec : +* ` ::= +` est le nom domaine de vérifications que spécialise ce domaine. +* ` ::= (: specialise )? ^ (: autorise )? ^ (: par_defaut)? ^ (: verifiable)?` +* ` ::= , …` +* ` ::= * | saisie (* | ) | calculee (* | base)?` représente les catégories des variables autorisées à êtres utilisées dans les vérifications de ce domaine. -## Règles de calcul +### Déclaration d'une sortie -Les règles en M sont des unités de calcul de variables associées à une ou -plusieurs application et optionnellement à un domaine de règles. -%% -Elles sont composées d'une successions d'affectations. -%% -Voici la définition de deux règles simples que nous rajoutons à notre fichier test : +Les *déclarations de sorties* ont la forme suivante : ``` -Z : calculee mon_attribut = 1 : "Cette variable s'appelle Z"; +sortie ( ) ; +``` + +### Indices -regle mon_domaine_de_regles 1: -application : mon_application; -Z = Y + 1; +Les *indices* ont la forme suivante : -regle 2: -application : mon_application; -Y = X + 1; +``` + ::= ; … + ::= = , … ``` -La première règle est associée au domaine `mon_domaine_de_regles` tandis que la -seconde n'étant pas spécifié, sera associée au domaine de règle par défaut. -%% -Dans notre exemple, il s'agissait également de `mon_domaine_de_regles`. +avec : +* ` ::= [a-z]` +* ` ::= [A-Z]` +* ` ::= + | .. | (.. | - )?` -Le calcul d'un domaine correspond au calcul de l'ensemble de ses règles. -%% -L'ordre d'application des règles dépend de l'ordre d'affectation des variables. -%% -Dans notre cas, `X` est une entrée dont `Y` dépend (règle 2), et `Z` dépend de -`Y`. + +### Expressions + +Les *expressions atomiques* ont la forme suivante : + +``` + ::= +( ) +| (<= | >= | < | > | != | =) +| non? dans ( ) +| (present | non_present) ( ([ ])? ) + + ::= +| +| +| [ ] +| ( ( , …)? ) +| somme ( : ) +| si ( ) + alors ( ) + (( sinon ))? + finsi +``` + +avec : +* ` ::= | ou ` +* ` ::= | et ` +* ` ::= | non ` +* ` ::= | (+ | -) ` +* ` ::= | (* | /) ` +* ` ::= | - ` +* ` ::= , …` +* ` ::= (.. )?` + + +Les `formules` ont la forme suivante : +``` + ::= + (`*[*` `*]*`)? `*=*` +``` + +Les `multi-formules` ont la forme suivante : +``` + ::= `*pour*` `*:*` +``` + +### Instructions + +Les *instructions* ont la forme suivante : +``` + ::= + + | + | si + alors + + (sinon +)? + finsi + | calculer domaine +; + | calculer enchaineur ; + | calculer cible + (: avec , …)?; + | verifier domaine + + (: avec ); + | (afficher | afficher__erreur) +; + | iterer + : variable + : categorie + , … + (: avec )? + : dans ( + ) + | restaurer + ( + : , … + | : variable : categorie + , … + (: avec )? + )+ + : apres ( + ) + | leve__erreur ?; + | ( + nettoie__erreurs + | exporte__erreurs + | finalise__erreurs + ) ; + | aiguillage (nom)? () : () + | stop ? +``` + +avec : + +``` + ::= + + | `*(*` `*)*` + (`*:*` (`*..*` )?)? + | (`*nom*` | `*alias*`) `*(*` `*)*` + | `*indenter*` `*(*` `*)*` + + ::= * + + ::= + cas : + + | cas indefini : + + | cas : + + | par_default : + + + ::= + application + | cible + | fonction + | +``` + +Les *instructions simples* ont la forme suivante : + +``` + ::= + + | + | `*si*` + `*alors*` + + (`*sinon*` +)? + `*finsi*` + | (`*afficher*` | `*afficher__erreur*`) + `*;*` +``` + +### Définition d'une règle + +Les *règles* ont la forme suivante : +``` + ::= + regle .. : + ( + application : , … ; + ^^ (enchaineur : , … ;)? + ^^ (variable temporaire : , … ;)? + ) + + +``` + +avec : + +* ` ::= ([ ])?` + +### Définition d'une vérification + +Les *vérifications* ont la forme suivante : + +``` + ::= + verif : + application : , … ; + si + alors erreur ? + ; +``` +### Définition d'une fonction + +Les *fonctions* ont la forme suivante : +``` + ::= + fonction : + ( + application : , … ; + ^^ (variable temporaire : , … ;)? + ^^ (argument : , … ;)? + ^^ resultat : ; + ) + + +``` + +avec : +* ` ::= ([ ])?` + +### Définition d'une cible + +Les *cibles* ont la forme suivante : + +``` + ::= + cible : + ( + application : , … ; + ^^ (enchaineur : , … ;)? + ^^ (variable temporaire : , … ;)? + ^^ (argument : , … ;)? + ) + + +``` + +avec : +* ` ::= ([ ])?` + +## Prétraitement + +Le prétraitement est une opération purement syntaxique. %% -Par conséquent, la règle 2 sera appliquée avant la règle 1. +Son but est triple : +- éliminer les constructions relatives aux applications non--sélectionnées ; +- remplacer les constantes par leur valeur numérique ; +- remplacer les expressions numériques débutant par `*somme*` avec des + additions ; +- éliminer les en les remplaçant par des séries de . + +Toute substitution transformant un programme M syntaxiquement valide en un +texte ne correspondant à aucun programme M provoque l'échec du traitement. + +### Cas des applications + +On élimine du programme M: +- les déclarations des applications non-sélectionnées ; +- les déclarations des enchaîneurs ne spécifiant pas une application + sélectionnée ; +- les déclarations des règles ne spécifiant pas une application + sélectionnée ; +- les déclarations des vérifications ne spécifiant pas une application + sélectionnée ; +- les déclarations des cibles ne spécifiant pas une application sélectionnée. + +Dans les déclarations des règles spécifiant une application sélectionnée, on +élimine les enchaîneurs qui ne sont plus déclarés dans le programme M obtenu. + +### Cas des constantes + +Pour prétraiter un programme, on le parcourt du début à la fin* Pour chaque + rencontrée, si elle correspond à une contante défini précédemment, +alors il est remplacé dans le programme par la valeur numérique correspondante. + +Un intervalle de la forme ~`*-*`~ est +converti par substitution de la constante /const/ en l'intervalle +~`****`~, avec /fin/ le naturel correspondant +à /const/. + +*Exemple* : considérons le programme suivant : +``` +fin : const = 10; +… +pour i = 9..fin : + Bi = Bi + fin; +``` + +Par substitution de la constante `fin`, il est remplacé dans un premier temps +remplacée par le programme : + +``` +fin : const = 10;` +… +pour i = 9..10 : + Bi = Bi + fin; +``` + +puis dans un second temps par le programme : +``` +fin : const = 10; +… +pour i = 9..10 : + Bi = Bi + 10; +``` + +### Interprétation des indices + +Pour rappel, les *indices* ont la forme suivante : +``` + ::= ; … + ::= = , … +``` + +avec : +* ` ::= [a-z]` +* ` ::= [A-Z]` +* ` ::= + | .. | (.. | - )?` + +Chaque `` associe à une lettre minuscule une série de chaînes de +caractères de même taille. %% -On peut ainsi rajouter une cible qui calcule le domaine de règles : -``` -cible calc_test: -application : mon_application; -calculer domaine mon_domaine_de_regles; -afficher "X = "; -afficher (X); -afficher "\nY = "; -afficher (Y); -afficher "\nZ = "; -afficher (Z); -afficher "\n"; -``` - -Et lancer le calcul : -``` - $ mlang --without_dfgip_m test.m -A mon_application --mpp_function calc_test --run_test test.irj - Parsing: completed! - X = indefini - Y = 1 - Z = 2 - [RESULT] test.irj - [RESULT] No failure! - [RESULT] Test passed! -``` \ No newline at end of file +Cette série est composée de la succession de chaque + à droite du symbole `=`. + +Les séries associées aux sont définis comme suit : +* `+` est la série composée de chacune des majuscules prises + séparément, donc de taille 1 (*par exemple* : `AXF` représente la série `A`, `X`, `F`); +* `****` est la série composée de toutes + les majuscules comprises entre /début/ et /fin/, bornes comprises, suivant + l'ordre alphabétique, donc de taille 1 (*par exemple* : `A**D` représente la série `A`, `B`, `C`, `D`); +* `****` est la série composée de tous les + nombres naturels entre /début/ et /fin/, bornes comprises, la taille des + éléments étant égale à la taille du plus grand naturel en base 10; les + naturels trop petits pour avoir la taille requise sont complétés par des 0 à + gauche (*par exemple* : `9**11` représente la série `09`, `10`, `11`); +* ``**`-`**`` est converti lors du prétraitement des constantes + en un intervalle de la forme ``**`..`**``. + +### Cas des expressions `somme(…)` + +Pour une expression numérique +`somme ( : )`, +l'expression *expr* sera remplacée par la somme des expressions construites +ainsi : pour chaque chaîne de caractères de la série introduite par *ind*, les +symboles apparaîssant dans *expr* sont remplacés par ceux dans lesquels la +lettre minuscule de /ind/ est substituéé par la chaine de caractère. +% +La somme ainsi générée est parenthésée. + +Une expression numérique +`somme ( ; : )`, +est remplacée par la somme des expressions +*`somme`*` : expr'> )` avec *expr'* prenant sa valeur +dans la série *sub(ind, expr). +% +La procédure est ensuite appliquée récursivement à cette somme. +% +La somme ainsi générée est parenthésée. +% +Notons que les sous-sommes récursivement produites n'ont pas besoin de l'être +car l'addition est associative. + +On applique cette transformation à toutes les expressions `somme(…)` tant +qu'il en existe dans le programme. + +**Exemple**. Considérons l'expression suivante : + +* `somme(i = XZ ; j = 9..10 : Bi + Bj)` + +Elle est dans un premier temps remplacée par la somme suivante : + +* `(somme(j = 9..10 : BX + Bj) + somme(j = 9..10 : BZ + Bj))` + +puis dans un second temps par la somme : + +* `(BX + B09 + BX + B10 + BZ + B09 + BZ + B10)` + +On remarque que seule l'expression globale est parenthésée car l'addition est +associative. + +### Cas des multi-formules + +On commence par substituer toutes les expressions `somme(…)` apparaissant dans +les multi-formules. +% +Puis on transforme les multi-formules en séries de formules en suivant la +méthode décrite ci-dessous. + +Pour chaque multi-formule rencontrée, de la forme `pour : `, +dès que les constantes apparaîssant dans les ont été substitués, on +remplace cette multi-formule par la série de formules générée de la manière +suivante. + +Pour une multi-formule `pour : `, la +formule `f` sera remplacée par la série des formules construites ainsi : pour +chaque chaîne de caractères de la série introduite par `ind`, les symboles +apparaîssant dans `f` sont remplacés par ceux dans lesquels la lettre +minuscule de `ind` est substituéé par la chaïne de caractère. +% +On notera `sub(ind, f)` la série constituée des formules ainsi régérées. + +Une multi-formule `pour ; : `, +est remplacée par la série des multi-formules +`pour : f'>` avec `f'` prenant sa valeur +dans la série `sub(ind, f)`. +% +La procédure est ensuite appliquée récursivement +à ces multi-formules. + +**Exemple**. Considérons la multi-formule suivante : +``` +pour i = XZ ; j = 9..10 : + Bi = Bi + Bj; +``` + +Elle est dans un premier temps remplacée par la série suivante : +``` +pour j = 9**10 : + BX = BX + Bj; + +pour j = 9**10 : + BZ = BZ + Bj; +``` + +Puis dans un second temps par la série des formules : +``` +BX = BX + B09; +BX = BX + B10; +BZ = BZ + B09; +BZ = BZ + B10; +```` + +## Syntaxe + +## Sémantique From ca7e7d3cbb43401934cac4796209131776666ebf Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Wed, 10 Dec 2025 11:04:22 +0100 Subject: [PATCH 08/26] Rajout de certains mots clef --- source-doc/intro.md | 4 +- source-doc/syntax.md | 115 ++++++++++++++++++-------------- src/mlang/m_frontend/mlexer.mll | 4 +- 3 files changed, 70 insertions(+), 53 deletions(-) diff --git a/source-doc/intro.md b/source-doc/intro.md index 657b01e0c..b1a2c91d3 100644 --- a/source-doc/intro.md +++ b/source-doc/intro.md @@ -13,7 +13,7 @@ Un programme M se caracterise par la définition successive : * des fonctions ; * de règles de calcul associées ou non à une application. -L'exécution d'un tel programme pour une application donnée correspond à +Exécuter d'un tel programme pour une application donnée correspond à exécuter l'ensemble des règles de calcul associée la dite application. %% L'ordre d'exécution des règles de calcul dépend des dépendances entre les @@ -201,4 +201,4 @@ Et lancer le calcul : [RESULT] test.irj [RESULT] No failure! [RESULT] Test passed! -``` \ No newline at end of file +``` diff --git a/source-doc/syntax.md b/source-doc/syntax.md index ef1572685..581adf286 100644 --- a/source-doc/syntax.md +++ b/source-doc/syntax.md @@ -2,29 +2,27 @@ # La syntaxe du M -## Morphologie - -### Programme M et applications +## 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. +* 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. %% @@ -65,12 +63,14 @@ Les lexèmes suivants sont les mots réservés : **afficher**, **afficher_erreur**, **aiguillage**, +**ajouter**, **alias**, **alors**, **anomalie**, **application**, **apres**, **argument**, +**arranger_evenements**, **attribut**, **autorise**, **avec**, @@ -78,30 +78,45 @@ Les lexèmes suivants sont les mots réservés : **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**, -**finsi**, +**faire**, +**filtrer**, **finalise_erreurs**, +**finquand**, +**finsi**, **fonction**, +**increment**, **indefini**, **indenter**, **informative**, **iterer**, **leve_erreur**, +**meme_variable**, +**nb_anomalies**, **nb_bloquantes**, **nb_categorie**, -**nb_anomalies**, **nb_discordances**, **nb_informatives**, +**neant**, **nettoie_erreurs**, +**nettoie_erreurs_finalisees**, **nom**, **non**, **numero_compl**, @@ -109,20 +124,26 @@ Les lexèmes suivants sont les mots réservés : **ou**, **par_defaut**, **pour**, +**puis_quand**, +**quand**, +**reference**, **regle**, **restaurer**, **restituee**, +**resultat**, **saisie**, **si**, -**sinon_si**, **sinon**, +**sinon_si**, **sortie**, **specialise**, +**stop**, **tableau**, **taille**, -**temporaire**, +**trier**, **type**, **un**, +**valeur** **variable**, **verif**, **verifiable**, @@ -131,8 +152,8 @@ et **verifier**. Les lexèmes numériques sont définis comme suit : * ` ::= [0-9] [0-9 _]*` * ` ::= (. )?` -* `` est la forme [a-z A-Z 0-9 _]+ dont sont exclus `` et -les mots réservés. +* `` est la forme `[a-z A-Z 0-9 _]+` dont sont exclus ``s et +les mots réservés ; * `` est un `` que l'on distingue pour représenter les mots pouvant prendre le nom d'une constante. @@ -153,7 +174,7 @@ Les *déclarations d'applications* ont la forme suivante : application ; ``` -où est le nom de l'application +où `` est le nom de l'application déclarée. ### Définition d'une constante @@ -334,12 +355,12 @@ avec : Les `formules` ont la forme suivante : ``` ::= - (`*[*` `*]*`)? `*=*` + ([ ])? = ``` Les `multi-formules` ont la forme suivante : ``` - ::= `*pour*` `*:*` + ::= pour : ``` ### Instructions @@ -492,11 +513,11 @@ avec : Le prétraitement est une opération purement syntaxique. %% Son but est triple : -- éliminer les constructions relatives aux applications non--sélectionnées ; +- éliminer les constructions relatives aux applications non-sélectionnées ; - remplacer les constantes par leur valeur numérique ; - remplacer les expressions numériques débutant par `*somme*` avec des additions ; -- éliminer les en les remplaçant par des séries de . +- éliminer les ``s en les remplaçant par des séries de ``s. Toute substitution transformant un programme M syntaxiquement valide en un texte ne correspondant à aucun programme M provoque l'échec du traitement. @@ -518,20 +539,20 @@ Dans les déclarations des règles spécifiant une application sélectionnée, o ### Cas des constantes -Pour prétraiter un programme, on le parcourt du début à la fin* Pour chaque - rencontrée, si elle correspond à une contante défini précédemment, +Pour prétraiter un programme, on le parcourt du début à la fin. Pour chaque +`` rencontrée, si elle correspond à une contante défini précédemment, alors il est remplacé dans le programme par la valeur numérique correspondante. -Un intervalle de la forme ~`*-*`~ est -converti par substitution de la constante /const/ en l'intervalle -~`****`~, avec /fin/ le naturel correspondant -à /const/. +Un intervalle de la forme `..` est +converti par substitution de la constante `const` en l'intervalle +`..`, avec `fin` le naturel correspondant +à `const`. *Exemple* : considérons le programme suivant : ``` fin : const = 10; … -pour i = 9..fin : +pour i = 9-fin : Bi = Bi + fin; ``` @@ -577,14 +598,14 @@ Les séries associées aux sont définis comme suit : séparément, donc de taille 1 (*par exemple* : `AXF` représente la série `A`, `X`, `F`); * `****` est la série composée de toutes les majuscules comprises entre /début/ et /fin/, bornes comprises, suivant - l'ordre alphabétique, donc de taille 1 (*par exemple* : `A**D` représente la série `A`, `B`, `C`, `D`); -* `****` est la série composée de tous les - nombres naturels entre /début/ et /fin/, bornes comprises, la taille des + l'ordre alphabétique, donc de taille 1 (*par exemple* : `A..D` représente la série `A`, `B`, `C`, `D`); +* `..` est la série composée de tous les + nombres naturels entre `début` et `fin`, bornes comprises, la taille des éléments étant égale à la taille du plus grand naturel en base 10; les naturels trop petits pour avoir la taille requise sont complétés par des 0 à - gauche (*par exemple* : `9**11` représente la série `09`, `10`, `11`); -* ``**`-`**`` est converti lors du prétraitement des constantes - en un intervalle de la forme ``**`..`**``. + gauche (*par exemple* : `9..11` représente la série `09`, `10`, `11`); +* `-` est converti lors du prétraitement des constantes + en un intervalle de la forme `..`. ### Cas des expressions `somme(…)` @@ -600,8 +621,8 @@ La somme ainsi générée est parenthésée. Une expression numérique `somme ( ; : )`, est remplacée par la somme des expressions -*`somme`*` : expr'> )` avec *expr'* prenant sa valeur -dans la série *sub(ind, expr). +*`somme`*` : expr'> )` avec `expr'` prenant sa valeur +dans la série `sub(ind, expr)`. % La procédure est ensuite appliquée récursivement à cette somme. % @@ -665,10 +686,10 @@ pour i = XZ ; j = 9..10 : Elle est dans un premier temps remplacée par la série suivante : ``` -pour j = 9**10 : +pour j = 9..10 : BX = BX + Bj; -pour j = 9**10 : +pour j = 9..10 : BZ = BZ + Bj; ``` @@ -679,7 +700,3 @@ BX = BX + B10; BZ = BZ + B09; BZ = BZ + B10; ```` - -## Syntaxe - -## Sémantique diff --git a/src/mlang/m_frontend/mlexer.mll b/src/mlang/m_frontend/mlexer.mll index 543c757ce..08be84845 100644 --- a/src/mlang/m_frontend/mlexer.mll +++ b/src/mlang/m_frontend/mlexer.mll @@ -94,7 +94,6 @@ rule token = parse | "erreur" -> ERROR | "espace" -> SPACE | "espace_variables" -> VARIABLE_SPACE - | "meme_variable" -> SAME_VARIABLE | "et" -> AND | "evenement" -> EVENT | "evenements" -> EVENTS @@ -111,9 +110,10 @@ rule token = parse | "informative" -> INFORMATIVE | "iterer" -> ITERATE | "leve_erreur" -> RAISE_ERROR + | "meme_variable" -> SAME_VARIABLE + | "nb_anomalies" -> NB_ANOMALIES | "nb_bloquantes" -> NB_BLOCKING | "nb_categorie" -> NB_CATEGORY - | "nb_anomalies" -> NB_ANOMALIES | "nb_discordances" -> NB_DISCORDANCES | "nb_informatives" -> NB_INFORMATIVES | "neant" -> NOTHING From 6cd19dd8f37552cf80531b56be57a534184354cf Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Wed, 10 Dec 2025 11:39:55 +0100 Subject: [PATCH 09/26] Retravail de l'index --- source-doc/index.md | 30 ++++++++++++++++++++++++++++++ source-doc/index.rst | 25 ------------------------- source-doc/syntax.md | 15 +++++++++++++++ 3 files changed, 45 insertions(+), 25 deletions(-) create mode 100644 source-doc/index.md delete mode 100644 source-doc/index.rst diff --git a/source-doc/index.md b/source-doc/index.md new file mode 100644 index 000000000..1edb32690 --- /dev/null +++ b/source-doc/index.md @@ -0,0 +1,30 @@ +
+
+ .____. ________________________ + | ._ ' | | + | | \ | Direction Générale des | +.-+-+-' | | + | | | Finances Publiques | + ! ! !________________________! +
+
+ +# Bienvenue dans la documentation du langage M ! + +## Table des matières + +```{toctree} +:maxdepth: 2 + +intro +syntax +syntax_irj +mlang +arithmetique +``` + +## Index et recherche + +* {ref}`genindex` +* {ref}`modindex` +* {ref}`search` diff --git a/source-doc/index.rst b/source-doc/index.rst deleted file mode 100644 index 6964150c3..000000000 --- a/source-doc/index.rst +++ /dev/null @@ -1,25 +0,0 @@ -.. MLang documentation master file, created by - sphinx-quickstart on Thu Nov 13 14:51:45 2025. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Bienvenue dans la documentation du langage M ! -============================================== - -.. toctree:: - :maxdepth: 2 - :caption: Table des matières: - - intro - syntax - syntax_irj - mlang - arithmetique - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/source-doc/syntax.md b/source-doc/syntax.md index 581adf286..1edcac209 100644 --- a/source-doc/syntax.md +++ b/source-doc/syntax.md @@ -508,6 +508,21 @@ Les *cibles* ont la forme suivante : avec : * ` ::= ([ ])?` +### 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. }# +``` + ## Prétraitement Le prétraitement est une opération purement syntaxique. From b9e7534348117dd468995c57d5ba7d1f514fec4a Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Wed, 10 Dec 2025 11:43:25 +0100 Subject: [PATCH 10/26] Poesie --- source-doc/syntax_irj.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source-doc/syntax_irj.md b/source-doc/syntax_irj.md index 5da345348..2c1fffed1 100644 --- a/source-doc/syntax_irj.md +++ b/source-doc/syntax_irj.md @@ -7,8 +7,8 @@ Les fichiers IRJ sont des fichiers de test faisant corespondre entrées et sorties du calcul d'un programme M. %% -Il sont divisés en 7 parties, plus 3 parties optionnelles, et est terminé par la -ligne `##`. +Chaque fichier IRJ est divisé en 7 parties, plus 3 parties optionnelles, +et est terminé par la ligne `##`. * `NOM` : le nom du test. * `ENTREES-PRIMITIF` : les valeurs des variables d'entrées au début du calcul. A chaque variable `VAR` est associée une valeur `val` entière ou décimale sur une ligne de la forme `VAR/val`. Les variables d'entrées qui ne sont pas définies dans le fichier IRJ seront initialisées à `indefini`. @@ -22,7 +22,7 @@ ligne `##`. * `RESULTATS-RAPPELS` : partie optionnelle, à documenter Voici un exemple de fichier IRJ minimal -``` +``` #NOM MON-TEST #ENTREES-PRIMITIF @@ -91,4 +91,4 @@ $ make test_dgfip_c_backend ``` L'utilisation du script `cal` utilisé dans cette règle est documentée dans -`examples/dgfip_c/README.md`. \ No newline at end of file +`examples/dgfip_c/README.md`. From 104f569232324d7fe95aa6d8dbe9e4207e9eb979 Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Wed, 10 Dec 2025 12:03:08 +0100 Subject: [PATCH 11/26] =?UTF-8?q?Ajout=20de=20la=20g=C3=A9n=C3=A9ration=20?= =?UTF-8?q?de=20documentation=20au=20format=20PDF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 1 + source-doc/conf.py | 4 ++-- source-doc/index.md | 6 ------ 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index c6295ecf8..830778e5d 100644 --- a/Makefile +++ b/Makefile @@ -43,3 +43,4 @@ sphinx-doc: FORCE rm -rf _build/default/source-doc/* cp -rf source-doc/* _build/default/source-doc/ sphinx-build -M html _build/default/source-doc/ doc/sphinx/ + sphinx-build -M latexpdf _build/default/source-doc/ doc/sphinx/ diff --git a/source-doc/conf.py b/source-doc/conf.py index 8f5b50ebd..5b231de11 100644 --- a/source-doc/conf.py +++ b/source-doc/conf.py @@ -7,8 +7,8 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information project = 'MLang' -copyright = '2025, Steven de Oliveira' -author = 'Steven de Oliveira' +copyright = '2025, Direction Générale des FInances Publiques' +author = 'Direction Générale des FInances Publiques' # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration diff --git a/source-doc/index.md b/source-doc/index.md index 1edb32690..63fe9f75c 100644 --- a/source-doc/index.md +++ b/source-doc/index.md @@ -22,9 +22,3 @@ syntax_irj mlang arithmetique ``` - -## Index et recherche - -* {ref}`genindex` -* {ref}`modindex` -* {ref}`search` From 7eb8d781835360cefed20920db8ab3de8abfc60d Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Wed, 10 Dec 2025 12:20:07 +0100 Subject: [PATCH 12/26] Verification d'installation de sphinx-doc --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 830778e5d..794285c28 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,10 @@ clean: FORCE remise_a_zero_versionnage dune clean sphinx-doc: FORCE + @command -v sphinx-build >/dev/null 2>&1 || \ + { echo "Pour construire la documentation, vous avez besoin de sphinx-build avec \ + l'extension 'myst-parser'."; exit 1; } rm -rf _build/default/source-doc/* - cp -rf source-doc/* _build/default/source-doc/ + cp -rf source-doc/* _build/default/source-doc/ sphinx-build -M html _build/default/source-doc/ doc/sphinx/ sphinx-build -M latexpdf _build/default/source-doc/ doc/sphinx/ From 099f5596be59b4b6485da6ccace3b04ec10ff069 Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Wed, 10 Dec 2025 13:50:15 +0100 Subject: [PATCH 13/26] Un peu d'infos sur mlang --- source-doc/index.md | 6 ++--- source-doc/mlang.md | 53 ++++++++++++++++++++++++++++++++++++++++++++ source-doc/mlang.rst | 6 ----- 3 files changed, 56 insertions(+), 9 deletions(-) create mode 100644 source-doc/mlang.md delete mode 100644 source-doc/mlang.rst diff --git a/source-doc/index.md b/source-doc/index.md index 63fe9f75c..d1442dcea 100644 --- a/source-doc/index.md +++ b/source-doc/index.md @@ -1,3 +1,5 @@ + +
.____. ________________________ @@ -9,9 +11,7 @@
-# Bienvenue dans la documentation du langage M ! - -## Table des matières +# Documentation du langage M ```{toctree} :maxdepth: 2 diff --git a/source-doc/mlang.md b/source-doc/mlang.md new file mode 100644 index 000000000..21964cafd --- /dev/null +++ b/source-doc/mlang.md @@ -0,0 +1,53 @@ +(mlang)= + +# Le compilateur MLang + +## Utiliser MLang + +Le binaire `mlang` prend en argument le fichier *M* à exécuter. +%% +Il peut également prendre en argument une liste de fichiers, auquel cas leur +traitement sera équivalent au traitement d'un seul et même fichier dans lequel +serait concatené le contenu de chaque fichier. +%% + +Les deux options principales sont : +* `-A`: le nom de l'application à traiter; +* `--mpp_function`: le nom de la fonction principale à traiter. + +### Mode interpreteur + +Le mode interpreteur de `mlang` utilise un fichier *IRJ* (voir {ref}`syntax_irj`) +pour exécuter le code *M* directement depuis sa représentation abstraite. +%% +Voici une commande simple pour invoquer l'interpreteur : +``` +$ mlang test.m \ + -A mon_application \ + -b interpreter \ + --mpp_function hello_world \ + --run_test test.irj \ + --without_dfgip_m +``` + +### Mode transpilation + +Le mode transpilation de `mlang` permet de traduire le code *M* dans un autre +langage. +%% +En 2025, seul le langage C est supporté. +%% +Voici une commande simple pour traduire un fichier *M* en *C* : + +``` +$ mlang test.m \ + -A mon_application \ + -b dgfip_c \ + --mpp_function hello_world + --dgfip_options='' + --output output/mon-test.c +``` + +### Options DGFiP + +## Comportement diff --git a/source-doc/mlang.rst b/source-doc/mlang.rst deleted file mode 100644 index cc713cdc8..000000000 --- a/source-doc/mlang.rst +++ /dev/null @@ -1,6 +0,0 @@ -.. _mlang: - -Le compilateur MLang -==================== - -Il y a plein de choses à dire sur MLang From 71d651418dbcfbee4e0a355bcec7a43b6c18dd08 Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Wed, 10 Dec 2025 14:31:40 +0100 Subject: [PATCH 14/26] Un peu plus d'infos sur mlang --- source-doc/mlang.md | 54 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/source-doc/mlang.md b/source-doc/mlang.md index 21964cafd..65c5c23eb 100644 --- a/source-doc/mlang.md +++ b/source-doc/mlang.md @@ -48,6 +48,60 @@ $ mlang test.m \ --output output/mon-test.c ``` +NB: le dossier `output` doit avoir été créé en amont. + ### Options DGFiP +Les options DGFiP sont à usage interne. + +``` + -b VAL + Set application to "batch" (b0 = normal, b1 = with EBCDIC sort) + + -D Generate labels for output variables + + -g Generate for test (debug) + + -I Generate immediate controls + + -k VAL (absent=0) + Number of debug files + + -L Generate calls to ticket function + + -m VAL (absent=1991) + Income year + + -O Optimize generated code (inline min_max function) + + -o Generate overlays + + -P Primitive calculation only + + -r Pass TGV pointer as register in rules + + -R Set application to both "iliad" and "pro" + + -s Strip comments from generated output + + -S Generate separate controls + + -t Generate trace code + + -U Set application to "cfir" + + -x Generate cross references + + -X Generate global extraction + + -Z Colored output in chainings +``` + ## Comportement + +* Traduction du code M dans l'arbre de syntaxe abstraite M_AST. +* Extension des constructions. +* Vérification de cohérence. +* Selon le mode : + * **Interpreteur** Lecture du fichier IRJ et interpretation du code. + * **Transpilation** Ecriture du code C équivalent au code M. From 62934b438a9544d20ccadd7acdddcbbba9c5cdbc Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Wed, 10 Dec 2025 14:36:53 +0100 Subject: [PATCH 15/26] Suppression des inter-lignes --- source-doc/arithmetique.md | 4 ---- source-doc/intro.md | 11 +---------- source-doc/mlang.md | 7 ++----- source-doc/syntax.md | 13 ------------- source-doc/syntax_irj.md | 8 +------- 5 files changed, 4 insertions(+), 39 deletions(-) diff --git a/source-doc/arithmetique.md b/source-doc/arithmetique.md index 7f66f5d32..d053a8812 100644 --- a/source-doc/arithmetique.md +++ b/source-doc/arithmetique.md @@ -4,11 +4,9 @@ Les variables en M prennent soit leur valeur sur les flottants, soit ont la valeur `indefini`. -%% 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 : @@ -27,7 +25,6 @@ Les calculs impliquant la valeur `indefini` ont un comportement spécifique : Pour résumer, seules les opérations d'addition et de soustraction avec une valeur renvoient autre chose que `indefini`. -%% Les comparaisons (=, <, >, ...) renvoient soit `0` soit `1` lorsque des valeurs definies sont comparées. @@ -35,7 +32,6 @@ valeurs definies sont comparées. Toutes les les opérations booléennes renvoient `indefini` si un de ses membres est `indefini` (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. diff --git a/source-doc/intro.md b/source-doc/intro.md index b1a2c91d3..b04c07879 100644 --- a/source-doc/intro.md +++ b/source-doc/intro.md @@ -97,7 +97,6 @@ calculées les données. Chacune de ces catégories principales doivent être dotées d'attributs, un ensemble d'entiers constants pour une variable donnée. -%% Ainsi, on peut rajouter à notre programme test les lignes suivantes : ``` variable saisie : attribut mon_attribut; @@ -107,10 +106,8 @@ Y : calculee mon_attribut = 1 : "Cette variable s'appelle Y"; ``` Notez que la variable `X` a un alias `ALIAS_DE_X`. -%% Toutes les variables saisies doivent être parées d'un alias qui peut être utilisé de la même façon que son nom original. -%% Cet alias existe initialement pour faire le lien entre la variable utilisée dans le M (nom original) et le code de la variable dans le formulaire de déclaration de l'impot sur le revenu tel qu'on le retrouve aujourd'hui sur @@ -147,9 +144,7 @@ section {ref}`arithmetique`. Les règles en M sont des unités de calcul de variables associées à une ou plusieurs application et optionnellement à un domaine de règles. -%% Elles sont composées d'une successions d'affectations. -%% Voici la définition de deux règles simples que nous rajoutons à notre fichier test : ``` Z : calculee mon_attribut = 1 : "Cette variable s'appelle Z"; @@ -165,18 +160,14 @@ Y = X + 1; La première règle est associée au domaine `mon_domaine_de_regles` tandis que la seconde n'étant pas spécifié, sera associée au domaine de règle par défaut. -%% Dans notre exemple, il s'agissait également de `mon_domaine_de_regles`. Le calcul d'un domaine correspond au calcul de l'ensemble de ses règles. -%% L'ordre d'application des règles dépend de l'ordre d'affectation des variables. -%% Dans notre cas, `X` est une entrée dont `Y` dépend (règle 2), et `Z` dépend de `Y`. -%% + Par conséquent, la règle 2 sera appliquée avant la règle 1. -%% On peut ainsi rajouter une cible qui calcule le domaine de règles : ``` cible calc_test: diff --git a/source-doc/mlang.md b/source-doc/mlang.md index 65c5c23eb..989e5a767 100644 --- a/source-doc/mlang.md +++ b/source-doc/mlang.md @@ -4,8 +4,7 @@ ## Utiliser MLang -Le binaire `mlang` prend en argument le fichier *M* à exécuter. -%% +Le binaire `mlang` prend en argument le fichier *M* à exécuter. Il peut également prendre en argument une liste de fichiers, auquel cas leur traitement sera équivalent au traitement d'un seul et même fichier dans lequel serait concatené le contenu de chaque fichier. @@ -19,7 +18,7 @@ Les deux options principales sont : Le mode interpreteur de `mlang` utilise un fichier *IRJ* (voir {ref}`syntax_irj`) pour exécuter le code *M* directement depuis sa représentation abstraite. -%% + Voici une commande simple pour invoquer l'interpreteur : ``` $ mlang test.m \ @@ -34,9 +33,7 @@ $ mlang test.m \ Le mode transpilation de `mlang` permet de traduire le code *M* dans un autre langage. -%% En 2025, seul le langage C est supporté. -%% Voici une commande simple pour traduire un fichier *M* en *C* : ``` diff --git a/source-doc/syntax.md b/source-doc/syntax.md index 1edcac209..57f006895 100644 --- a/source-doc/syntax.md +++ b/source-doc/syntax.md @@ -5,9 +5,7 @@ ## 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 ; @@ -25,19 +23,15 @@ Un programme M est constitué d'une suite d'éléments parmi lesquels on compte * 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. @@ -45,10 +39,8 @@ Ces formes sont étendues avec les notations suivantes : * `` 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 n` qui 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. @@ -194,7 +186,6 @@ enchaineur : ; avec : ` ::= , …` représente l'ensemble des applications incluant cet enchaîneur. -%% Le `` de l'enchaineur est le nom de l'application déclarée. @@ -256,7 +247,6 @@ avec : * ` ::= anomalie | discordance | informative` Le symbole est le nom de l'erreur. -%% % A faire: documenter les s ! ### Déclaration d'une fonction externe @@ -511,7 +501,6 @@ avec : ### 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 `}#`. @@ -526,7 +515,6 @@ Exemple: ## Prétraitement Le prétraitement est une opération purement syntaxique. -%% Son but est triple : - éliminer les constructions relatives aux applications non-sélectionnées ; - remplacer les constantes par leur valeur numérique ; @@ -604,7 +592,6 @@ avec : Chaque `` associe à une lettre minuscule une série de chaînes de caractères de même taille. -%% Cette série est composée de la succession de chaque à droite du symbole `=`. diff --git a/source-doc/syntax_irj.md b/source-doc/syntax_irj.md index 2c1fffed1..9becb8066 100644 --- a/source-doc/syntax_irj.md +++ b/source-doc/syntax_irj.md @@ -6,8 +6,7 @@ Les fichiers IRJ sont des fichiers de test faisant corespondre entrées et sorties du calcul d'un programme M. -%% -Chaque fichier IRJ est divisé en 7 parties, plus 3 parties optionnelles, +Chaque fichier IRJ est divisé en 7 parties, plus 3 parties optionnelles, et est terminé par la ligne `##`. * `NOM` : le nom du test. @@ -47,7 +46,6 @@ Trois utilitaires sont dédiés à l'utilisation des fichiers IRJ. Les sources de mlang mettent à disposition un code de vérification de fichiers IRJ. -%% Après compilation, il peut être exécuté via la commande : ``` $ dune exec -- irj_checker @@ -57,7 +55,6 @@ $ dune exec -- irj_checker Le binaire mlang intègre un interpreteur de M qui prend en entrée un ou plusieurs fichiers M ainsi qu'un fichier IRJ. -%% Après compilation, l'interpreteur peut être exécuté via la commande : ``` $ dune exec -- mlang test.m -A application -b interpreter --mpp_function cible_dentree --dgfip_options='' -r test.irj @@ -70,10 +67,8 @@ dossier complet. Il est également possible d'utiliser les fichiers IRJ comme entrée du code C généré à partir d'une compilation de code M par `mlang`. -%% Ce traitement est effectué dans le cas du backend `dgfip_c` de mlang, dont le code est disponible dans `examples/dgfip_c/ml_primitif`. -%% La calculette d'une année donnée peut êter compilée via : ``` $ make YEAR=year compile_dgfip_c_backend @@ -82,7 +77,6 @@ $ make YEAR=year compile_dgfip_c_backend Les scripts présents dans `examples/dgfip_c/ml_primitif/ml_driver` permettent d'interfacer les fichiers IRJ avec les valeurs `C` de type `T_irdata` contenant le TGV (Tableau Général des Variables). -%% La commande suivante permet de tester la calculette d'une année sur l'ensemble des tests fuzzés de la dite année. From de40d2cfec813bd7e7dc1fefecc8e94b316b6d4e Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Wed, 10 Dec 2025 14:42:14 +0100 Subject: [PATCH 16/26] =?UTF-8?q?D=C3=A9placement=20du=20pr=C3=A9-traiteme?= =?UTF-8?q?nt=20dans=20la=20section=20mlang?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source-doc/mlang.md | 196 +++++++++++++++++++++++++++++++++++++++++++ source-doc/syntax.md | 191 ----------------------------------------- 2 files changed, 196 insertions(+), 191 deletions(-) diff --git a/source-doc/mlang.md b/source-doc/mlang.md index 989e5a767..5c79c3001 100644 --- a/source-doc/mlang.md +++ b/source-doc/mlang.md @@ -96,6 +96,202 @@ Les options DGFiP sont à usage interne. ## Comportement +### Traduction + +### Pré-traitement + +Le prétraitement est une opération purement syntaxique. +Son but est triple : +- éliminer les constructions relatives aux applications non-sélectionnées ; +- remplacer les constantes par leur valeur numérique ; +- remplacer les expressions numériques débutant par `*somme*` avec des + additions ; +- éliminer les ``s en les remplaçant par des séries de ``s. + +Toute substitution transformant un programme M syntaxiquement valide en un +texte ne correspondant à aucun programme M provoque l'échec du traitement. + +#### Cas des applications + +On élimine du programme M: +- les déclarations des applications non-sélectionnées ; +- les déclarations des enchaîneurs ne spécifiant pas une application + sélectionnée ; +- les déclarations des règles ne spécifiant pas une application + sélectionnée ; +- les déclarations des vérifications ne spécifiant pas une application + sélectionnée ; +- les déclarations des cibles ne spécifiant pas une application sélectionnée. + +Dans les déclarations des règles spécifiant une application sélectionnée, on +élimine les enchaîneurs qui ne sont plus déclarés dans le programme M obtenu. + +#### Cas des constantes + +Pour prétraiter un programme, on le parcourt du début à la fin. Pour chaque +`` rencontrée, si elle correspond à une contante défini précédemment, +alors il est remplacé dans le programme par la valeur numérique correspondante. + +Un intervalle de la forme `..` est +converti par substitution de la constante `const` en l'intervalle +`..`, avec `fin` le naturel correspondant +à `const`. + +*Exemple* : considérons le programme suivant : +``` +fin : const = 10; +… +pour i = 9-fin : + Bi = Bi + fin; +``` + +Par substitution de la constante `fin`, il est remplacé dans un premier temps +remplacée par le programme : + +``` +fin : const = 10;` +… +pour i = 9..10 : + Bi = Bi + fin; +``` + +puis dans un second temps par le programme : +``` +fin : const = 10; +… +pour i = 9..10 : + Bi = Bi + 10; +``` + +#### Interprétation des indices + +Pour rappel, les *indices* ont la forme suivante : +``` + ::= ; … + ::= = , … +``` + +avec : +* ` ::= [a-z]` +* ` ::= [A-Z]` +* ` ::= + | .. | (.. | - )?` + +Chaque `` associe à une lettre minuscule une série de chaînes de +caractères de même taille. +Cette série est composée de la succession de chaque + à droite du symbole `=`. + +Les séries associées aux sont définis comme suit : +* `+` est la série composée de chacune des majuscules prises + séparément, donc de taille 1 (*par exemple* : `AXF` représente la série `A`, `X`, `F`); +* `****` est la série composée de toutes + les majuscules comprises entre /début/ et /fin/, bornes comprises, suivant + l'ordre alphabétique, donc de taille 1 (*par exemple* : `A..D` représente la série `A`, `B`, `C`, `D`); +* `..` est la série composée de tous les + nombres naturels entre `début` et `fin`, bornes comprises, la taille des + éléments étant égale à la taille du plus grand naturel en base 10; les + naturels trop petits pour avoir la taille requise sont complétés par des 0 à + gauche (*par exemple* : `9..11` représente la série `09`, `10`, `11`); +* `-` est converti lors du prétraitement des constantes + en un intervalle de la forme `..`. + +#### Cas des expressions `somme(…)` + +Pour une expression numérique +`somme ( : )`, +l'expression *expr* sera remplacée par la somme des expressions construites +ainsi : pour chaque chaîne de caractères de la série introduite par *ind*, les +symboles apparaîssant dans *expr* sont remplacés par ceux dans lesquels la +lettre minuscule de /ind/ est substituéé par la chaine de caractère. +% +La somme ainsi générée est parenthésée. + +Une expression numérique +`somme ( ; : )`, +est remplacée par la somme des expressions +*`somme`*` : expr'> )` avec `expr'` prenant sa valeur +dans la série `sub(ind, expr)`. +% +La procédure est ensuite appliquée récursivement à cette somme. +% +La somme ainsi générée est parenthésée. +% +Notons que les sous-sommes récursivement produites n'ont pas besoin de l'être +car l'addition est associative. + +On applique cette transformation à toutes les expressions `somme(…)` tant +qu'il en existe dans le programme. + +**Exemple**. Considérons l'expression suivante : + +* `somme(i = XZ ; j = 9..10 : Bi + Bj)` + +Elle est dans un premier temps remplacée par la somme suivante : + +* `(somme(j = 9..10 : BX + Bj) + somme(j = 9..10 : BZ + Bj))` + +puis dans un second temps par la somme : + +* `(BX + B09 + BX + B10 + BZ + B09 + BZ + B10)` + +On remarque que seule l'expression globale est parenthésée car l'addition est +associative. + +#### Cas des multi-formules + +On commence par substituer toutes les expressions `somme(…)` apparaissant dans +les multi-formules. +% +Puis on transforme les multi-formules en séries de formules en suivant la +méthode décrite ci-dessous. + +Pour chaque multi-formule rencontrée, de la forme `pour : `, +dès que les constantes apparaîssant dans les ont été substitués, on +remplace cette multi-formule par la série de formules générée de la manière +suivante. + +Pour une multi-formule `pour : `, la +formule `f` sera remplacée par la série des formules construites ainsi : pour +chaque chaîne de caractères de la série introduite par `ind`, les symboles +apparaîssant dans `f` sont remplacés par ceux dans lesquels la lettre +minuscule de `ind` est substituéé par la chaïne de caractère. +% +On notera `sub(ind, f)` la série constituée des formules ainsi régérées. + +Une multi-formule `pour ; : `, +est remplacée par la série des multi-formules +`pour : f'>` avec `f'` prenant sa valeur +dans la série `sub(ind, f)`. +% +La procédure est ensuite appliquée récursivement +à ces multi-formules. + +**Exemple**. Considérons la multi-formule suivante : +``` +pour i = XZ ; j = 9..10 : + Bi = Bi + Bj; +``` + +Elle est dans un premier temps remplacée par la série suivante : +``` +pour j = 9..10 : + BX = BX + Bj; + +pour j = 9..10 : + BZ = BZ + Bj; +``` + +Puis dans un second temps par la série des formules : +``` +BX = BX + B09; +BX = BX + B10; +BZ = BZ + B09; +BZ = BZ + B10; +```` + +### Vérification de cohérence + +### Traitement * Traduction du code M dans l'arbre de syntaxe abstraite M_AST. * Extension des constructions. * Vérification de cohérence. diff --git a/source-doc/syntax.md b/source-doc/syntax.md index 57f006895..bbd7dca9a 100644 --- a/source-doc/syntax.md +++ b/source-doc/syntax.md @@ -511,194 +511,3 @@ Exemple: #{ Ceci est un commentaire sur plusieurs lignes. }# ``` - -## Prétraitement - -Le prétraitement est une opération purement syntaxique. -Son but est triple : -- éliminer les constructions relatives aux applications non-sélectionnées ; -- remplacer les constantes par leur valeur numérique ; -- remplacer les expressions numériques débutant par `*somme*` avec des - additions ; -- éliminer les ``s en les remplaçant par des séries de ``s. - -Toute substitution transformant un programme M syntaxiquement valide en un -texte ne correspondant à aucun programme M provoque l'échec du traitement. - -### Cas des applications - -On élimine du programme M: -- les déclarations des applications non-sélectionnées ; -- les déclarations des enchaîneurs ne spécifiant pas une application - sélectionnée ; -- les déclarations des règles ne spécifiant pas une application - sélectionnée ; -- les déclarations des vérifications ne spécifiant pas une application - sélectionnée ; -- les déclarations des cibles ne spécifiant pas une application sélectionnée. - -Dans les déclarations des règles spécifiant une application sélectionnée, on -élimine les enchaîneurs qui ne sont plus déclarés dans le programme M obtenu. - -### Cas des constantes - -Pour prétraiter un programme, on le parcourt du début à la fin. Pour chaque -`` rencontrée, si elle correspond à une contante défini précédemment, -alors il est remplacé dans le programme par la valeur numérique correspondante. - -Un intervalle de la forme `..` est -converti par substitution de la constante `const` en l'intervalle -`..`, avec `fin` le naturel correspondant -à `const`. - -*Exemple* : considérons le programme suivant : -``` -fin : const = 10; -… -pour i = 9-fin : - Bi = Bi + fin; -``` - -Par substitution de la constante `fin`, il est remplacé dans un premier temps -remplacée par le programme : - -``` -fin : const = 10;` -… -pour i = 9..10 : - Bi = Bi + fin; -``` - -puis dans un second temps par le programme : -``` -fin : const = 10; -… -pour i = 9..10 : - Bi = Bi + 10; -``` - -### Interprétation des indices - -Pour rappel, les *indices* ont la forme suivante : -``` - ::= ; … - ::= = , … -``` - -avec : -* ` ::= [a-z]` -* ` ::= [A-Z]` -* ` ::= + | .. | (.. | - )?` - -Chaque `` associe à une lettre minuscule une série de chaînes de -caractères de même taille. -Cette série est composée de la succession de chaque - à droite du symbole `=`. - -Les séries associées aux sont définis comme suit : -* `+` est la série composée de chacune des majuscules prises - séparément, donc de taille 1 (*par exemple* : `AXF` représente la série `A`, `X`, `F`); -* `****` est la série composée de toutes - les majuscules comprises entre /début/ et /fin/, bornes comprises, suivant - l'ordre alphabétique, donc de taille 1 (*par exemple* : `A..D` représente la série `A`, `B`, `C`, `D`); -* `..` est la série composée de tous les - nombres naturels entre `début` et `fin`, bornes comprises, la taille des - éléments étant égale à la taille du plus grand naturel en base 10; les - naturels trop petits pour avoir la taille requise sont complétés par des 0 à - gauche (*par exemple* : `9..11` représente la série `09`, `10`, `11`); -* `-` est converti lors du prétraitement des constantes - en un intervalle de la forme `..`. - -### Cas des expressions `somme(…)` - -Pour une expression numérique -`somme ( : )`, -l'expression *expr* sera remplacée par la somme des expressions construites -ainsi : pour chaque chaîne de caractères de la série introduite par *ind*, les -symboles apparaîssant dans *expr* sont remplacés par ceux dans lesquels la -lettre minuscule de /ind/ est substituéé par la chaine de caractère. -% -La somme ainsi générée est parenthésée. - -Une expression numérique -`somme ( ; : )`, -est remplacée par la somme des expressions -*`somme`*` : expr'> )` avec `expr'` prenant sa valeur -dans la série `sub(ind, expr)`. -% -La procédure est ensuite appliquée récursivement à cette somme. -% -La somme ainsi générée est parenthésée. -% -Notons que les sous-sommes récursivement produites n'ont pas besoin de l'être -car l'addition est associative. - -On applique cette transformation à toutes les expressions `somme(…)` tant -qu'il en existe dans le programme. - -**Exemple**. Considérons l'expression suivante : - -* `somme(i = XZ ; j = 9..10 : Bi + Bj)` - -Elle est dans un premier temps remplacée par la somme suivante : - -* `(somme(j = 9..10 : BX + Bj) + somme(j = 9..10 : BZ + Bj))` - -puis dans un second temps par la somme : - -* `(BX + B09 + BX + B10 + BZ + B09 + BZ + B10)` - -On remarque que seule l'expression globale est parenthésée car l'addition est -associative. - -### Cas des multi-formules - -On commence par substituer toutes les expressions `somme(…)` apparaissant dans -les multi-formules. -% -Puis on transforme les multi-formules en séries de formules en suivant la -méthode décrite ci-dessous. - -Pour chaque multi-formule rencontrée, de la forme `pour : `, -dès que les constantes apparaîssant dans les ont été substitués, on -remplace cette multi-formule par la série de formules générée de la manière -suivante. - -Pour une multi-formule `pour : `, la -formule `f` sera remplacée par la série des formules construites ainsi : pour -chaque chaîne de caractères de la série introduite par `ind`, les symboles -apparaîssant dans `f` sont remplacés par ceux dans lesquels la lettre -minuscule de `ind` est substituéé par la chaïne de caractère. -% -On notera `sub(ind, f)` la série constituée des formules ainsi régérées. - -Une multi-formule `pour ; : `, -est remplacée par la série des multi-formules -`pour : f'>` avec `f'` prenant sa valeur -dans la série `sub(ind, f)`. -% -La procédure est ensuite appliquée récursivement -à ces multi-formules. - -**Exemple**. Considérons la multi-formule suivante : -``` -pour i = XZ ; j = 9..10 : - Bi = Bi + Bj; -``` - -Elle est dans un premier temps remplacée par la série suivante : -``` -pour j = 9..10 : - BX = BX + Bj; - -pour j = 9..10 : - BZ = BZ + Bj; -``` - -Puis dans un second temps par la série des formules : -``` -BX = BX + B09; -BX = BX + B10; -BZ = BZ + B09; -BZ = BZ + B10; -```` From 0e3b26d3d5db450db6486516ae803f16ceeb6651 Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Wed, 10 Dec 2025 14:45:07 +0100 Subject: [PATCH 17/26] Poesie --- source-doc/mlang.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/source-doc/mlang.md b/source-doc/mlang.md index 5c79c3001..bdf599e54 100644 --- a/source-doc/mlang.md +++ b/source-doc/mlang.md @@ -94,17 +94,19 @@ Les options DGFiP sont à usage interne. -Z Colored output in chainings ``` -## Comportement +## Comportement de mlang ### Traduction +% A faire : traduction du M en M_AST + ### Pré-traitement Le prétraitement est une opération purement syntaxique. Son but est triple : - éliminer les constructions relatives aux applications non-sélectionnées ; - remplacer les constantes par leur valeur numérique ; -- remplacer les expressions numériques débutant par `*somme*` avec des +- remplacer les expressions numériques débutant par `somme` avec des additions ; - éliminer les ``s en les remplaçant par des séries de ``s. @@ -291,10 +293,14 @@ BZ = BZ + B10; ### Vérification de cohérence +% A faire : documentation de la verification + ### Traitement -* Traduction du code M dans l'arbre de syntaxe abstraite M_AST. -* Extension des constructions. -* Vérification de cohérence. -* Selon le mode : - * **Interpreteur** Lecture du fichier IRJ et interpretation du code. - * **Transpilation** Ecriture du code C équivalent au code M. + +#### Interpreteur + +Lecture du fichier IRJ et interpretation du code. + +#### Transpilation + +Ecriture du code C équivalent au code M. From e3996e0f270e5bd1d431981e163f7402946f9021 Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Mon, 15 Dec 2025 15:54:32 +0100 Subject: [PATCH 18/26] =?UTF-8?q?D=C3=A9placement=20d'arithmetique=20dans?= =?UTF-8?q?=20syntaxe=20et=20ajout=20d'un=20exemple?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source-doc/arithmetique.md | 37 --------- source-doc/exemples/valeurs.md | 137 +++++++++++++++++++++++++++++++++ source-doc/index.md | 14 +++- source-doc/intro.md | 2 +- source-doc/syntax.md | 61 +++++++++++++++ 5 files changed, 212 insertions(+), 39 deletions(-) delete mode 100644 source-doc/arithmetique.md create mode 100644 source-doc/exemples/valeurs.md diff --git a/source-doc/arithmetique.md b/source-doc/arithmetique.md deleted file mode 100644 index d053a8812..000000000 --- a/source-doc/arithmetique.md +++ /dev/null @@ -1,37 +0,0 @@ -(arithmetique)= - -# L'arithmetique en M - -Les variables en M prennent soit leur valeur sur les flottants, soit ont la -valeur `indefini`. -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 = indefini` -* `indefini + n = n` -* `n + indefini = n` -* `indefini - indefini = indefini` -* `indefini - n = -n` -* `n - indefini = n` -* `indefini * indefini = indefini` -* `indefini * n = indefini` -* `n * indefini = indefini` -* `indefini / indefini` = indefini` -* `indefini / n` = indefini` -* `n / indefini = indefini` - -Pour résumer, seules les opérations d'addition et de soustraction avec une -valeur renvoient autre chose que `indefini`. - -Les comparaisons (=, <, >, ...) renvoient soit `0` soit `1` lorsque des -valeurs definies sont comparées. -% -Toutes les les opérations booléennes renvoient `indefini` si un de ses -membres est `indefini` (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. - diff --git a/source-doc/exemples/valeurs.md b/source-doc/exemples/valeurs.md new file mode 100644 index 000000000..fb0f603fe --- /dev/null +++ b/source-doc/exemples/valeurs.md @@ -0,0 +1,137 @@ +(exemples/valeurs)= + +# Calcul des valeurs + + ## Fichier test : test.m +``` +espace_variables GLOBAL : par_defaut; +domaine regle mon_domaine_de_regle: par_defaut; +domaine verif mon_domaine_de_verifications: par_defaut; +application mon_application; +variable saisie : attribut mon_attribut; +variable calculee : attribut mon_attribut; +X : saisie mon_attribut = 0 alias AX : ""; + +cible indefini_test: +application : mon_application; +afficher "Bonjour, monde, X = "; +afficher (X); +afficher " !\n"; +# Addition +afficher "X + 1 = "; +afficher (X + 1); +afficher " !\n"; +afficher "1 + X = "; +afficher (1 + X); +afficher " !\n"; +afficher "X + X = "; +afficher (X + X); +afficher " !\n"; +# Soustraction +afficher "X - 1 = "; +afficher (X - 1); +afficher " !\n"; +afficher "1 - X = "; +afficher (1 - X); +afficher " !\n"; +afficher "X - X = "; +afficher (X - X); +afficher " !\n"; +# Multiplication +afficher "X * 1 = "; +afficher (X * 1); +afficher " !\n"; +afficher "1 * X = "; +afficher (1 * X); +afficher " !\n"; +afficher "X * X = "; +afficher (X * X); +afficher " !\n"; +# Division +afficher "X / 1 = "; +afficher (X / 1); +afficher " !\n"; +afficher "1 / X = "; +afficher (1 / X); +afficher " !\n"; +afficher "1 / 0 = "; +afficher (1 / 0); +afficher " !\n"; +afficher "X / 0 = "; +afficher (X / 0); +afficher " !\n"; +afficher "X / X = "; +afficher (X / X); +afficher " !\n"; +# Comparaisons +afficher "(X = 0) = "; +afficher (X = 0); +afficher " !\n"; +afficher "(X = X) = "; +afficher (X = X); +afficher " !\n"; +afficher "(X >= 0) = "; +afficher (X >= 0); +afficher " !\n"; +afficher "(X >= X) = "; +afficher (X >= X); +afficher " !\n"; +afficher "(X > 0) = "; +afficher (X > 0); +afficher " !\n"; +afficher "(X > X) = "; +afficher (X > X); +afficher " !\n"; +afficher "(X <= 0) = "; +afficher (X <= 0); +afficher " !\n"; +afficher "(X < 0) = "; +afficher (X < 0); +afficher " !\n"; +afficher "(X <= X) = "; +afficher (X <= X); +afficher " !\n"; +afficher "(X < X) = "; +afficher (X < X); +afficher " !\n"; +# Opérations booléennes +afficher "(X et X) = "; +afficher (X et X); +afficher " !\n"; +afficher "(X et 1) = "; +afficher (X et 1); +afficher " !\n"; +afficher "(X ou X) = "; +afficher (X ou X); +afficher " !\n"; +afficher "(X ou 1) = "; +afficher (X ou 1); +afficher " !\n"; +afficher "non X = "; +afficher (non X); +afficher " !\n"; +# Vérifier la définition d'une valeur +afficher "present(X) = "; +afficher (present(X)); +afficher " !\n"; +``` + +## Fichier irj : test.irj + +``` +#NOM +MON-TEST +#ENTREES-PRIMITIF +#CONTROLES-PRIMITIF +#RESULTATS-PRIMITIF +#ENTREES-CORRECTIF +#CONTROLES-CORRECTIF +#RESULTATS-CORRECTIF +## +``` + +## Commande + +``` +mlang --without_dfgip_m test.m -A mon_application --mpp_function indefini_test --run_test test.irj +``` diff --git a/source-doc/index.md b/source-doc/index.md index d1442dcea..35e121c07 100644 --- a/source-doc/index.md +++ b/source-doc/index.md @@ -13,6 +13,8 @@ # Documentation du langage M +## Le langage M + ```{toctree} :maxdepth: 2 @@ -20,5 +22,15 @@ intro syntax syntax_irj mlang -arithmetique ``` + +## Exemples + +```{toctree} +:maxdepth: 1 + +exemples/valeurs +``` + + + diff --git a/source-doc/intro.md b/source-doc/intro.md index b04c07879..a88c6b59e 100644 --- a/source-doc/intro.md +++ b/source-doc/intro.md @@ -138,7 +138,7 @@ Y = 1 ! ``` Pour comprendre la valeur finale de Y, référez-vous à la -section {ref}`arithmetique`. +section {ref}`valeurs`. ## Règles de calcul diff --git a/source-doc/syntax.md b/source-doc/syntax.md index bbd7dca9a..672e22217 100644 --- a/source-doc/syntax.md +++ b/source-doc/syntax.md @@ -511,3 +511,64 @@ Exemple: #{ Ceci est un commentaire sur plusieurs lignes. }# ``` + +(valeurs)= +## 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 {ref}`exemples/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 `vrai`e 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 = indefini` +* `indefini ou b = (0 si b = 0, 1 sinon)` +* `b ou indefini = (0 si b = 0, 1 sinon)` +* `indefini et indefini = indefini` +* `b et indefini = indefini` +* `indefini et b = indefini` +* `non 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éfini`e, 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 = indefini` +* `indefini + n = n` +* `n + indefini = n` +* `indefini - indefini = indefini` +* `indefini - n = -n` +* `n - indefini = n` +* `indefini * indefini = indefini` +* `indefini * n = indefini` +* `n * indefini = indefini` +* `indefini / indefini = indefini` +* `indefini / n = indefini` +* `n / indefini = indefini` + +Pour résumer, seules les opérations d'addition et de soustraction avec une +valeur renvoient autre chose que `indefini`. + From 494010038b2cb9a03848af6d90dfe4f7270f77a7 Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Mon, 15 Dec 2025 15:54:50 +0100 Subject: [PATCH 19/26] Poesie --- source-doc/syntax.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source-doc/syntax.md b/source-doc/syntax.md index 672e22217..b6e0e9cfb 100644 --- a/source-doc/syntax.md +++ b/source-doc/syntax.md @@ -521,7 +521,7 @@ 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 {ref}`exemples/valeurs` +dans l'exemple sur le {ref}`exemples/valeurs`. ### Calcul booléen From 70318ad0f69aa64ab7443380395c4609671f03fb Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Mon, 15 Dec 2025 17:53:32 +0100 Subject: [PATCH 20/26] =?UTF-8?q?Plein=20de=20fonctions=20rajout=C3=A9es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source-doc/fonctions.md | 92 +++++++++++++++++++++++++++++++++++++++++ source-doc/index.md | 1 + source-doc/syntax.md | 1 + 3 files changed, 94 insertions(+) create mode 100644 source-doc/fonctions.md diff --git a/source-doc/fonctions.md b/source-doc/fonctions.md new file mode 100644 index 000000000..558b4feee --- /dev/null +++ b/source-doc/fonctions.md @@ -0,0 +1,92 @@ +(fonctions)= +# Les fonctions + +Les fonctions prédéfinies sont gérées directement par le compilateur `mlang` +qui en définit le comportement par des instructions M. + +## abs(X) + +Cette fonction prend exactement un argument et renvoie sa valeur absolue. +Si `X` est `indefini`, alors `abs(X) = indefini`. + +## arr(X) + +Cette fonction prend exactement un argument et renvoie l'entier le plus +proche, ou `indefini` s'il est `indefini`. + +## inf(X) + +Cette fonction prend exactement un argument et renvoie l'entier inferieur +le plus proche, ou `indefini` s'il est `indefini`. + +## max(X, Y) + +Cette fonction prend exactement deux arguments et renvoie la plus grande +valeur des deux. +Si les deux valeurs sont `indefini`es, alors la fonction renvoie +`indefini`. +Si `X` est défini et `Y` est `indefini`, alors `max(X,Y) = max(X, 0)`. De même, +si `X` est `indéfini` et `Y` est defini, alors `max(X,Y) = max(0, Y)`. + +## min(X, Y) + +Cette fonction prend exactement deux arguments et renvoie la plus petite +valeur des deux. +Si les deux valeurs sont `indefini`es, alors la fonction renvoie +`indefini`. +Si `X` est défini et `Y` est `indefini`, alors `min(X,Y) = min(X, 0)`. De même, +si `X` est `indéfini` et `Y` est defini, alors `min(X,Y) = min(0, Y)`. + + +## null(X) + +Cette fonction prend exactement un argument `X` et renvoie `1` si `X` est +égal à `0`, `0` si `X` est défini et différent de `0`, +et `indefini` s'il est `indefini`. + +Cette fonction est strictement équivalente à l'expression `(X = 0)` + +## positif(X) + +Cette fonction prend exactement un argument `X` et renvoie `1` si `X` est +**strictement** supérieur à `0`, `0` si `X` est inferieur ou égal à `0`, et +`indefini` si `X` est indefini. + +Cette fonction est strictement équivalente à l'expression `X > 0`. + +## positif_ou_nul(X) + +Cette fonction prend exactement un argument `X` et renvoie `1` si `X` est +supérieur ou égale à `0`, `0` si `X` est strictement inferieur ou égal à +`0`, et `indefini` si `X` est indefini. + +Cette fonction est strictement équivalente à l'expression `X >= 0`. + +## present(X) + +Cette fonction prend exactement un argument `X` et renvoie `0` s'il +est `indefini` et `1` sinon. + +**Note** : cette fonction est la seule façon de tester si une valeur est +égale à `indefini` car l'expression booléenne `(indefini = indefini)` +est égale à `indefini`. + +## somme(X, Y, ...) + +Cette fonction n'a pas de limite d'arguments. +Elle calcule leur somme. +Si aucun argument n'est donné à la fonction `somme`, elle renvoie `0`. +Si tous ses arguments sont `indefini`s, alors elle renvoie la valeur +`indefini`. + +% TODO + +## multimax() + +## nb_evenements() + +## numero_compil() + +## numero_verif() + +## supzero() diff --git a/source-doc/index.md b/source-doc/index.md index 35e121c07..fda3161ec 100644 --- a/source-doc/index.md +++ b/source-doc/index.md @@ -20,6 +20,7 @@ intro syntax +fonctions syntax_irj mlang ``` diff --git a/source-doc/syntax.md b/source-doc/syntax.md index b6e0e9cfb..2863faabb 100644 --- a/source-doc/syntax.md +++ b/source-doc/syntax.md @@ -572,3 +572,4 @@ Les calculs impliquant la valeur `indefini` ont un comportement spécifique : Pour résumer, seules les opérations d'addition et de soustraction avec une valeur renvoient autre chose que `indefini`. +% A faire : les fonctions prédéfinies devraient avoir leur chapitre dedié From f259a9c444fe824e698aa4a854edd5efbc66bca2 Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Tue, 16 Dec 2025 15:16:49 +0100 Subject: [PATCH 21/26] Encore plein de fonctions en plus --- source-doc/fonctions.md | 89 ++++++++++++++++++++++++++++++++--------- 1 file changed, 71 insertions(+), 18 deletions(-) diff --git a/source-doc/fonctions.md b/source-doc/fonctions.md index 558b4feee..d28d3c700 100644 --- a/source-doc/fonctions.md +++ b/source-doc/fonctions.md @@ -1,46 +1,91 @@ (fonctions)= # Les fonctions -Les fonctions prédéfinies sont gérées directement par le compilateur `mlang` -qui en définit le comportement par des instructions M. - ## abs(X) -Cette fonction prend exactement un argument et renvoie sa valeur absolue. +Cette fonction prend un argument et renvoie sa valeur absolue. Si `X` est `indefini`, alors `abs(X) = indefini`. +## afficher(X) / afficher "texte" + +Cette fonction affiche sur la sortie standard la valeur de l'expression en argument. + ## arr(X) -Cette fonction prend exactement un argument et renvoie l'entier le plus +Cette fonction prend un argument et renvoie l'entier le plus proche, ou `indefini` s'il est `indefini`. +## attribut(X, attribut) + +Cette fonction prend un argument `X` et un nom d'attribut `a` et retourne +la valeur associée à l'attribut `a` de `X`. + +## champ_evenement(X, champ) + +Cette fonction prend un argument `X` et un nom de champ d'événement `champ`. +La valeur `X` correspond à l'identifiant de l'événement. %TODO: référence chap événement +Si le `champ` correspond à une valeur, `champ_evenement` la retourne. Si +le `champ` correspond à une variable, `champ_evenement` retourne sa valeur. + +**Note** : `champ_evenement` peut être utilisée pour assigner des valeurs et +des références à des événéments. Exemple: +``` +evenement +: valeur ev_val +: variable ev_var; + +# Associe la valeur 42 au champ ev_val de l'événement 0. +champ_evenement (0,ev_val) = 42; +# Associe la variable X au champ ev_var de l'événement 0. +champ_evenement (0,ev_var) reference X; +``` + ## inf(X) -Cette fonction prend exactement un argument et renvoie l'entier inferieur +Cette fonction prend un argument et renvoie l'entier inferieur le plus proche, ou `indefini` s'il est `indefini`. ## max(X, Y) -Cette fonction prend exactement deux arguments et renvoie la plus grande +Cette fonction prend deux arguments et renvoie la plus grande valeur des deux. Si les deux valeurs sont `indefini`es, alors la fonction renvoie `indefini`. Si `X` est défini et `Y` est `indefini`, alors `max(X,Y) = max(X, 0)`. De même, si `X` est `indéfini` et `Y` est defini, alors `max(X,Y) = max(0, Y)`. +## meme_variable(X, Y) + +Cette fonction prend en argument deux variables et vérifie s'il s'agit de la même +variable. +Elle est notamment utilisée dans les iterateurs de variables pour effectuer des +traitements spécifiques. + +## multimax(X, TAB) + +Cette fonction prend deux arguments `X` une valeur et `TAB` un tableau +de valeurs. +Elle calcule la plus grande valeur contenue dans `TAB` entre `0` et `X - 1`. +Si X est `indefini` ou `X <= 0`, alors `multimax(X, TAB) = indefini`. +`X` peut être plus grand que la taille de `TAB`, auquel cas `multimax` calculera le +maximum de `TAB`. + ## min(X, Y) -Cette fonction prend exactement deux arguments et renvoie la plus petite +Cette fonction prend deux arguments et renvoie la plus petite valeur des deux. Si les deux valeurs sont `indefini`es, alors la fonction renvoie `indefini`. Si `X` est défini et `Y` est `indefini`, alors `min(X,Y) = min(X, 0)`. De même, si `X` est `indéfini` et `Y` est defini, alors `min(X,Y) = min(0, Y)`. +## nb_evenements() + +Cette fonction renvoie le nombre total d'événements. ## null(X) -Cette fonction prend exactement un argument `X` et renvoie `1` si `X` est +Cette fonction prend un argument `X` et renvoie `1` si `X` est égal à `0`, `0` si `X` est défini et différent de `0`, et `indefini` s'il est `indefini`. @@ -48,7 +93,7 @@ Cette fonction est strictement équivalente à l'expression `(X = 0)` ## positif(X) -Cette fonction prend exactement un argument `X` et renvoie `1` si `X` est +Cette fonction prend un argument `X` et renvoie `1` si `X` est **strictement** supérieur à `0`, `0` si `X` est inferieur ou égal à `0`, et `indefini` si `X` est indefini. @@ -56,7 +101,7 @@ Cette fonction est strictement équivalente à l'expression `X > 0`. ## positif_ou_nul(X) -Cette fonction prend exactement un argument `X` et renvoie `1` si `X` est +Cette fonction prend un argument `X` et renvoie `1` si `X` est supérieur ou égale à `0`, `0` si `X` est strictement inferieur ou égal à `0`, et `indefini` si `X` est indefini. @@ -64,7 +109,7 @@ Cette fonction est strictement équivalente à l'expression `X >= 0`. ## present(X) -Cette fonction prend exactement un argument `X` et renvoie `0` s'il +Cette fonction prend un argument `X` et renvoie `0` s'il est `indefini` et `1` sinon. **Note** : cette fonction est la seule façon de tester si une valeur est @@ -79,14 +124,22 @@ Si aucun argument n'est donné à la fonction `somme`, elle renvoie `0`. Si tous ses arguments sont `indefini`s, alors elle renvoie la valeur `indefini`. -% TODO +## supzero(X) -## multimax() +Cette fonction prend un argument `X` et renvoie sa valeur s'il est strictement supérieur +à `0`, sinon il renvoie `indefini`. -## nb_evenements() +## taille(TAB) -## numero_compil() +Cette fonction prend en argument soit une variable, soit un tableau. +S'il s'agit d'une variable, `taille` renvoie `1`, sinon elle renvoie la taille du +tableau. +Elle échoue si l'argument est une constante ou une valeur. + +% TODO -## numero_verif() +% ## numero_compil() +% Unsupported, raises assert false! -## supzero() +% ## numero_verif() +% Unsupported as well From 0b42bde1cedd59132eccb9b59e10b5341e2d5b77 Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Tue, 16 Dec 2025 15:33:52 +0100 Subject: [PATCH 22/26] Exemple sur les fonctions --- source-doc/exemples/fonctions.md | 318 +++++++++++++++++++++++++++++++ source-doc/exemples/valeurs.md | 2 +- source-doc/fonctions.md | 4 + source-doc/index.md | 1 + 4 files changed, 324 insertions(+), 1 deletion(-) create mode 100644 source-doc/exemples/fonctions.md diff --git a/source-doc/exemples/fonctions.md b/source-doc/exemples/fonctions.md new file mode 100644 index 000000000..192936362 --- /dev/null +++ b/source-doc/exemples/fonctions.md @@ -0,0 +1,318 @@ +(exemples/fonctions)= + +# Les fonctions + +## Fichier test : test.m +``` +espace_variables GLOBAL : par_defaut; +domaine regle mon_domaine_de_regle: par_defaut; +domaine verif mon_domaine_de_verifications: par_defaut; +application mon_application; +variable calculee : attribut mon_attribut; + +evenement +: valeur ev_val +: variable ev_var; + +X : calculee mon_attribut = 0 : ""; +TAB : tableau[10] calculee mon_attribut = 2 : ""; + +cible init_tab: +application : mon_application; +iterer : variable I : entre 0..(taille(TAB) - 1) increment 1 : dans ( + TAB[I] = I; +) + +cible reinit_tab: +application : mon_application; +iterer : variable I : entre 0..(taille(TAB) - 1) increment 1 : dans ( + TAB[I] = indefini; +) + +cible test_abs: +application : mon_application; +afficher "\n__ABS__"; +afficher "\n abs(indefini) = "; +afficher (abs(indefini)); +afficher "\n abs(1) = "; +afficher (abs(1)); +afficher "\n abs(-1) = "; +afficher (abs(-1)); +afficher "\n"; + +cible test_arr: +application : mon_application; +afficher "\n__ARR__"; +afficher "\n arr(indefini) = "; +afficher (arr(indefini)); +afficher "\n arr(1.8) = "; +afficher (arr(1.8)); +afficher "\n arr(-1.7) = "; +afficher (arr(-1.7)); +afficher "\n"; + +cible test_attribut: +application : mon_application; +afficher "\n__ATTRIBUT__"; +afficher "\n attribut(X, mon_attribut) = "; +afficher (attribut(X, mon_attribut)); +afficher "\n attribut(TAB, mon_attribut) = "; +afficher (attribut(TAB, mon_attribut)); +afficher "\n"; + +cible test_champ_evenement_base: +application : mon_application; +afficher "\n champ_evenement(0, ev_val) = "; +afficher (champ_evenement (0,ev_val)); +afficher "\n champ_evenement(0, ev_var) = "; +afficher (champ_evenement (0,ev_var)); +afficher "\n"; + +cible test_champ_evenement: +application : mon_application; +afficher "\n__CHAMP_EVENEMENT__"; +arranger_evenements + : ajouter 1 + : dans ( + afficher "\nAvant d'initialiser les champs de l'événement:"; + calculer cible test_champ_evenement_base; + champ_evenement (0,ev_var) reference X; + champ_evenement (0,ev_val) = 42; + X = 2; + afficher "\n Après avoir initialisé les champs de l'événement:"; + calculer cible test_champ_evenement_base; + X = indefini; + ) + +cible test_inf: +application : mon_application; +afficher "\n__INF__"; +afficher "\n inf(indefini) = "; +afficher (inf(indefini)); +afficher "\n inf(1.8) = "; +afficher (inf(1.8)); +afficher "\n inf(-1.7) = "; +afficher (inf(-1.7)); +afficher "\n"; + +cible test_max: +application : mon_application; +afficher "\n__MAX__"; +afficher "\n max(indefini, indefini) = "; +afficher (max(indefini, indefini)); +afficher "\n max(-1, indefini) = "; +afficher (max(-1, indefini)); +afficher "\n max(indefini, -1) = "; +afficher (max(indefini, -1)); +afficher "\n max(1, indefini) = "; +afficher (max(1, indefini)); +afficher "\n"; + +cible test_meme_variable: +application : mon_application; +afficher "\n__MEME_VARIABLE__"; +afficher "\n meme_variable(X,X) = "; +afficher (meme_variable(X,X)); +afficher "\n meme_variable(X,TAB) = "; +afficher (meme_variable(X,TAB)); +afficher "\n meme_variable(TAB[0],TAB) = "; +afficher (meme_variable(TAB[0],TAB)); +afficher "\n"; + +cible test_min: +application : mon_application; +afficher "\n__MIN__"; +afficher "\n min(indefini, indefini) = "; +afficher (min(indefini, indefini)); +afficher "\n min(1, indefini) = "; +afficher (min(1, indefini)); +afficher "\n min(indefini, 1) = "; +afficher (min(indefini, 1)); +afficher "\n min(-1, indefini) = "; +afficher (min(-1, indefini)); +afficher "\n"; + +cible test_multimax_base: +application : mon_application; +afficher "\n multimax(indefini, TAB) = "; +afficher (multimax(indefini, TAB)); +afficher "\n multimax(7, TAB) = "; +afficher (multimax(7, TAB)); +afficher "\n multimax(taille(TAB) + 1, TAB) = "; +afficher (multimax(taille(TAB) + 1, TAB)); +afficher "\n multimax(0, TAB) = "; +afficher (multimax(0, TAB)); +afficher "\n multimax(-1, TAB) = "; +afficher (multimax(-1, TAB)); + +cible test_multimax: +application : mon_application; +afficher "\n__MULTIMAX__"; +afficher "\nAvant initialisation du tableau :"; +calculer cible test_multimax_base; +calculer cible init_tab; +afficher "\nAprès initialisation du tableau :"; +calculer cible test_multimax_base; +calculer cible reinit_tab; +afficher "\n"; + +cible test_nb_evenements_base: +application : mon_application; +afficher "\n nb_evenements() = "; +afficher (nb_evenements ()); +afficher "\n"; + +cible test_nb_evenements: +application : mon_application; +afficher "\n__NB_EVENEMENTS__"; +afficher "\nAvant la définition d'un événement :"; +calculer cible test_nb_evenements_base; +arranger_evenements + : ajouter 1 + : dans ( + afficher "\nPendant la définition d'un événement :"; + calculer cible test_nb_evenements_base; + ) +afficher "\nAprès la définition d'un événement :"; +calculer cible test_nb_evenements_base; + +cible test_null: +application : mon_application; +afficher "\n__NULL__"; +afficher "\n null(indefini) = "; +afficher (null(indefini)); +afficher "\n null(0) = "; +afficher (null(0)); +afficher "\n null(1) = "; +afficher (null(1)); +afficher "\n"; + +cible test_positif: +application : mon_application; +afficher "\n__POSITIF__"; +afficher "\n positif(indefini) = "; +afficher (positif(indefini)); +afficher "\n positif(0) = "; +afficher (positif(0)); +afficher "\n positif(1) = "; +afficher (positif(1)); +afficher "\n positif(-1) = "; +afficher (positif(-1)); +afficher "\n"; + +cible test_positif_ou_nul: +application : mon_application; +afficher "\n__POSITIF OU NUL__"; +afficher "\n positif_ou_nul(indefini) = "; +afficher (positif_ou_nul(indefini)); +afficher "\n positif_ou_nul(0) = "; +afficher (positif_ou_nul(0)); +afficher "\n positif_ou_nul(1) = "; +afficher (positif_ou_nul(1)); +afficher "\n positif_ou_nul(-1) = "; +afficher (positif_ou_nul(-1)); +afficher "\n"; + +cible test_present: +application : mon_application; +afficher "\n__PRESENT__"; +afficher "\n present(indefini) = "; +afficher (present(indefini)); +afficher "\n present(0) = "; +afficher (present(0)); +afficher "\n present(1) = "; +afficher (present(1)); +afficher "\n"; + +cible test_somme: +application : mon_application; +afficher "\n__SOMME__"; +afficher "\n somme() = "; +afficher (somme()); +afficher "\n somme(indefini) = "; +afficher (somme(indefini)); +afficher "\n somme(1, indefini) = "; +afficher (somme(1, indefini)); +afficher "\n somme(1, 2, 3, 4, 5) = "; +afficher (somme(1, 2, 3, 4, 5)); +afficher "\n"; + +cible test_supzero: +application : mon_application; +afficher "\n__SUPZERO__"; +afficher "\n supzero(indefini) = "; +afficher (supzero(indefini)); +afficher "\n supzero(42) = "; +afficher (supzero(42)); +afficher "\n supzero(-1) = "; +afficher (supzero(-1)); +afficher "\n supzero(0) = "; +afficher (supzero(0)); +afficher "\n"; + +cible test_taille: +application : mon_application; +afficher "\n__TAILLE__"; +afficher "\n taille(TAB) = "; +afficher (taille(TAB)); +afficher "\n taille(X) = "; +afficher (taille(X)); +afficher "\n"; + +cible fun_test: +application : mon_application; +# Abs +calculer cible test_abs; +# Arr +calculer cible test_arr; +# Attribut +calculer cible test_attribut; +# Champ evenement +calculer cible test_champ_evenement; +# Inf +calculer cible test_inf; +# Max +calculer cible test_max; +# Meme variable +calculer cible test_meme_variable; +# Min +calculer cible test_min; +# Multimax +calculer cible test_multimax; +# Null +calculer cible test_nb_evenements; +# Null +calculer cible test_null; +# Positif +calculer cible test_positif; +# Positif ou nul +calculer cible test_positif_ou_nul; +# Présent +calculer cible test_present; +# Somme +calculer cible test_somme; +# Supzero +calculer cible test_supzero; +# Taille +calculer cible test_taille; +``` + +## Fichier irj : test.irj + +``` +#NOM +MON-TEST +#ENTREES-PRIMITIF +#CONTROLES-PRIMITIF +#RESULTATS-PRIMITIF +#ENTREES-CORRECTIF +#CONTROLES-CORRECTIF +#RESULTATS-CORRECTIF +## +``` + +## Commande + +``` +mlang --without_dfgip_m test.m -A mon_application --mpp_function fun_test --run_test test.irj +``` diff --git a/source-doc/exemples/valeurs.md b/source-doc/exemples/valeurs.md index fb0f603fe..ff8bae647 100644 --- a/source-doc/exemples/valeurs.md +++ b/source-doc/exemples/valeurs.md @@ -2,7 +2,7 @@ # Calcul des valeurs - ## Fichier test : test.m +## Fichier test : test.m ``` espace_variables GLOBAL : par_defaut; domaine regle mon_domaine_de_regle: par_defaut; diff --git a/source-doc/fonctions.md b/source-doc/fonctions.md index d28d3c700..cda4e8ea1 100644 --- a/source-doc/fonctions.md +++ b/source-doc/fonctions.md @@ -1,6 +1,10 @@ (fonctions)= # Les fonctions +Voici la liste de toutes les fonctions standard du M. +Leur utilisation est présentée dans l'exemple sur +{ref}`exemples/fonctions`. + ## abs(X) Cette fonction prend un argument et renvoie sa valeur absolue. diff --git a/source-doc/index.md b/source-doc/index.md index fda3161ec..76983d7be 100644 --- a/source-doc/index.md +++ b/source-doc/index.md @@ -31,6 +31,7 @@ mlang :maxdepth: 1 exemples/valeurs +exemples/fonctions ``` From b7aa6660f41419309d52ff993d76d73f80b84224 Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Tue, 16 Dec 2025 15:36:14 +0100 Subject: [PATCH 23/26] Poesie --- source-doc/exemples/fonctions.md | 6 +++++- source-doc/exemples/valeurs.md | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/source-doc/exemples/fonctions.md b/source-doc/exemples/fonctions.md index 192936362..a2a7f7795 100644 --- a/source-doc/exemples/fonctions.md +++ b/source-doc/exemples/fonctions.md @@ -314,5 +314,9 @@ MON-TEST ## Commande ``` -mlang --without_dfgip_m test.m -A mon_application --mpp_function fun_test --run_test test.irj +mlang test.m \ + --without_dfgip_m \ + -A mon_application \ + --mpp_function fun_test \ + --run_test test.irj ``` diff --git a/source-doc/exemples/valeurs.md b/source-doc/exemples/valeurs.md index ff8bae647..2ab328aae 100644 --- a/source-doc/exemples/valeurs.md +++ b/source-doc/exemples/valeurs.md @@ -133,5 +133,9 @@ MON-TEST ## Commande ``` -mlang --without_dfgip_m test.m -A mon_application --mpp_function indefini_test --run_test test.irj +mlang test.m \ + --without_dfgip_m \ + -A mon_application \ + --mpp_function indefini_test \ + --run_test test.irj ``` From 7ec878a55bf8c8302d6e7e15681a176f688d4dea Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Tue, 16 Dec 2025 15:45:53 +0100 Subject: [PATCH 24/26] OLIVE --- source-doc/index.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source-doc/index.md b/source-doc/index.md index 76983d7be..d3cd2fb4b 100644 --- a/source-doc/index.md +++ b/source-doc/index.md @@ -2,12 +2,12 @@
- .____. ________________________ - | ._ ' | | - | | \ | Direction Générale des | -.-+-+-' | | - | | | Finances Publiques | - ! ! !________________________! + .____. ________________________ + | ._ ' | | + | | \ | Direction Générale des | + .-+-+-' | | + | | | Finances Publiques | + ! ! !________________________!
From 3c727741e10eb9a3fc88efab13494a2433b577bd Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Tue, 16 Dec 2025 16:09:07 +0100 Subject: [PATCH 25/26] =?UTF-8?q?D=C3=A9placement=20dans=20doc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 9 +++++---- doc/architecture.png | Bin 63846 -> 0 bytes {source-doc => doc}/conf.py | 0 {source-doc => doc}/exemples/fonctions.md | 0 {source-doc => doc}/exemples/valeurs.md | 0 {source-doc => doc}/fonctions.md | 0 {source-doc => doc}/index.md | 0 {source-doc => doc}/intro.md | 0 {source-doc => doc}/mlang.md | 0 {source-doc => doc}/syntax.md | 0 {source-doc => doc}/syntax_irj.md | 0 11 files changed, 5 insertions(+), 4 deletions(-) delete mode 100644 doc/architecture.png rename {source-doc => doc}/conf.py (100%) rename {source-doc => doc}/exemples/fonctions.md (100%) rename {source-doc => doc}/exemples/valeurs.md (100%) rename {source-doc => doc}/fonctions.md (100%) rename {source-doc => doc}/index.md (100%) rename {source-doc => doc}/intro.md (100%) rename {source-doc => doc}/mlang.md (100%) rename {source-doc => doc}/syntax.md (100%) rename {source-doc => doc}/syntax_irj.md (100%) diff --git a/Makefile b/Makefile index 794285c28..7c0822ee7 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,8 @@ sphinx-doc: FORCE @command -v sphinx-build >/dev/null 2>&1 || \ { echo "Pour construire la documentation, vous avez besoin de sphinx-build avec \ l'extension 'myst-parser'."; exit 1; } - rm -rf _build/default/source-doc/* - cp -rf source-doc/* _build/default/source-doc/ - sphinx-build -M html _build/default/source-doc/ doc/sphinx/ - sphinx-build -M latexpdf _build/default/source-doc/ doc/sphinx/ + rm -rf _build/default/doc/* + cp -rf doc/* _build/default/doc/ + mkdir -p examples/doc + sphinx-build -M html _build/default/doc/ examples/doc + sphinx-build -M latexpdf _build/default/doc/ examples/doc diff --git a/doc/architecture.png b/doc/architecture.png deleted file mode 100644 index 20c96e2f8e8f49731791c1ec313df875206ec756..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63846 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 diff --git a/source-doc/conf.py b/doc/conf.py similarity index 100% rename from source-doc/conf.py rename to doc/conf.py diff --git a/source-doc/exemples/fonctions.md b/doc/exemples/fonctions.md similarity index 100% rename from source-doc/exemples/fonctions.md rename to doc/exemples/fonctions.md diff --git a/source-doc/exemples/valeurs.md b/doc/exemples/valeurs.md similarity index 100% rename from source-doc/exemples/valeurs.md rename to doc/exemples/valeurs.md diff --git a/source-doc/fonctions.md b/doc/fonctions.md similarity index 100% rename from source-doc/fonctions.md rename to doc/fonctions.md diff --git a/source-doc/index.md b/doc/index.md similarity index 100% rename from source-doc/index.md rename to doc/index.md diff --git a/source-doc/intro.md b/doc/intro.md similarity index 100% rename from source-doc/intro.md rename to doc/intro.md diff --git a/source-doc/mlang.md b/doc/mlang.md similarity index 100% rename from source-doc/mlang.md rename to doc/mlang.md diff --git a/source-doc/syntax.md b/doc/syntax.md similarity index 100% rename from source-doc/syntax.md rename to doc/syntax.md diff --git a/source-doc/syntax_irj.md b/doc/syntax_irj.md similarity index 100% rename from source-doc/syntax_irj.md rename to doc/syntax_irj.md From aec2d86dbad1663aabe4b4ba84b058d512805642 Mon Sep 17 00:00:00 2001 From: Steven de Oliveira Date: Tue, 16 Dec 2025 16:22:09 +0100 Subject: [PATCH 26/26] Ajout d'une regle pour construire la doc facilement --- Makefile | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 7c0822ee7..52a0a137b 100644 --- a/Makefile +++ b/Makefile @@ -39,12 +39,16 @@ clean: FORCE remise_a_zero_versionnage rm -f doc/doc.html dune clean +doc-deps: FORCE + python3 -m venv .venv + .venv/bin/pip install sphinx myst-parser + sphinx-doc: FORCE - @command -v sphinx-build >/dev/null 2>&1 || \ + @command -v .venv/bin/sphinx-build >/dev/null 2>&1 || \ { echo "Pour construire la documentation, vous avez besoin de sphinx-build avec \ - l'extension 'myst-parser'."; exit 1; } + l'extension 'myst-parser'. Lancez `make doc-deps`."; exit 1; } rm -rf _build/default/doc/* cp -rf doc/* _build/default/doc/ mkdir -p examples/doc - sphinx-build -M html _build/default/doc/ examples/doc - sphinx-build -M latexpdf _build/default/doc/ examples/doc + .venv/bin/sphinx-build -M html _build/default/doc/ examples/doc + .venv/bin/sphinx-build -M latexpdf _build/default/doc/ examples/doc