Stell dir das so vor: Jeder Funktionsaufruf bewirkt, dass die Anweisungen, die in der Funktion stehen, auf einen Zettel schreibst und diesen Zettel auf einen Stapel legst.
Wenn du mit einem Zettel fertig bist, nimmst du ihn vom Stapel runter. Du bearbeitest aber immer nur den Zettel, der gerade ganz oben liegt.
Wenn also der erste Aufruf von ausgaberueck passiert, schreibst du auf einen Zettel den Code dieser Methode. Dann arbeitest du ihn ab. Nun steht da drin ein Funktionsaufruf. Das heißt für dich: Neuer Zettel, wieder mit demselben Inhalt. Der vorherige Zettel wird erst einmal nicht weiter bearbeitet. Jeder weitere Aufruf bewirkt, dass ein weiterer Zettel auf dem Stapel landet, bis irgendwann die Bedingung nicht mehr wahr ist. Dann wird der oberste Zettel abgearbeitet, einschließlich der Ausgabe. Damit kann der oberste Zettel entfernt werden. Beim nächsten Zettel geht die Ausführung dann dort weiter, wo sie für den Aufruf unterbrochen wurde. Als nächstes wird also die Ausgabe des Zettels abgearbeitet, der jetzt oben liegt.
Du siehst, dadurch, dass die Ausgabe hinter dem Aufruf steht, geschieht die Ausgabe in umgekehrter Reihenfolge des Aufrufs, weil die Ausgabe erst beim "Abräumen" des Stapels passiert.