Selon Wikipedia: A langage compilé est un langage de programmation dont les implémentations sont généralement des compilateurs (traducteurs qui génèrent du code machine à partir du code source). Et un langage interprété est un type de langage de programmation pour lequel la plupart de ses implémentations exécutent des instructions directement et librement, sans avoir préalablement compilé un programme en instructions en langage machine.
Par conséquent, ce qui suit est clair.
C, C++ and few other similar languages
- Langue compilée Shell script, Perl, Ruby and some more
- Langue interprétée Cependant, il existe également un troisième type de langage. Des langages comme C # et Java qui utilisent à la fois un compilateur et un JIT lors de l'exécution. Ma question est donc, existe-t-il un nom distinct pour ces langages ou ils peuvent être classés dans l'un des types ci-dessus? Une réponse explicative serait plus utile?
MODIFIER:
D'après Wikipedia et ce SO post: interprété vs compilé il est évident qu'il existe 2 types d'implémentation de langage bien définis. Mais ma question porte sur le fait que c'est suffisant pour avoir 2 catégories, toutes les langues peuvent-elles entrer dans ces 2 ou y en a-t-il une 3ème?
La réponse à votre question:
Chaque langue peut-elle être classée comme compilée ou interprétée?
Est "Non", mais pas pour la raison pour laquelle vous pensez que c'est le cas. La raison n'est pas qu'il existe une troisième catégorie manquante, la raison est que la catégorisation elle-même est absurde .
Il n'existe pas de "langage compilé" ou de "langage interprété". Ces termes ne sont même pas faux, ils sont absurdes.
Les langages de programmation sont des ensembles de règles mathématiques abstraites, de définitions et de restrictions. Les langages de programmation ne sont ni compilés ni interprétés. Les langages de programmation juste sont . [Le mérite revient à Shriram Krishnamurthi qui a dit cela dans une interview sur Channel il y a 9 ans (vers 51: 37-52: 20). ]
En fait, un langage de programmation peut parfaitement exister sans avoir aucun interprète ou compilateur! Par exemple, Konrad Zuse 's Plankalkül qu'il a conçu dans les années 1930 n'a jamais été mis en œuvre de son vivant. Vous pouvez toujours y écrire des programmes, vous pouvez analyser ces programmes, les raisonner, prouver leurs propriétés… vous ne pouvez tout simplement pas les exécuter. (Eh bien, en fait, même cela est faux: vous pouvez bien sûr les exécuter dans votre tête ou avec un stylo et du papier.)
La compilation et l'interprétation sont des traits du compilateur ou de l'interpréteur (duh!), Pas du langage de programmation. La compilation et l'interprétation vivent à un niveau d'abstraction différent des langages de programmation: un langage de programmation est un concept abstrait, une spécification, un morceau de papier. Un compilateur ou un interpréteur est un logiciel (ou matériel) concret qui implémente cette spécification. Si l'anglais était une langue dactylographiée, les termes "langue compilée" et "langue interprétée" seraient des erreurs de type. [Encore une fois, crédit à Shriram Krishnamurthi.]
Chaque langage de programmation peut être implémenté par un compilateur. Chaque langage de programmation peut être implémenté par un interprète. De nombreux langages de programmation grand public modernes ont à la fois interprété et compilé des implémentations. De nombreuses implémentations de langage de programmation hautes performances modernes ont à la fois des compilateurs et des interprètes.
Il existe des interprètes pour C et pour C++. D'un autre côté, chaque implémentation principale courante actuelle d'ECMAScript, PHP, Python, Ruby et Lua a un compilateur. La version originale du moteur ECMAScript V8 de Google était un pur compilateur de code machine natif. (Ils sont passés par plusieurs designs différents, et la version actuelle a un interprète, mais pendant de nombreuses années, il n'en a pas eu un.) XRuby et Ruby.NET était purement compilé Ruby implémentations. IronRuby a commencé comme une compilation purement Ruby implémentation, puis a ajouté un interpréteur plus tard afin d'améliorer les performances. - Opal est une implémentation Ruby purement compilée).
Certaines personnes pourraient dire que les termes "langage interprété" ou "langage compilé" ont un sens pour s'appliquer aux langages de programmation qui ne peuvent être implémentés que par un interprète ou par un compilateur. Mais, un tel langage de programmation n'existe pas. Chaque langage de programmation peut être implémenté par un interprète et par un compilateur.
Par exemple, vous pouvez dériver automatiquement et mécaniquement un compilateur d'un interprète à l'aide de la seconde projection Futamura. Il a été décrit pour la première fois par Prof. Yoshihiko Futamura dans son article de 1971 Évaluation partielle du processus de calcul - Une approche d'un compilateur-compilateur (japonais) , un version anglaise qui a été republié 28 ans plus tard. Il utilise évaluation partielle , en évaluant partiellement l'évaluateur partiel lui-même par rapport à l'interpréteur, ce qui donne un compilateur.
Mais même sans de telles transformations hautement académiques complexes, vous pouvez créer quelque chose qui est fonctionnellement impossible à distinguer de la compilation d'une manière beaucoup plus simple: il suffit de regrouper l'interpréteur avec le programme à interpréter en un seul exécutable.
Une autre possibilité est l'idée d'un "méta-JIT". (Ceci est lié dans l'esprit aux projections Futamura.) C'est par exemple utilisé dans le framework RPython pour implémenter des langages de programmation. Dans RPython, vous écrivez un interpréteur pour votre langue, puis le framework RPython compilera JIT votre interprète pendant qu'il interprète le programme, produisant ainsi une version compilée spécialisée de l'interpréteur qui ne peut interpréter que ce seul programme - qui est à nouveau indiscernable de la compilation de ce programme. Donc, dans un certain sens, RPython génère dynamiquement des compilateurs JIT à partir d'interprètes.
Dans l'autre sens, vous pouvez envelopper un compilateur dans un wrapper qui compile d'abord le programme, puis l'exécute directement, ce qui rend ce compilateur encapsulé impossible à distinguer d'un interpréteur. C'est en fait ainsi que le Scala REPL, le C♯ REPL (à la fois en Mono et .NET), le Clojure REPL, le GHC REPL interactif) et de nombreux autres REPL sont implémentés. Ils prennent simplement une ligne/une instruction/une expression, le compilent, l'exécutent immédiatement et affichent le résultat. Ce mode d'interaction avec le compilateur est donc indiscernable d'un interprète, que certaines personnes utilisent réellement l'existence d'un REPL pour le langage de programmation comme caractéristique définissant ce que signifie être un "interprété") langage de programmation".
Notez cependant que vous ne pouvez pas exécuter un programme sans interprète. Un compilateur traduit simplement un programme d'une langue à une autre. Mais c'est tout. Vous avez maintenant le même programme, juste dans une langue différente. La seule façon d'obtenir réellement un résultat du programme est d'interpréter il. Parfois, le langage est un langage machine binaire extrêmement simple, et l'interpréteur est en fait codé en dur en silicone (et nous l'appelons un "CPU"), mais c'est toujours une interprétation.
Certaines personnes disent que vous pouvez appeler un langage de programmation "interprété" si la majorité de ses implémentations sont des interprètes. Eh bien, regardons un langage de programmation très populaire: ECMAScript. Il existe un certain nombre d'implémentations grand public très performantes et prêtes pour la production d'ECMAScript, et chacune d'entre elles comprend au moins un compilateur , certains compilateurs même multiples. Ainsi, selon cette définition, ECMAScript est clairement un langage compilé.
Vous pourriez également être intéressé par ma réponse, qui explique les différences et les différents moyens de combiner les interprètes, les compilateurs JIT et les compilateurs AOT et cette réponse traitant des différences entre un compilateur AOT et un compilateur JIT .
Il est possible de catégoriser les implémentations du langage dans une certaine mesure. En général, nous avons la distinction entre
Dans le groupe de compilateurs, nous avons la distinction temporelle lorsque le compilateur est exécuté:
Et puis nous avons des implémentations qui combinent interprètes et compilateurs, ou combinent plusieurs compilateurs, ou (beaucoup plus rare) plusieurs interprètes. Certaines combinaisons typiques sont
Mais il y en a encore d'autres. Certaines implémentations utilisent deux compilateurs au lieu d'un compilateur et d'un interprète pour obtenir les mêmes avantages qu'un moteur en mode mixte (par exemple, les premières années, la V8 a fonctionné de cette façon).
RPython combine un interpréteur de bytecode et un JIT, mais le JIT ne compile pas le programme utilisateur, il compile l'interpréteur de bytecode pendant qu'il interprète le programme utilisateur! La raison en est que RPython est un framework pour implémenter les langages, et de cette manière, un implémenteur de langage n'a qu'à écrire l'interpréteur de bytecode et obtient un JIT gratuitement. (L'utilisateur le plus connu de RPython est bien sûr PyPy .)
Le Truffle framework interprète un AST indépendant du langage, mais en même temps il se spécialise lui-même pour l'AST spécifique, qui est sorte de compilation comme mais pas non plus. Le résultat final est que Truffle peut exécuter le code extrêmement rapidement, sans en savoir trop sur les spécificités du langage. (Truffle est également un cadre générique pour les implémentations de langage.) Parce que le AST est indépendant de la langue, vous pouvez mélanger et faire correspondre plusieurs langues dans le même programme, et Truffle est capable d'effectuer des optimisations entre les langues , comme l'inclusion d'une méthode Ruby dans une fonction ECMAScript, etc.
Les macros et eval
sont parfois citées comme des fonctionnalités qui ne peut pas être compilé. Mais c'est faux. Il existe deux façons simples de compiler des macros et eval
. (Notez que pour les besoins de la compilation, les macros et eval
sont quelque peu duales les unes aux autres et peuvent être gérées en utilisant des moyens similaires.)
eval
, vous intégrez un interpréteur dans le programme compilé ou dans les bibliothèques de support d'exécution.eval
, vous intégrez un compilateur dans le programme compilé ou dans les bibliothèques de support d'exécution.Si nous sommes pédant, il n'y a pas de langage compilé ou interprété, car n'importe quel langage pourrait en principe être implémenté par un compilateur ou un interprète. Cependant, la plupart des langues suivent une stratégie de mise en œuvre relativement cohérente. C++ est presque toujours compilé en code natif. Python est presque toujours exécuté via un interpréteur de bytecode. Java est presque toujours exécuté via un comiler JIT. Donc, si nous n'insistons pas sur un pédantisme obtus) , il est logique de parler de langages compilés ou interprétés.
Cependant, la stratégie d'implémentation du langage ne correspond pas parfaitement à la dichotomie compilée/interprétée. Essentiellement, aucune langue n'est strictement interprétée, exécutée directement à partir de la source. Ce serait très lent. Au lieu de cela, pratiquement toutes les implémentations de langage "interprétées" compilent la source en quelque chose (souvent du bytecode) qui peut être exécuté de manière plus efficace. En plus de cela, certaines implémentations JIT compilent ce bytecode en code natif au moment de l'exécution. Même les langues que nous considérons comme étant compilées contiennent souvent une certaine quantité d'interprétation. Par exemple, printf en C est effectivement un interpréteur de la chaîne de format.
Donc, je dirais qu'il n'est pas logique d'essayer de catégoriser les langues en compilées ou interprétées. Presque toutes les langues sont un certain degré d'hybride entre les deux approches. (Et oui, si nous sommes pédant, ce sont les implémentations de langage et non les langages qui sont compilés/interprétés).
Non, la classification compilée vs interprétée n'est pas pertinente pour les langues.
Les compilateurs et les interprètes ne sont que des moyens de livrer une langue. Et la technologie derrière ces moyens évolue. Exemples pratiques:
Enfin un article intéressant de la façon dont le même langage peut évoluer d'interprété à compilé.
Certaines versions de Basic symbolisent les instructions dans un fichier de code source, quelque chose entre interprétatif et compilé.
APL (un langage de programmation), a un opérateur d'exécution, qui prend une chaîne variable comme paramètre, puis l'interprète et l'exécute. Il existe un opérateur de création de fonction, qui prend une matrice de chaînes variables et crée une fonction à partir de celle-ci. Cela nécessiterait un certain type de compilation au moment de l'exécution afin de considérer le langage comme compilé.
Sous la définition OP de langage compilé et langage interprété .
Les autres catégories seraient:
Une langue peut changer de catégorie à mesure que de nouveaux outils sont développés ou que les tendances d'utilisation changent.