web-dev-qa-db-fra.com

Pourquoi le premier compilateur a-t-il été écrit avant le premier interprète?

Le premier compilateur a été écrit par Grace Hopper en 1952 tandis que l'interprète LISP a été écrit en 1958 par l'étudiant de John McCarthy, Steve Russell. L'écriture d'un compilateur semble être un problème beaucoup plus difficile qu'un interprète. Si tel est le cas, pourquoi le premier compilateur a-t-il été écrit six ans avant le premier interprète?

72
anguyen

L'écriture d'un compilateur semble être un problème beaucoup plus difficile qu'un interprète.

C'est peut-être vrai aujourd'hui, mais je dirais que ce n'était pas le cas il y a une soixantaine d'années. Quelques raisons pour lesquelles:

  • Avec un interprète, vous devez le garder et le programme en mémoire. À une époque où 1 Ko de mémoire était un luxe énorme, il était essentiel de conserver une empreinte mémoire faible. Et l'interprétation nécessite un peu plus de mémoire que l'exécution d'un programme compilé.
  • Les processeurs modernes sont extrêmement complexes avec d'énormes catalogues d'instructions. Donc, écrire un bon compilateur est vraiment un défi. Les anciens processeurs étaient beaucoup plus simples, donc même la compilation était plus simple.
  • Les langues modernes sont beaucoup plus complexes que les anciennes langues, donc même les compilateurs sont beaucoup plus complexes. Les anciennes langues auraient donc des compilateurs plus simples.
97
Euphoric

Le point fondamental est que l'environnement matériel informatique des années 50 a fait en sorte que seul un compilateur était réalisable étant donné le traitement orienté par lots des ordinateurs à l'époque.

À l'époque, les meilleures interfaces utilisateur étaient principalement limitées aux cartes perforées et aux imprimantes téléscriptives . En 1961, le système SAGE est devenu le premier affichage à tube cathodique (CRT) sur un ordinateur. La nature interactive d'un interprète n'était donc préférable ou naturelle que bien plus tard.

De nombreux ordinateurs dans les années 1950 utilisaient des commutateurs du panneau avant pour charger les instructions, et la sortie était simplement des rangées de lampes/LED, et les amateurs ont même utilisé des commutateurs du panneau avant et des LED dans les années 1970. Vous connaissez peut-être l'infâme Altair 88 .

D'autres limitations matérielles ont également rendu les interprètes irréalisables. Il y avait une disponibilité extrêmement limitée de mémoire primaire (par exemple RAM) dans les ordinateurs dans les années 1950. Avant le circuit intégré à semi-conducteur (qui n'est arrivé qu'en 1958), la mémoire était limitée à mémoire à noyau magnétique ou mémoire à ligne à retard qui était mesurée en bits ou mots, pas de préfixe. Combiné à la lenteur de la mémoire de stockage secondaire (par exemple, disque ou bande), il serait considéré comme un gaspillage, voire impossible, d'avoir une grande partie de la mémoire utilisée pour l'interpréteur, avant même que le programme en cours d'interprétation ne soit chargé.

Les limitations de mémoire étaient encore un facteur majeur lorsque l'équipe dirigée par John Backus chez IBM a créé le compilateur FORTRAN en 1954-57. Ce compilateur innovant n'a réussi que parce qu'il s'agissait d'un optimisation du compilateur .

La plupart des ordinateurs des années 50 n'avaient à peine aucun système d'exploitation , sans parler des fonctionnalités modernes telles que la liaison dynamique et la gestion de la mémoire virtuelle, donc l'idée d'un interprète était trop radical et peu pratique à l'époque.

Addendum

Les langues des années 50 étaient primitives. Ils ne comprenaient qu'une petite poignée d'opérations, souvent influencées soit par les instructions du matériel sous-jacent, soit par la définition du problème de leur utilisation ciblée.

À cette époque, les ordinateurs étaient rarement des ordinateurs à usage général dans le sens où nous pensons aux ordinateurs aujourd'hui. Le fait qu'ils soient reprogrammables sans avoir à être reconstruits était considéré comme un concept révolutionnaire - auparavant, les gens utilisaient des machines électromécaniques (généralement des calculatrices) pour calculer ou calculer des réponses (la majorité des applications dans les années 1950 étaient de nature numérique).

D'un point de vue informatique, les compilateurs et les interprètes sont tous les deux - traducteurs, et à peu près de complexité à implémenter.

42
mctylr

Les premiers langages de programmation étaient assez simples (pas de récursivité par exemple) et proches de l'architecture machine qui était elle-même simple. La traduction était alors un processus simple .

Un compilateur était plus simple en tant que programme qu'un interprète qui devait conserver à la fois les données pour l'exécution du programme et les tables pour interpréter le code source. Et l'interpréteur prendrait plus de place , pour lui-même, pour le code source du programme et pour les tableaux symboliques.

La mémoire peut être si rare (à la fois pour des raisons de coût et d'architecture) que les compilateurs peuvent être des programmes autonomes qui écrasent le système d'exploitation (j'en ai utilisé un). L'OS a dû être rechargé après la compilation afin d'exécuter le programme compilé. ... ce qui montre clairement que exécuter un interpréteur pour un travail réel n'était tout simplement pas une option .

Pour être vrai, la simplicité requise des compilateurs était telle que les compilateurs n'étaient pas très bons (l'optimisation du code était encore balbutiante, quand on la considérait du tout). Le code machine manuscrit avait, au moins jusqu'à la fin des années 60 à certains endroits, la réputation d'être beaucoup plus efficace que le code généré par le compilateur. Il y avait même un concept de rapport d'expansion du code , qui comparait la taille du code compilé au travail d'un très bon programmeur. Il était généralement supérieur à 1 pour la plupart (tous?) Des compilateurs, ce qui signifiait des programmes plus lents et, plus important encore, des programmes plus gros nécessitant plus de mémoire. C'était encore un problème dans les années soixante.

L'intérêt du compilateur était de faciliter la programmation, en particulier pour les utilisateurs qui n'étaient pas des spécialistes de l'informatique, comme les scientifiques dans divers domaines. Cet intérêt n'était pas la performance du code. Mais encore, le temps du programmeur était alors considéré comme une ressource bon marché. Le coût était en temps informatique, jusqu'en 1975-1980, lorsque le coût est passé du matériel au logiciel. Ce qui signifie que même le compilateur n'a pas été pris au sérieux par certains professionnels .

Le coût très élevé du temps informatique était une autre raison de disqualifier les interprètes , au point que l'idée même aurait été risible pour la plupart des gens.

Le cas de LISP est très spécial, car c'était un langage extrêmement simple qui le rendait possible (et l'ordinateur était devenu un peu plus gros en 58). Plus important encore, l'interpréteur LISP était une preuve de concept concernant l'auto-définissabilité de LISP ( méta-circularité ), indépendamment de tout problème d'utilisation.

Le succès de LISP est dû en grande partie au fait que cette auto-définition en a fait un excellent banc d'essai pour étudier les structures de programmation et concevoir de nouveaux langages (et aussi pour sa commodité pour le calcul symbolique).

12
babou

Je suis en désaccord avec la prémisse de la question.

Adm. Le premier compilateur de Hopper (le A-0) ressemblait plus à un éditeur de liens ou à un langage macro. Elle stockait les sous-programmes sur une bande (chacun assignait un numéro) et ses programmes seraient écrits comme une liste de sous-programmes et d'arguments. Le compilateur copiera les sous-programmes demandés à partir de la bande et les réordonnera dans un programme complet.

Elle a utilisé le mot "compiler" dans le même sens que l'on compile une anthologie de poèmes: rassembler divers éléments ensemble en un seul volume.

Ce premier compilateur n'avait pas de lexer ou d'analyseur, pour autant que je sache, ce qui en fait un ancêtre éloigné d'un compilateur moderne. Elle a ensuite créé un autre compilateur (le B-0, alias FLOW-MATIC) dans le but d'une syntaxe plus proche de l'anglais, mais il n'a été achevé qu'en 1958 ou 1959 - à peu près au même moment que l'interpréteur LISP.

Par conséquent, je pense que la question elle-même est un peu erronée. Il semble que les compilateurs et les interprètes ont co-évolué presque exactement en même temps, sans doute en raison du partage d'idées qui aurait amené de nombreux scientifiques à penser dans le même sens à cette époque.

Une meilleure réponse avec des citations ici: https://stackoverflow.com/a/7719098/12276 .

4
Mark E. Haase

L'autre partie de l'équation est que les compilateurs étaient une abstraction d'étape au-dessus d'un assembleur. Nous avions d'abord un code machine codé en dur. "Nous" étions l'assembleur. Chaque saut et décalage, etc. a été calculé à la main en hexadécimal (ou octal) puis perforé en ruban de papier ou en cartes. Donc, quand les assembleurs sont venus sur la scène, c'était un énorme gain de temps. La prochaine étape était les macro-assembleurs. Cela a permis d'écrire une macro qui se développerait en un ensemble d'instructions machine. Fortran et Cobol ont donc été un énorme pas en avant. Le manque de ressources (stockage, mémoire et cycles de processeur) a obligé les interprètes à usage général à attendre que la technologie se développe. La plupart des premiers interprètes étaient des moteurs de code octet (comme Java ou CLR d'aujourd'hui, mais avec beaucoup moins de capacités). UCSD Pascal était un langage très populaire (et rapide). MS Basic était un octet- moteur de code sous le capot. Donc, la "compilation" était vraiment de générer un flux de code octet qui a été réellement exécuté par le runtime.

En termes de frais généraux d'instruction, cela dépendait totalement du processeur exécuté. L'industrie a traversé une grande tourmente RISC vs CISC pendant un certain temps. J'ai personnellement écrit assembleur pour IBM, Data General, Motorola, Intel (quand ils sont arrivés), TI et plusieurs autres. Il y avait une différence assez importante dans les jeux d'instructions, les registres, etc. qui influenceraient ce qui était nécessaire pour "interpréter" un code p.

Comme référence temporelle, j'ai commencé à programmer dans la compagnie de téléphone vers 1972.

3
Bill Brothers

Si vous ne conservez pas tout en mémoire, le code compilé est beaucoup plus rapide. N'oubliez pas qu'à cette époque, les fonctions étaient jointes au code compilé. Si vous ne compilez pas, vous ne savez pas de quelles fonctions vous aurez besoin. Donc, vous appelez des fonctions à partir de ... Oh, pas encore à partir du disque, nous sommes au début des 50 liens, mais à partir de cartes! En runtime!

Bien sûr, il est possible de trouver une solution de contournement, mais elle n'a pas encore été trouvée, car les langues étaient très simples et pas si éloignées du code machine. Et la compilation était facile et suffisante.

2
Gangnus

Avant l'écriture du premier compilateur, les gens écrivaient du code assembleur, ce qui était un énorme progrès par rapport au code binaire ordinaire. À l'époque, il y avait un argument fort selon lequel le code compilé par un compilateur serait moins efficace que le code assembleur - à cette époque, la relation entre (coût de l'ordinateur) et (coût du programmeur) était très, très différente qu'aujourd'hui. Il y avait donc une forte résistance contre les compilateurs de ce point de vue.

Mais les compilateurs sont beaucoup plus efficaces que les interprètes. Si vous aviez suggéré d'écrire un interprète à ce moment-là, les gens auraient pensé que vous étiez fou. Pouvez-vous imaginer acheter un ordinateur à un million de dollars, puis gaspiller 90% de son pouvoir pour interpréter le code?

1
gnasher729

Avant qu'un programme en boucle puisse être interprété, il doit être stocké sur un support qui peut être lu de manière répétée. Dans la plupart des cas, le seul support approprié serait la RAM. Étant donné que le code sera généralement entré sur des cartes perforées qui - pour les langues lisibles par l'homme - sont susceptibles d'être largement vides, une sorte de traitement doit être effectué sur le code avant qu'il ne soit stocké dans la RAM. Dans de nombreux cas, le traitement du texte de la carte perforée dans un formulaire qui est adapté à une exécution directe par le processeur n'est pas vraiment plus difficile que de le traiter dans un formulaire qui pourrait être efficacement géré via un interpréteur.

Notez que le but des premiers compilateurs n'était pas de produire un fichier de langage d'assemblage ou de code objet sur le disque, mais plutôt de finir le code dans RAM qui était prêt à exécuter. C'est en fait étonnamment facile quand il n'y a pas de système d'exploitation à gêner. Un compilateur peut générer du code à partir d'une extrémité de la mémoire et allouer des variables et des cibles de branche à partir de l'autre. Si une instruction est marquée avec l'étiquette "1234", le compilateur stockera dans la variable appelée "1234" une instruction pour passer à l'adresse de génération de code actuelle, en créant cette variable si elle n'existe pas. Une instruction "goto 1234" créera une variable "1234" si elle n'existe pas, puis saute à cette variable [qui, espérons-le, aura un saut à l'emplacement approprié qui y est stocké avant l'exécution de cette instruction]. Notez que le compilateur n'a rien à faire de spécial pour permettre au code de goto une étiquette qui n'a pas ' t encore défini, car il sait quand le goto compile où il va sauter - à un va riable. Ce n'est peut-être pas le moyen le plus efficace de générer du code, mais il convient aux tailles de programmes que les ordinateurs étaient censés gérer.

1
supercat

Parce que les interprètes ont besoin de compilateurs pour fonctionner.

La déclaration ci-dessus n'est pas vraiment vraie. À strictement parler, vous pouvez créer un interpréteur sans jamais utiliser ou interagir avec un compilateur. Mais les résultats de cette opération ne ressembleraient pas beaucoup à ce que je pense que vous entendez par ces termes.

Au sens strict, les compilateurs et les interprètes font des choses entièrement différentes. Un compilateur lit le texte d'une source et le transforme en un autre format: langage d'assemblage, code machine, autre langage de haut niveau, structure de données ou autre. Un interprète, quant à lui, prend une structure de données d'une certaine sorte et exécute des instructions en fonction de celle-ci.

Ce que nous avons tendance à considérer comme un "compilateur" de nos jours est en fait un compilateur qui a été associé à un générateur de code : un programme qui prend les données d'une source et génère du code dans un certain format en fonction de ce qu'il voit. C'est une utilisation assez intuitive pour les compilateurs, et c'était l'une des premières choses pour lesquelles les compilateurs ont été créés. Mais si vous regardez les choses autrement, cela semble très similaire à ce que fait un interprète. Il génère toujours du code au lieu d'effectuer des opérations plus générales, mais le principe est le même.

Si nous le regardons de l'autre côté, un interprète doit obtenir ses données quelque part. Ce ne sont que des données, vous pouvez donc les créer de la même manière que vous le feriez pour tout autre type de données. Puisque nous parlons d'interprétation, il semble naturel que vous puissiez créer vos données en fonction des instructions contenues dans un fichier texte. Mais pour ce faire, vous auriez besoin de quelque chose à lire dans le texte et à créer votre structure de données, et c'est un compilateur . Il est connecté à l'interpréteur au lieu d'un générateur de code, mais c'est tout de même un compilateur.

C'est pourquoi les compilateurs ont été écrits en premier. L'idée d'interpréter les structures de données n'était pas nouvelle même lorsque les compilateurs ont été conçus, mais les compilateurs étaient le "lien manquant" qui permettait aux programmeurs de construire ces structures à partir du texte.

0
The Spooniest