Les premiers pas
Suivons les étapes de développement d'un programme simple et expliquons ainsi quelques concepts fondamentaux de la programmation et des fonctionnalités de base de Modula-2. La tâche consiste, étant donné deux nombres naturels x et y, à calculer leur plus grand diviseur commun (gcd). Les connaissances mathématiques nécessaires pour ce problème sont les suivantes :
- Si x est égal à y, x (ou y) est le résultat souhaité.
- Le gcd de deux nombres reste inchangé, si nous remplaçons par le plus grand, la différence des nombres, c'est-à-dire soustrayons le plus petit nombre du plus grand.
Exprimées en termes mathématiques, ces règles prennent la forme :
|
La recette de base, appelée algorithme, est alors la suivante : on modifie les nombres x et y selon la règle 2 de telle sorte que leur différence diminue. On répète cette opération jusqu'à ce qu'ils soient égaux. La règle 2 garantit que les modifications sont telles que gcd(x,y) reste toujours le même, et la règle 1 garantit que l'on trouve finalement le résultat.
Il faut maintenant mettre ces recommandations en termes de Modula-2. Une première tentative conduit au schéma suivant. Notez que le symbole # signifie "inégal".
La phrase entre guillemets est en français simple. La deuxième version affine la première version en remplaçant de la phrase en français par des termes formels&nbps;:
Ce texte n'est pas encore un programme complet, mais il montre déjà les caractéristiques essentielles d'un langage de programmation structuré. La version 1 est une instruction, et cette instruction contient une autre instruction subordonnée (entre guillemets). Dans la version 2, celle-ci est élaborée, et d'autres instructions subordonnées apparaissent (exprimant le remplacement d'une valeur x par une autre valeur x-y). Cette hiérarchie d'instructions exprime la structure sous-jacente de l'algorithme. Elle devient explicite en raison de la structure du langage de programmation, permettant l'imbrication des composantes d'un programme. Il est donc important de connaître la structure du langage (syntaxe) dans ses moindres détails. Textuellement, nous exprimons l'imbrication ou la subordination par une indentation appropriée. Bien que cela ne soit pas exigé par les règles du langage de programmation, cela aide considérablement à la compréhension d'un texte.
Refléter la structure inhérente d'un algorithme par la structure textuelle du programme est une idée clef de la programmation structurée. Il est pratiquement impossible de reconnaître le sens d'un programme lorsque sa structure est supprimée, comme le fait un compilateur lors de la production d'un code informatique. Et nous devons garder à l'esprit qu'un programme n'a aucune valeur s'il n'existe pas sous une forme dans laquelle un humain peut le comprendre et avoir confiance en sa conception.
Nous nous attaquons maintenant à l'objectif de produire un programme complet à partir du fragment ci-dessus. Nous nous rendons compte que nous devons spécifier une action affectant des valeurs initiales aux variables x et y, ainsi qu'une action rendant le résultat visible. Pour cela, nous devons connaître les moyens dont dispose un ordinateur pour communiquer avec son utilisateur. Comme nous ne voulons pas faire référence à une machine spécifique, et surtout pas à des abstractions de ces moyens de communication, en postulant qu'ils seront disponibles, la programmation est dite possible. Ces abstractions prennent la forme d'instructions standard, comme indiqué ci-dessous. L'entrée de données est appelée une opération Read, leur sortie une opération Write. Nous pouvons, par exemple, supposer que les données sont lues à partir d'un clavier et écrites sur un écran.
La procédure ReadInt lit un entier (non négatif) et l'affecte à son paramètre (x). La procédure WriteInt génère un cardinal tel que spécifié par le premier paramètre (x). Le deuxième paramètre 6, indique le nombre de chiffres disponibles pour la représentation de cette valeur sur le support de sortie.
Dans la prochaine et dernière version, nous complétons notre texte de telle sorte qu'il devienne un véritable programme Module.
Les ajouts essentiels de cette étape sont ce que l'on appelle des déclarations. Dans Modula-2, tous les noms d'objets apparaissant dans un programme, tels que les variables et les constantes, doivent être déclarés. Une déclaration introduit l'identificateur de l'objet (Name), spécifie le type de l'objet (s'il s'agit d'une variable, d'une constante ou autre chose) et indique des propriétés générales et invariantes, telles que le type d'une variable ou la valeur d'une constante.
L'ensemble du programme est appelé un module, on lui donne un nom (gcd) et il a le format suivant :
MODULE name; <import lists> <declarations > BEGIN <statements> END name. |
Quelques commentaires supplémentaires concernant notre exemple s'imposent. Les procédures WriteLn, WriteString, ReadInt et WriteInt ne font pas partie du langage de programmation Modula-2 lui-même. Elles sont définies dans un autre module appelé InOut étant censé être disponible. Nous soulignons simplement ici qu'ils doivent être importés pour être connus dans un programme. Cela se fait en incluant les noms des objets nécessaires dans une liste d'importation et en spécifiant à partir de quel module ils sont demandés.
La procédure WriteString génère une chaîne de caractèrers, c'est-à-dire une séquence de caractères (entre guillemets). Cette sortie permet à l'utilisateur de l'ordinateur de savoir qu'une entrée est demandée ultérieurement, une caractéristique essentielle des systèmes conversationnels. La procédure WriteLn termine une ligne dans le texte de sortie.
Et ceci conclut la discussion de notre premier exemple. Elle a été maintenue assez informelle. Cela est admissible car le but était d'expliquer un programme existant. Cependant, la programmation consiste à concevoir, à créer de nouveaux programmes. Pour cela, seule une description précise et formelle de notre outil est suffisante.