Metteur en page de sources Ada
Cette application permet d'effectuer la mise en page de sources Ada (pour le lecteur humain; elle ne change rien pour le compilateur). Pour ceci, une simple analyse lexicale se montrant insuffisante, on a bien besoin d'une analyse syntaxique des sources.
L'application importe des services de :
Sans noms de fichiers en paramètres, comme dans les deux applications précédantes, elle travaille sur les canaux standard d'E/S.
Les erreurs de syntaxe dans le code provoquent l'arrêt de la mise en page. Dans le cas où une erreur est détectée, l'application va le signaler, en indiquant sur forme de commentaire Ada les numéros de ligne et de colonne où l'erreur se trouve, pour ensuite copier le reste du fichier d'entrée tel quel dans le fichier de sortie. Du point de vue d'un compilateur, le résultat n'est pas modifié.
En outre, dans le cas où on dépasse le nombre maximum de caractères autorisés par ligne, une nouvelle ligne contenant la partie du code qui excède cette limite va être générée.
Forme générale de la commande :
structure [-i<indentation>] [-c<caractères_par_ligne>]
[in_file [out_file]]
(1) Nombre de caractères d'indentation :
(2) Nombre maximum de caractères par ligne :
(3) Fichier d'entrée :
(4) Fichier de sortie (seulement si le fichier d'entrée a été spécifié) :
Pour l'analyse syntaxique des sources, on va se servir du composant GRAMACT [STROHMEIER92].
GRAMACT est un projet de recherche du LGL. Il permet de réaliser des programmes d'application traitant des sources en insérant des actions dans une grammaire préexistante. Ces actions sont activées au moment des dérivations des règles de la grammaire.
GRAMOL est le formalisme utilisé dans GRAMACT pour décrire la grammaire d'un langage. Dans le cas qui nous concerne, on va utiliser la description en GRAMOL du langage Ada [LRM87].
Le deuxième élément qui nous intéresse dans GRAMACT est le programme d'extraction d'actions Extract. Ce programme permet d'extraire les actions qui ont été placées sur la grammaire et de produire le fichier de paramétrisation de l'analyseur syntaxique.
Enfin, le dernier élément intervenant est l'application "structure" elle-même, qui réalise la mise en page des sources Ada. Elle utilise l'analyseur syntaxique Syntax_Analyser_G fournit par GRAMACT en forme de paquetage générique. Ce paquetage implémente l'interprète qui effectue l'analyse syntaxique, et qui, durant celle-ci, signale les actions rencontrées pour permettre à l'application de les exécuter.
D'après son architecture (figure 3), on peut remarquer que l'application est facilement adaptable à plusieurs styles de mise en page. En effet, il suffit d'avoir pour chaque style un fichier avec la grammaire "décorée" du langage, qui servira à initialiser l'analyseur syntaxique. A noter que, dans tous les cas, l'application reste inchangée.
En plus d'analyser syntaxiquement le code, on tient aussi compte des commentaires, qui n'appartiennent pas à la syntaxe du langage, mais qui servent à "décorer" le code source.
On peut donc dire que cette application ne se limite pas à une analyse syntaxique pure, mais elle va plus loin. Et c'est au niveau de traitement des commentaires que l'analyseur syntaxique de GRAMACT montre quelques faiblesses, qu'on peut considérer normales si on tient compte qu'il s'agit d'éléments n'appartenant pas à la syntaxe.
Figure 3. Architecture de l'application "structure".
Les critères pour effectuer la mise en page des sources Ada ont été établis à l'aide du document "Ada Quality and Style" [SPC92] :
(1) Laisser un espace de séparation au moins :
(2) Ne pas laisser des espaces de séparation :
(3) Exemples d'indentation des structures du langage :
Il s'agit ici de deux aspect primordiaux :
Les actions définies ont comme caractéristique importante leur simplicité ou atomicité : elles ne font pas plusieurs opérations en même temps, mais une opération précise et simple.
Pour produire plusieurs effets, on va donc combiner un certain nombre d'actions dans l'ordre correct.
L'emplacement des différents éléments lexicaux dans le fichier de sortie va être fait à l'aide de la variable globale Colonne et des primitives de Text_IO.
Les actions qui ont été définies sont les suivantes :
LINE
Text_IO.New_Line;
Passe le fichier de sortie à la ligne suivante.
SET
Text_IO.Set_Col (Colonne);
Positionne le fichier de sortie dans la colonne indiquée par Colonne.
SPACE
Text_IO.Put (Blank);
Ecrit un espace de séparation.
AVANCE
Colonne := Colonne + 1;
Incrémente d'une unité la valeur de Colonne.
RECULE
Colonne := Colonne - 1;
Décremente d'une unité la valeur de Colonne.
INCR
Colonne := Colonne + Positive_Count (Indentation);
Incrémente Colonne du nombre de caractères d'indentation donné en paramètre.
DECR
Colonne := Colonne - Positive_Count (Indentation);
Décremente Colonne du nombre de caractères d'indentation donné en paramètre.
AVIS_DECR
Decrementer := Decrementer + 1;
Augmente d'une unité le nombre de fois qu'on va devoir décrementer Colonne pour revenir à la position adéquate. Il s'agit d'une action qui sert par exemple à mettre à jour une variable d'état indiquant qu'on est dans le contexte d'une instruction "block" dont un nom a été donné, et par conséquence toute l'instruction doit être indentée par rapport au nom.
L'emploi d'une variable numérique au lieu d'une variable booléenne répond au fait qu'il est possible de trouver plusieurs cas "imbriqués". En effet, dans le cas où une variable booléenne serait employée, on ne tiendrait compte que d'un seul avis, en perdant le reste.
DECR_EV
if Decrementer > 0 then
Colonne := Colonne - Positive_Count (Indentation);
Decrementer := Decrementer - 1;
end if;
Décremente Colonne (du nombre de caractères d'indentation donné en paramètre) dans le cas où on se trouve dans le contexte d'une instruction "block" dont un nom a été donné. De même, la variable qui indique ce fait est mise à jour.
A l'aide des actions qu'on vient de décrire, la démarche à suivre pour effectuer la mise en page serait :
Ci-dessous on montre quelques exemples de règles "décorées" :
a) Règle définissant la clause de contexte "with" :
Règle décorée avec des actions :
Exemple :
Résultat :
b) Règle définissant l'instruction "if" :
Règle décorée avec des actions :
Exemple :
Résultat :
c) Règle définissant l'instanciation des paquetages génériques :
Règle décorée avec des actions :
Exemple :
Résultat :
Etant donné le fichier comparer.a :
(1) structure comparer.a :
(2) structure comparer.a | apparence -iu :
(3) structure -i4 comparer.a | ada_to_postscript :
Exemple contenant une erreur de syntaxe ("elseif" au lieu de "elsif") :
(4) structure comparer.a :
Generated with CERN WebMaker
6.1. Description
6.2. Options
6.3. Emploi de GRAMACT
6.4. Critères de mise en page
begin
<<étiquette>>
<instruction>
end;
if <condition> then | <nom>:
<instructions> | loop
elsif <condition> then | <instructions>
<instructions> | exit when <condition>;
else | <instructions>
<instructions> | end loop <nom>;
end if;
<nom>: | <nom>:
for <schéma> loop | while <condition> loop
<instructions> | <instructions>
end loop <nom>; | end loop <nom>;
<nom>: | case <expression> is
declare | when <choix> =>
<déclarations> | <instructions>
begin | when <choix> =>
<instructions> | <instructions>
exception | when others =>
when <choix> => | <instructions>
<instructions> | end case;
when others =>
<instructions>
end <nom>;
separate (<unité père>)
<corps>
procedure <spécification> is | package body <nom> is
<déclarations> | <déclarations>
begin | begin
<instructions> | <instructions>
exception | exception
when <choix> => | when <choix> =>
<instructions> | <instructions>
end <nom>; | end <nom>;
function <spécification> | task body <nom> is
return <nom de type> is | <déclarations>
<déclarations> | begin
begin | <instructions>
<instructions> | exception
exception | when <choix> =>
when <choix> => | <instructions>
<instructions> | end <nom>;
end <nom>;
with | function <spécification>
<nom>; | return <type>;
use | package <nom> is
<nom>; | <déclarations>
| private
| <déclarations>;
<unité de compilation> | end <nom>;
generic | task type <nom> is
<paramètres formels> | <entry déclarations>
<unité de compilation> | end <nom>;
procedure <nom> is | type <nom>
new <nom générique> | <discriminants> is
<paramètres actuels> | record
| <composants>
function <nom> is | case <discriminant> is
new <nom générique> | when <choix> =>
<paramètres actuels> | <composants>
| when <choix> =>
package <nom> is | <composants>
new <nom générique> | end case;
<paramètres actuels> | end record;
function <nom> | procedure <nom>
(Paramètre_1; | (Paramètre_1;
Paramètre_2; | Paramètre_2;
... | ...
Paramètre_n) | Paramètre_n);
return <type>;
6.5. Définition des actions
with_clause = "WITH" {+ simple_name $ "," +} ";" .
with_clause = "WITH" <+LINE, INCR+>
{+ <+SET+> simple_name $ "," <+LINE+> +} ";"
<+LINE, DECR+> .
with Calendar, Command_Line, Text_IO;
with
Calendar,
Command_Line,
Text_IO;
if_statement = "IF" condition "THEN" sequence_of_statements
{ "ELSIF" condition "THEN" sequence_of_statements }
[ "ELSE" sequence_of_statements ] "END" "IF" ";" .
if_statement = "IF" <+SPACE+> condition <+SPACE+> "THEN"
sequence_of_statements <+LINE, SET+>
{ "ELSIF" <+SPACE+> condition <+SPACE+> "THEN"
sequence_of_statements <+LINE, SET+> }
[ "ELSE" sequence_of_statements <+LINE, SET+> ]
"END" <+SPACE+> "IF" ";" .
if condition_1 then action_1; action_2;
elsif condition_2 then action_3;
else action_4; action_5;
end if;
if condition_1 then
action_1;
action_2;
elsif condition_2 then
action_3;
else
action_4;
action_5;
end if;
generic_instanciation = "PACKAGE" simple_name "IS" "NEW" package_name
[ generic_actual_part ] ";" .
generic_instanciation = "PACKAGE" <+SPACE+> simple_name <+SPACE+> "IS"
<+INCR, LINE, SET+> "NEW" <+SPACE+> package_name
[ generic_actual_part ] ";" <+DECR+> .
package Ada_To_PostScript is new Ada_To_Foo_G
( Put_Page, Put_Empty, Put_Newline, Put_Line_Number, Put_Blank,
Put_Reserved, Put_Identifier, Put_Numeric, Put_String, Put_Comment,
Put_Character, Put_Delimiter, Put_Substitute );
package Ada_To_PostScript is
new Ada_To_Foo_G
(Put_Page,
Put_Empty,
Put_Newline,
Put_Line_Number,
Put_Blank,
Put_Reserved,
Put_Identifier,
Put_Numeric,
Put_String,
Put_Comment,
Put_Character,
Put_Delimiter,
Put_Substitute);
6.6. Exemples
---------------------------------------------------------
function Comparer ( Element_1, Element_2 : Type_Element )
return Integer is
begin
if Element_1 > Element_2 then return 1;
elsif Element_1 = Element_2 then return 0;
else return -1;
end if;
end Comparer;
---------------------------------------------------------
----------------------------------
function Comparer
(Element_1,
Element_2 : Type_Element)
return Integer is
begin
if Element_1 > Element_2 then
return 1;
elsif Element_1 = Element_2 then
return 0;
else
return -1;
end if;
end Comparer;
----------------------------------
----------------------------------
function COMPARER
(ELEMENT_1,
ELEMENT_2 : TYPE_ELEMENT)
return INTEGER is
begin
if ELEMENT_1 > ELEMENT_2 then
return 1;
elsif ELEMENT_1 = ELEMENT_2 then
return 0;
else
return -1;
end if;
end COMPARER;
----------------------------------
1 ------------------------------------
2 function Comparer
3 (Element_1,
4 Element_2 : Type_Element)
5 return Integer is
6 begin
7 if Element_1 > Element_2 then
8 return 1;
9 elsif Element_1 = Element_2 then
10 return 0;
11 else
12 return -1;
13 end if;
14 end Comparer;
15 ------------------------------------
---------------------------------------------------------
function Comparer ( Element_1, Element_2 : Type_Element )
return Integer is
begin
if Element_1 > Element_2 then return 1;
elseif Element_1 = Element_2 then return 0;
else return -1;
end if;
end Comparer;
---------------------------------------------------------
----------------------------------
function Comparer
(Element_1,
Element_2 : Type_Element)
return Integer is
begin
if Element_1 > Element_2 then
return 1;
-- ***** SYNTAX ERROR at line : 5, column : 3
elseif Element_1 = Element_2 then return 0;
else return -1;
end if;
end Comparer;
-----------------------------------------------
Metteur en page de sources Ada - 29 MAR 95
[Next] [Previous] [Top]