En général, dans les langages suffisamment généralistes, les compilateurs sont écrits dans le langage lui-même (c'est souvent une preuve que le langage a une bonne puissance d'expression ; en tout cas, qu'elle est suffisante pour écrire un compilateur).
C'est par exemple le cas de C, C++, Pascal, Java, Ada, Caml, Lisp -- la liste est bien sûr non exhaustive.
Du coup, il y a effectivement un problème d'amorçage (bootstrapping en anglais).
Ce que l'on fait alors, c'est réécrire, à la main, une toute petite partie du compilateur en langage de bas niveau (ex: assembleur), même mal et avec un code pas efficace du tout, de manière à compiler un morceau du compilateur en langage évolué, ce morceau servant à compilaer un autre morceau, et ainsi de suite, jusqu'à compiler l'intégralité du compilateur.
Et voilà !