Une des raisons de cette technique (appelée bootstrapping, comme un autre utilisateur a répondu correctement), peut être d'utiliser différentes techniques d'optimisations du compilateur et de travaux (à peu près) comme suit:
Supposons que vous ayez un compilateur de travail Y, qui compile une langue X pour, disons, la langue d'assemblage. Ensuite, ce compilateur est tout ce dont vous avez besoin pour traduire un programme écrit en langage X en une forme compréhensible et exécutable (après une liaison, etc.) sur votre machine.
Maintenant, vous pensez que ce compilateur est bien écrit dans ses aspects principaux, mais pas si bien écrit dans d'autres aspects (par exemple: il est très lent dans l'évaluation d'une longue déclaration de cas).
Ce que vous faites est: vous réécrivez le langage complet X en utilisant seulement un sous-ensemble (bien implémenté avec le compilateur Y) du langage X et optimisez l'évaluation des longues déclarations de cas mentionnées (exemple).
Maintenant, vous avez un compilateur Z, qui évalue un programme de langage X à un programme qui ne comprend que des instructions de base du langage X. Avec le compilateur Y vous pouvez maintenant le traduire en langage assembleur.
Généralement: À un certain point d'une longue rangée de compilateurs, il devrait y avoir un compilateur, qui génère réellement des instructions machine valides ou vous ne pourrez pas exécuter votre joli programme (cela semble trivial, mais bon à garder à l'esprit) .
EDIT @merito: un compilateur traduit un programme d'un langage source vers un langage cible, qui peut être un code binaire, mais pas nécessairement. Votre distinction entre interprète et compilateur me semble erronée.