web-dev-qa-db-fra.com

Est-il possible de créer un interprète «bootsTrapped» indépendant de l'interprète d'origine?

Selon Wikipedia, le terme "bootstrapping" dans le contexte des compilateurs d'écriture signifie ceci :

En informatique, la bootstrapping est le processus d'écriture d'un compilateur (ou d'assembleur) dans la langue de programmation source qu'elle a l'intention de compiler. L'application de cette technique conduit à un compilateur d'auto-hébergement.

Et je peux comprendre comment cela fonctionnerait. Cependant, l'histoire semble être un peu différente pour les interprètes. Maintenant, bien sûr, il est possible d'écrire un interprète auto-hébergement. Ce n'est pas ce que je demande. Ce que je demande réellement, c'est: est-il possible de faire un interprète auto-hébergé indépendant de l'original, premier interprète. Pour expliquer ce que je veux dire, considérez cet exemple:

Vous écrivez votre première version d'interpréteur dans la langue [~ # ~] x [~ # ~ ~], et l'interprète est pour une nouvelle langue que vous créez, appelée [~ # ~ # ~] y [~ # ~]. Vous utilisez d'abord la langue [~ # ~] x [~ # ~ ~] Compiler pour créer un exécutable. Vous pouvez maintenant interpréter des fichiers écrits dans votre nouvelle langue [~ # ~] y [~ # ~ ~] Utilisation de l'interprète écrit dans la langue [~ # ~ # ~ # ~]].

Maintenant, pour autant que je comprends bien, pour être capable de "bootstrap" l'interprète que vous avez écrit dans la langue X , vous auriez besoin de réécrire l'interprète dans la langue Y . Mais voici la prise: même si vous réécrivez l'intégralité de l'interprète dans la langue Y , vous allez toujours avoir besoin de l'interprète original que vous avez écrit dans la langue - X . Parce que doit exécuter l'interprète dans la langue Y , vous allez devoir interpréter les fichiers source. Mais qu'est-ce qui va interpréter exactement les fichiers source? Bien, cela ne peut être rien, bien sûr, vous êtes donc obligé de toujours utiliser le premier interprète.

Peu importe combien de nouveaux interprètes vous écrivez dans la langue [[~ # ~] y [~ # ~], vous allez toujours devoir utiliser le premier interprète écrit dans X Pour interpréter les interprètes ultérieurs. Cela semble être un problème simplement à cause de la nature des interprètes.

Cependant, sur le côté retournement, Cet article de Wikipedia sur les interprètes parle en réalité d'interprètes d'hébergement auto-hébergement . Voici un petit extrait qui est pertinent:

Un interprète auto-interprète est un interpréteur de langue de programmation écrit dans un langage de programmation qui peut interpréter; Un exemple est un interprète de base écrit en basique. Les auto-interprètes sont liés à des compilateurs d'hébergement.

Si aucun compilateur n'existe pour que la langue soit interprétée, la création d'un interprète auto-interprète nécessite la mise en œuvre de la langue dans une langue d'hôte (qui peut être un autre langage de programmation ou assembleur). En ayant un premier interprète tel que ceci, le système est bootstrapped et de nouvelles versions de l'interprète peuvent être développées dans la langue elle-même.

Ce n'est toujours pas clair pour moi, comment cela serait fait exactement. Il semble que peu importe quoi, vous allez toujours être obligé d'utiliser la première version de votre interprète écrit dans la langue hôte.

Maintenant, l'article mentionné ci-dessus liens vers un autre article dans lequel Wikipedia donne quelques exemples d'interprètes supposés auto-hébergements . Après une inspection de plus près, il semble que la partie principale "interprétation" de nombreux interprètes d'hébergement auto-hébergement (en particulier certaines des plus courantes telles que Pypy ou Rubinius) soient réellement écrites dans d'autres langues telles que C++ ou C.

Voilà ce que je décris ci-dessus possible? Un interprète auto-hébergé peut-il être indépendant de son hôte d'origine? Si oui, comment cela serait-il exactement?

21
Christian Dean

La réponse courte est: vous avez raison dans vos soupçons, vous avez toujours besoin d'un autre interprète soit écrit en [~ # ~] x [~ # ~] ou un compilateur de [~ # ~] y [~ # ~] à une autre langue pour laquelle vous avez déjà un interprète. Les interprètes exécutent, compilateurs ne font que traduire d'une langue à une autre, à certains point dans votre système, doit ​​être un interprète ... même c'est juste la CPU.

Peu importe combien de nouveaux interprètes vous écrivez dans un langage [~ # ~] y [~ # ~] , vous allez toujours avoir à utiliser le premier interprète écrit en [~ # ~] x [~ # ~] pour interpréter les interprètes suivants. Cela semble être un problème simplement à cause de la nature des interprètes.

Correct. Qu'est-ce que vous peut ​​faire est d'écrire un compilateur de [~ # ~] y [~ # ~] à [~ # ~] x [ ~ # ~] (ou une autre langue pour laquelle vous avez un interprète), et vous pouvez même le faire dans [~ # ~] y [~ # ~] . Ensuite, vous pouvez exécuter votre [~ # ~] y [~ # ~] compilateur écrit en [~ # ~] y [~ # ~] sur le [~ # ~] y [~ # ~] interprète écrit en [~ # ~] x [~ # ~] (ou la course sur [~ # ~] y [~ # ~] interprète écrit en [~ # ~] y [~ # ~] le [~ # ~] y [~ # ~] interprète écrit en [~ # ~] x [~ # ~], ou sur le [~ # ~] y [~ # ~] interprète écrit en [~ # ~] y [~ # ~] en cours d'exécution sur le [~ # ~] y [~ # ~] interprète écrit en [~ # ~] y [~ # ~] en cours d'exécution sur le [ ~ # ~] y [~ # ~] interprète écrit en [~ # ~] x [~ # ~] , ou ... ad infinitum) pour compiler votre [~ # ~] y [~ # ~] interprète écrit en [~ # ~] y [~ # ~] à [ ~ # ~] x [~ # ~] , de sorte que vous pouvez l'exécuter sur un [~ # ~] x [~ # ~] interprète. De cette façon, vous avez réussi à se débarrasser de votre [~ # ~] y [~ # ~] interprète écrit en [~ # ~] x [~ # ~] , mais maintenant vous avez besoin de [~ # ~] x [~ # ~] interprète (nous savons que nous avons déjà un, cependant, car sinon nous ne pouvions pas RAN le [~ # ~] x [~ # ~] interprète écrit en ) [~ # ~] y [~ # ~], - et ​​vous deviez écrire un [~ # ~] y [~ # ~] - à - [~ # ~] x [~ # ~ ] - premier compilateur.

Cependant, sur le côté, l'article de Wikipédia sur les interprètes parle en fait des interpréteurs auto-hébergement. Voici un petit extrait qui est pertinent:

Un interprète auto-interprète est un interpréteur de langue de programmation écrit dans un langage de programmation qui peut interpréter; Un exemple est un interprète de base écrit en basique. Les auto-interprètes sont liés à des compilateurs d'hébergement.

Si aucun compilateur n'existe pour que la langue soit interprétée, la création d'un interprète auto-interprète nécessite la mise en œuvre de la langue dans une langue d'hôte (qui peut être un autre langage de programmation ou assembleur). En ayant un premier interprète tel que ceci, le système est bootstrapped et de nouvelles versions de l'interprète peuvent être développées dans la langue elle-même.

Ce n'est toujours pas clair pour moi, comment cela serait fait exactement. Il semble que peu importe quoi, vous allez toujours être obligé d'utiliser la première version de votre interprète écrit dans la langue hôte.

Correct. Notez que l'article de Wikipedia dit explicitement que vous avez besoin deuxième mise en œuvre de votre langue, et il ne dit pas que vous pouvez vous débarrasser de la première.

Maintenant, l'article mentionné ci-dessus des liens vers un autre article dans lequel Wikipedia donne quelques exemples d'interprètes d'auto-hébergement supposés. Après une inspection de plus près, il semble que la partie principale "interprétation" de nombreux interprètes d'hébergement auto-hébergement (en particulier certaines des plus courantes telles que Pypy ou Rubinius) soient réellement écrites dans d'autres langues telles que C++ ou C.

Encore une fois, correcte. Ce sont des exemples vraiment mauvais. Prenez Rubinius, par exemple. Oui, il est vrai que le Ruby une partie de Rubinius est auto-hébergé, mais il est un compilateur, pas un interprète: il compile à Ruby code source pour Rubinius bytecode. La partie interprète OTOH n'est pas auto-hébergé: il interprète bytecode Rubinius, mais il est écrit en C++. Alors, appelant Rubinius un " interprète auto-hébergé " est erroné: le auto-hébergé partie est pas interprète, et interprète partie n'est pas auto-hébergé.

PyPy est similaire, mais encore plus incorrect: il est même pas écrit dans Python en premier lieu, il est écrit dans RPython, ce qui est une autre langue. Il est syntaxiquement similaire à Python, sémantiquement un " sous-ensemble étendu ", mais il est en fait un statiquement typé à peu près au même niveau d'abstraction que Java, et sa mise en œuvre est un compilateur avec plusieurs backends qui compile le code source RPython à C, ECMAScript code source, code octet CIL, bytecode JVM, ou Python code source.

Voilà ce que je décris ci-dessus possible? Un interprète auto-hôte peut-il être indépendant de son hôte d'origine? Si oui, comment cela serait-il exactement?

Non, pas seul. Vous devez soit garder l'interprète d'origine, soit écrire un compilateur et compiler votre auto-interprète.

Là-bas sont ​​Quelques VMS méta-circulaires, tels que - klein (écrit en auto ) et Maxine (écrit en Java ). Notez cependant que la définition de "méta-circulaire" est encore différente: ces ordinateurs virtuels ne sont pas écrits dans la langue qu'ils exécutent: Klein exécute auto-recode mais est écrit en soi, Maxine exécute JVM Bytecode mais est écrit en Java. Cependant, le code source auto/Java code source du VM est réellement compilé au bytecode auto/jvm, puis exécuté par la machine virtuelle, alors au moment où la VM est exécuté, c'est est ​​dans la langue qu'il exécute. Phew.

Notez également que ceci est différent de VMS tel que le Squeakvm et le Jikes RVM . Jikes est écrit en Java, et le Squeakvm est écrit en argot (un sous-ensemble syntaxique statiquement dactylographié et sémantique de SmallTalk à peu près au même niveau d'abstraction qu'un assembleur de haut niveau), et les deux sont statilement compilés au code natif avant qu'ils ne soient exécutés. Ils ne courent pas à l'intérieur d'eux-mêmes. Vous peut, cependant, exécutez-les sur-le-dessus d'eux-mêmes (ou sur un autre SmallTalk VM/jvm). Mais ce n'est pas "méta-circulaire" dans ce sens.

Maxine et Klein, Otoh do courir à l'intérieur d'eux-mêmes; Ils exécutent leur propre bytecode en utilisant leur propre mise en œuvre. Ceci est vraiment mentalité! Il permet certaines possibilités d'optimisation de cool, par exemple depuis que le programme VMs'exécute avec le programme utilisateur, il peut apporter des appels en ligne à partir du programme utilisateur au programme VM et vice versa, par exemple. L'appel à la poubelle ou l'allocateur de la mémoire peut être affiné dans le code de l'utilisateur et les rappels réfléchissants dans le code de l'utilisateur peuvent être inlinés dans la machine virtuelle. En outre, toutes les astuces d'optimisation intelligente que les VMS modernes font, où ils surveillent le programme d'exécution et l'optimisent en fonction de la charge de travail et des données réelles, le VM peut appliquer ces mêmes trucs en soi pendant qu'il exécute la programme utilisateur pendant que le programme utilisateur exécute la charge de travail spécifique. En d'autres termes, le VM hautement spécialisé pour que programme particulier exécutant que charge de travail particulière.

Toutefois, remarquez-moi que je suis revers l'utilisation du mot "interprète" ci-dessus et toujours utilisé "exécuter"? Eh bien, ces ordinateurs virtuels ne sont pas construits autour des interprètes, ils sont construits autour des compilateurs (JIT). Il y avait un interprète ajouté à Maxine plus tard, mais vous avez toujours besoin du compilateur: vous devez exécuter le VM ne fois sur le dessus d'un autre VM (par exemple, Oracle Hotspot dans le cas de maxine), de sorte que le VM peut compiler (JIT) se compiler. Dans le cas de Maxine, il sera jit compilé sa propre phase de démarrage, puis sérialisez ce code natif compilé à une image bootstrap VM VM écrit en C, bien que cela soit juste pour la commodité, cela pourrait être dans Java aussi). Maintenant, vous pouvez utiliser Maxine pour s'exécuter.

24
Jörg W Mittag