Dans quel langage est programmé un langage de programmation ?

a marqué ce sujet comme résolu.

Je pense à ça en lisant le billet sur Go…

Si demain je veux inventer un nouveau langage de programmation. Je commence par quoi ? Le programmer dans un langage de plus bas niveau ? Genre le gars qui a inventé l’assembleur manipulé directement les 0 et les 1, celui qui à fait C l’a fait en assembleur, Guido à fait Python en C, etc ? Est-ce qu’inventer un langage ne revient pas en fait à programmer un compilateur ou un interpréteur ? Ça marche comment ?

Salut,

Le seul langage qu’un CPU comprend est le langage machine (qui est implémenté de façon physique au niveau du matériel lui-même, chaque instruction en langage machine correspond directement à un signal électrique dans les circuits du CPU). Comme le langage machine est une suite de bits que la machine peut comprendre directement, il n’y a pas besoin de "le programmer", on peut directement donner les nombres à la machine et elle exécute les instructions correspondantes.

Évidemment, fournir directement des nombres à la machine est très fastidieux et source d’erreur. Donc assez vite, on a exprimé les programmes en langage d’assemblage, qui est quasiment une représentation textuelle du langage machine. Il est trivial de compiler ce langage d’assemblage en langage machine puisqu’il y a quasiment une correspondance directe avec le langage machine, donc on peut se permettre d’écrire les "compilateurs" (appelés assembleurs) en langage machine. Une fois qu’on a un assembleur qui fonctionne, on peut le réécrire en langage d’assemblage et utiliser le premier assembleur implémenté en langage machine pour assembler le second assembleur implémenté en langage d’assemblage. On s’est alors déjà affranchi du besoin d’écrire des programmes en langage machine directement, et on peut s’appuyer sur le langage d’assemblage pour écrire des programmes un peu plus complexes.

Mais évidemment, le langage d’assemblage lui-même est aussi austère et fastidieux à manipuler directement comme il n’offre quasiment aucune abstraction par-dessus le fonctionnement de la machine et le langage machine. Les programmes écrits ne sont aussi valables que pour une architecture donnée, donc c’est pas très pratique.

Rapidement, on a développé des langages de plus haut-niveau (i.e. de plus haut niveau d’abstraction par rapport au matériel), comme FORTRAN en 1957, en écrivant des compilateurs en langage d’assemblage qui sont capables de traduire un programme écrit en FORTRAN en langage machine. Au départ, les compilateurs ne génèrent pas du code machine très efficaces, et les langages ne sont pas à un niveau d’abstraction très éloigné de la machine pour qu’écrire un compilateur en langage d’assemblage ne soit pas une tâche insurmontable. Le langage le plus célèbre de cette époque est sûrement le C (1972), qui a encore un succès énorme en tant que langage système qui permet de manipuler des considérations bas niveau (importantes pour les performances) tout en offrant un niveau d’abstraction relativement acceptable pour développer des applications conséquentes. De la même façon qu’avec le langage d’assemblage où on a juste besoin d’écrire un premier assembleur en langage machine pour ensuite écrire l’assembleur lui-même en langage d’assemblage, on peut écrire un premier compilateur C en langage d’assemblage, puis utiliser celui-ci pour compiler un compilateur écrit en C lui-même.

Sont ensuite venus des langages à plus haut-niveau d’abstraction, soit qu’on ne se fatigue même pas à compiler complètement vers du langage machine mais qu’on compile en bytecode pour une machine virtuelle (comme Java ou Python), soit que l’on compile toujours vers du langage machine mais qui s’appuient sur les progrès en théorie des langages et l’expérience accumulé avec C dans l’objectif de nous rendre la vie plus facile qu’en C (comme Zig ou Rust). Note que la première implémentation d’un langage peut être faite en n’importe quel langage existant, et qu’elle n’a même pas besoin d’être bonne puisqu’on peut facilement passer à d’autres langages (incluant le nouveau langage qu’on vient de créer) si cela est intéressant. Par exemple, Rust a été développé en OCaml originellement (en s’appuyant sur la LLVM développé en C++ pour la génération de code machine), et est maintenant développé en Rust lui-même (toujours en s’appuyant sur la LLVM).


Ça c’est pour la question de comment on implémente un langage, mais la partie difficile derrière l’invention d’un langage est surtout le design du langage. Inventer un langage est beaucoup plus que simplement écrire un compilateur pour ce langage, il faut d’abord le spécifier pour savoir où l’on va. Il faut se donner une grammaire et une syntaxe, définir un modèle mémoire, un modèle de calcul, quelles seront les features du langage, et bien sûr à quel besoin de l’industrie on essaie de répondre dans le cas où on n’est pas sur un projet jouet.

+11 -0

Salut,

Alors il faut bien comprendre qu’on ne programme pas un langage de programmation, on le spécifie.
Ensuite on implémente des outils qui respectent cette spécification.
Alors il faut commencer par écrire un document qui décrit le langage en détail, les mot clé et les comportements. Ensuite tu vas pouvoir implémenter un compilateur ou un interpréteur, ainsi que la lib standard, avec la technologie de ton choix, mais il peut très bien y avoir ensuite d’autre implémentations qui naitront fait avec d’autres technologies. Ainsi en C on a les compilateurs gcc, clang et msvc, et les libs glibc ou musl.

