Langages de haut niveau
Introduction Un assembleur est un programme traduisant en code machine un programme écrit à l'aide des mnémoniques Les langages d'assemblage représentent une deuxième génération de langages, après les langages machine. Toutefois, la différence entre les deux générations se situe simplement au niveau de la syntaxe, puisque les primitives sont les mêmes Le transfert d'un programme écrit en assembleur vers un autre processeur n'est pas une tâche aisée Une troisième génération de langages utilise des primitives de plus haut niveau, indépendantes de la machine. Les deux exemples les plus connus sont: FORTRAN (Formula Translator), développé pour des applications scientifiques, et COBOL (Common Business-Oriented Language), développé par l'us Navy pour des applications commerciales Page 2
L'approche suivie par cette troisième génération était d'identifier un ensemble de primitives de haut niveau utilisables pour développer le logiciel Chacune de ces primitives devait pouvoir être implémentée comme une séquence des primitives de bas niveau disponibles dans les langages machine Un traducteur est ensuite nécessaire pour transformer les primitives de haut niveau en séquences d'instructions machine: c'est le compilateur Le premier compilateur a été écrit par Grace Hopper Un autre type de traducteur est l'interpréteur. Dans ce cas, les instructions machine sont exécutées au fur et à mesure qu'elles sont générées, au lieu d'être stockées dans un fichier pour une utilisation ultérieure Page 3
Les problèmes de portabilité n'ont pas été tous résolus par les langages de troisième génération Certains de ces problèmes disparaissent avec une standardisation du langage, le plus souvent menée à bien par deux organisations: ANSI (American National Standards Institute) et ISO (International Organization for Standardization) Parfois les fabricants du compilateur ajoutent des "extensions" au langage qui le rendent incompatible avec d'autres produits Pour les générations suivantes, l'ambition s'est déplacée de la portabilité vers la communication avec l'ordinateur en utilisant des concepts abstraits. Ou, mieux encore, vers une découverte par l'ordinateur d'une partie de l'algorithme à exécuter Page 4
Paradigmes de programmation LISP ML Scheme fonctionnel langages machine C++ C# Smalltalk Visual Basic Java FORTRAN Basic C Ada COBOL Algol APL Pascal orienté objet impératif GPSS Prolog déclaratif 1950 1960 1970 1980 1990 2000 Page 5
Ces paradigmes représentent des approches différentes pour construire des solutions aux problèmes. Plus que des paradigmes de programmation, on pourrait parler des paradigmes de développement de logiciel Paradigme impératif ou procédural: le processus de programmation est défini comme le développement d'une séquence de commandes qui manipulent des données pour produire le résultat souhaité. C'est-à-dire, on doit trouver l'algorithme donnant solution au problème et, ensuite, il doit être exprimé comme une séquence de commandes Avec le paradigme déclaratif, l'approche est différente: au lieu de décrire l'algorithme, le programmeur doit maintenant décrire le problème Page 6
Pour le paradigme déclaratif, il faut trouver et implémenter un algorithme général de solution de problèmes. Si cela est fait, il suffit ensuite de décrire un problème donné en respectant un format compatible avec cet algorithme général pour obtenir sa solution Le paradigme fonctionnel voit le processus de développement de programmes comme l'interconnexion de "boîtes noires" prédéfinies. Chacune de ces boîtes est une fonction mathématique Les primitives d'un langage fonctionnel sont des fonctions élémentaires que le programmeur doit utiliser pour construire les fonctions plus complexes nécessaires pour résoudre le problème traité Page 7
Exemple d'un programme fonctionnel pour calculer la moyenne d'une liste de nombres, utilisant les fonctions Add, Compter et Diviser: Entrée: x 1,x 2,...,x n Add Compter Diviser Sortie: (x 1 +x 2 +...+x n )/n (Diviser (Add Nombres) (Compter Nombres)) Page 8
Le paradigme orienté objets (OOP) voit les unités de données comme objets "actifs", contrairement aux unités passives vues par le paradigme impératif traditionnel Prenons, par exemple, une liste de noms. Le paradigme impératif voit cette liste comme une simple collection de données, et tout programme l'utilisant doit inclure un algorithme capable d'exécuter le traitement demandé. Pour le paradigme orienté objets, la liste est construite comme un objet composé par la liste elle-même plus une collection de procédures capables de la manipuler Les procédures à l'intérieur d'un objet, décrivant la façon de répondre aux messages adressés à l'objet, sont essentiellement des unités de programmation impérative Page 9
Concepts de programmation Les concepts étudiés ici sont ceux des langages impératifs et orientés objets Trois catégories de phrases: phrases déclaratives: définition des termes utilisés par la suite phrases impératives: description des pas de l'algorithme commentaires Les langages de haut niveau se réfèrent aux positions de mémoire par le biais des noms, contrairement aux adresses explicites utilisées par les langages machine. Ces noms sont les variables du programme Une variable doit être déclarée avant son utilisation. Cette déclaration doit donner également le type de la donnée, ce qui définit la façon de coder la donnée et les opérations qui peuvent l'utiliser Page 10
Exemples des déclarations de variables: Pascal: var Longueur, Largeur : real; Prix, Taxe, Total : integer; Symbole : char; C, C++, C#, Java: float Longueur, Largeur; int Prix, Taxe, Total; char Symbole FORTRAN: REAL Longueur, Largeur INTEGER Prix, Taxe, Total CHARACTER Symbole Page 11
En plus de son type de donnée, une variable est souvent associée à une structure de données: c'est sa forme conceptuelle, son arrangement virtuelle. La disposition physique de la variable à l'intérieur de la mémoire est souvent différente Exemple d'un tableau (array): Pascal: Employe: record Nom : packed array[1..8] of char; Age : integer; Evaluation: real end; C: struct {char Nom[8]; int Age; float Evaluation; } Employe; Employe Nom Age Evaluation Page 12
L'algorithme est décrit à l'aide des phrases impératives La phrase impérative de base est l'affectation, qui permet d'affecter une valeur à une variable (ou, plus précisément, de stocker une valeur dans la zone de mémoire réservée pour la variable) Exemple: C, C++, C#, Java: z = x + y; Ada, Pascal: z := x + y; Page 13
Une phrase de contrôle altère la séquence d'exécution d'un programme Exemples en C, C++, C# et Java: s1 B? s2 if B s1 else s2; B? s1 while B s1; Page 14
Un résultat surprenant de l'informatique théorique nous dit que le nombre de structures de contrôle nécessaires pour garantir à un langage de programmation qu'il est capable d'exprimer une solution à tout problème possédant une solution algorithmique est très petit Du choix des structures de contrôle d'un langage dépend en bonne partie la lisibilité des programmes. La programmation structurée est une méthodologie de programmation qui utilise une certaine famille de structures de contrôle afin de faciliter la lisibilité et la preuve des programmes Page 15
Unités procédurales Une procédure est un ensemble d'instructions qui réalisent une tâche et qui peut être considéré comme une unité par d'autres unités du programme Lorsque les services de la procédure sont nécessaires, le programme lui passe le contrôle: on appelle la procédure unité appelante passage du contrôle àla procédure procédure retour du contrôle Page 16
En général, une procédure possède une structure similaire à celle du programme principale, avec une partie déclarative suivie des phrases impératives qui décrivent l'algorithme Une variable déclarée dans une procédure est une variable locale, appelées ainsi par opposition aux variables globales du programme Les procédures sont écrites avec des termes génériques qui deviennent spécifiques au moment de l'appel: c'est les paramètres de la procédure Les termes utilisés pendant l'écriture de la procédure sont les paramètres formels. L'affectation spécifique donnée aux paramètres formels au moment de l'appel sont les paramètres réels Page 17
Exemple de procédure: paramètre formel void PredictionPopulation (float TauxCroissance) { int Annee; variable locale } Population[0] = 100.0; for (Annee = 0; Annee =< 10; Annee++) Population[Annee+1] = Population[Annee]*TauxCroissance); paramètre réel PredictionPopulation (0.03); Page 18
Le passage d'une donnée entre les paramètres formels et réels peut se faire de plusieurs façons, selon le langage Dans le passage par valeur, la procédure reçoit seulement une copie du paramètre réel: toute modification faite par la procédure sur le paramètre est ignorée par l'unité appelante Le passage par valeur est très peu efficace pour des données à très grande taille Dans le passage par référence, la procédure reçoit un accès direct au paramètre réel, en recevant son adresse. La procédure peut dans ce cas modifier la donnée de l'unité appelante Page 19
Dans certains cas, le but de la procédure est de produire une valeur, plus que de réaliser une action: c'est une fonction Exemple de fonction: type de la valeur produite float VolumeCylindre (float Rayon, float Hauteur) { float Volume; } Volume = 3.14 * Rayon * Rayon * Hauteur; return Volume; valeur produite Cout = CoutPerUniteVol * VolumeCylindre(3.45, 12.7); Page 20