6.1. Jak pracuje kompilator? 167
ASM(Instr2) koniec:
ASM(instr) znacza ciąg instrukcji asemblerowych odpowiadających instrukcji im Ir, a if, if_not i goto są elementarnymi instrukcjami procesora (słowami klu czowymi języka asemblera).
Każdą dowolną instrukcję strukturalną można przetłumaczyć na jej postać sekwencyjną (rzeczywiste kompilatory tym właśnie między innymi się zajmują) Także w przypadku wywołań proceduralnych czynność ta. wbrew pozorom, nie jest skomplikowana. Przyjmując pewne uproszczenia, ciąg instrukcji:
Insrrl;
P(x) ;
Instrż;
odpowiada, już po przetłumaczeniu przez kompilator, następującej sekwencji:
ASM(Instrl)
tmp=x
adr_powr-etl goto et2
etl:
ASM(Instr2); et2:
ASM(P(tmp>); goto adr_powr
Czy w podany wyżej sposób da się również potraktować wywołania rekurencyjne (w procedurze P wywołujemy jeszcze raz P)1 Oczywiście nie powielamy tyle razy fragmentu kodu odpowiadającego tekstowi P, aby obsłużyć wszystkie jej egzemplarze - byłoby to absurdalne i niewykonalne w praktyce. Jedyne, co nam pozostaje, to zasymulować wywołanie rekurencyjne poprzez zwykłe wielokrotne użycie tego bloku instrukcji, który odpowiada procedurze P - z jednym wszakże zastrzeżeniem: wywołanie rekurencyjne nie może zacierać informacji, które są niezbędne do prawidłowego kontynuowania wykonywania programu.
Niestety, sposób podany poprzednio nie spełnia tego warunku. Spójrzmy na przykład na następujący program rckurencyjny1:
Piint x)
(
Instrl;
P(F(x)];
Inscr2;
)
Funkcja F oznacza grupę przekształceń dokonywanych na parametrach funkcji.