Je ne connais pas l’histoire de tous les langages. Mais tu peux être intéressé par celle de rust qui a fait le choix de bootstrap son compilateur officiel, c’est à dire que le compilateur est écrit en Rust et est compilé à partir d’une version précédente de lui-même. Le premier compilateur étant écrit en Ocaml.

PS: Grillé par adr1 qui a une réponse plus complète et détaillée. Je laisse la mienne pour le lien vers rustdoc.

+3 -0

Salut,

Le seul langage qu’un CPU comprend est le langage machine (qui est implémenté de façon physique au niveau du matériel lui-même, chaque instruction en langage machine correspond directement à un signal électrique dans les circuits du CPU). Comme le langage machine est une suite de bits que la machine peut comprendre directement, il n’y a pas besoin de "le programmer", on peut directement donner les nombres à la machine et elle exécute les instructions correspondantes.

Évidemment, fournir directement des nombres à la machine est très fastidieux et source d’erreur. Donc assez vite, on a exprimé les programmes en langage d’assemblage, qui est quasiment une représentation textuelle du langage machine. Il est trivial de compiler ce langage d’assemblage en langage machine puisqu’il y a quasiment une correspondance directe avec le langage machine, donc on peut se permettre d’écrire les "compilateurs" (appelés assembleurs) en langage machine. Une fois qu’on a un assembleur qui fonctionne, on peut le réécrire en langage d’assemblage et utiliser le premier assembleur implémenté en langage machine pour assembler le second assembleur implémenté en langage d’assemblage. On s’est alors déjà affranchi du besoin d’écrire des programmes en langage machine directement, et on peut s’appuyer sur le langage d’assemblage pour écrire des programmes un peu plus complexes.

Mais évidemment, le langage d’assemblage lui-même est aussi austère et fastidieux à manipuler directement comme il n’offre quasiment aucune abstraction par-dessus le fonctionnement de la machine et le langage machine. Les programmes écrits ne sont aussi valables que pour une architecture donnée, donc c’est pas très pratique.

Rapidement, on a développé des langages de plus haut-niveau (i.e. de plus haut niveau d’abstraction par rapport au matériel), comme FORTRAN en 1957, en écrivant des compilateurs en langage d’assemblage qui sont capables de traduire un programme écrit en FORTRAN en langage machine. Au départ, les compilateurs ne génèrent pas du code machine très efficaces, et les langages ne sont pas à un niveau d’abstraction très éloigné de la machine pour qu’écrire un compilateur en langage d’assemblage ne soit pas une tâche insurmontable. Le langage le plus célèbre de cette époque est sûrement le C (1972), qui a encore un succès énorme en tant que langage système qui permet de manipuler des considérations bas niveau (importantes pour les performances) tout en offrant un niveau d’abstraction relativement acceptable pour développer des applications conséquentes. De la même façon qu’avec le langage d’assemblage où on a juste besoin d’écrire un premier assembleur en langage machine pour ensuite écrire l’assembleur lui-même en langage d’assemblage, on peut écrire un premier compilateur C en langage d’assemblage, puis utiliser celui-ci pour compiler un compilateur écrit en C lui-même.

Sont ensuite venus des langages à plus haut-niveau d’abstraction, soit qu’on ne se fatigue même pas à compiler complètement vers du langage machine mais qu’on compile en bytecode pour une machine virtuelle (comme Java ou Python), soit que l’on compile toujours vers du langage machine mais qui s’appuient sur les progrès en théorie des langages et l’expérience accumulé avec C dans l’objectif de nous rendre la vie plus facile qu’en C (comme Zig ou Rust). Note que la première implémentation d’un langage peut être faite en n’importe quel langage existant, et qu’elle n’a même pas besoin d’être bonne puisqu’on peut facilement passer à d’autres langages (incluant le nouveau langage qu’on vient de créer) si cela est intéressant. Par exemple, Rust a été développé en OCaml originellement (en s’appuyant sur la LLVM développé en C++ pour la génération de code machine), et est maintenant développé en Rust lui-même (toujours en s’appuyant sur la LLVM).


Ça c’est pour la question de comment on implémente un langage, mais la partie difficile derrière l’invention d’un langage est surtout le design du langage. Inventer un langage est beaucoup plus que simplement écrire un compilateur pour ce langage, il faut d’abord le spécifier pour savoir où l’on va. Il faut se donner une grammaire et une syntaxe, définir un modèle mémoire, un modèle de calcul, quelles seront les features du langage, et bien sûr à quel besoin de l’industrie on essaie de répondre dans le cas où on n’est pas sur un projet jouet.

adri1

Cette réponse pourrait aisément donner lieu à un petit billet/article sur le sujet car elle est très complète et suffisamment générique pour être utile si d’aventure (et il y en aura) d’autres questions étaient posées. Si cela tente certains d’entre vous… ;)

+7 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte