Il n'est pas possible d'implémenter une sémantique d'appel de fonction sans utiliser une sorte de pile. Il est uniquement possible de jouer à des jeux de mots (par exemple, utilisez un nom différent, comme "FILO return buffer").
Il est possible d'utiliser quelque chose qui n'implémente pas la sémantique des appels de fonction (par exemple le style de passage de continuation, les acteurs), puis de construire la sémantique des appels de fonction par-dessus; mais cela signifie ajouter une sorte de structure de données pour suivre où le contrôle est passé lorsque la fonction revient, et cette structure de données serait un type de pile (ou une pile avec un nom / description différent).
Imaginez que vous ayez de nombreuses fonctions qui peuvent toutes s’appeler. Au moment de l'exécution, chaque fonction doit savoir où retourner lorsque la fonction se termine. Si vous first
appelez, second
vous avez:
second returns to somewhere in first
Ensuite, si vous avez des second
appels third
:
third returns to somewhere in second
second returns to somewhere in first
Ensuite, si vous avez des third
appels fourth
:
fourth returns to somewhere in third
third returns to somewhere in second
second returns to somewhere in first
Lorsque chaque fonction est appelée, davantage d'informations "où retourner" doivent être stockées quelque part.
Si une fonction retourne, ses informations "où retourner" sont utilisées et ne sont plus nécessaires. Par exemple, si fourth
retourne quelque part, third
la quantité d'informations "où retourner" deviendrait:
third returns to somewhere in second
second returns to somewhere in first
Fondamentalement; La "sémantique des appels de fonctions" implique que:
- vous devez avoir des informations "où retourner"
- la quantité d'informations augmente à mesure que les fonctions sont appelées et diminue lorsque les fonctions reviennent
- la première information "où retourner" stockée sera la dernière information "où retourner" rejetée
Ceci décrit un tampon FILO / LIFO ou une pile.
Si vous essayez d'utiliser un type d'arbre, chaque nœud de l'arborescence n'aura jamais plus d'un enfant. Remarque: un nœud avec plusieurs enfants ne peut se produire que si une fonction appelle 2 fonctions ou plus en même temps , ce qui nécessite une sorte de concurrence (par exemple, threads, fork (), etc.) et il ne s'agirait pas de "sémantique d'appel de fonction". Si chaque nœud de l'arborescence n'aura jamais plus d'un enfant; alors cet "arbre" ne serait utilisé que comme tampon FILO / LIFO ou pile; et parce qu'il n'est utilisé que comme tampon FILO / LIFO ou comme pile, il est juste de prétendre que «l'arbre» est une pile (et la seule différence est les jeux de mots et / ou les détails d'implémentation).
La même chose s'applique à toute autre structure de données qui pourrait éventuellement être utilisée pour implémenter la "sémantique d'appel de fonction" - elle sera utilisée comme une pile (et la seule différence est les jeux de mots et / ou les détails d'implémentation); à moins qu'il ne casse la "sémantique d'appel de fonction". Remarque: je fournirais des exemples pour d'autres structures de données si je le pouvais, mais je ne pense à aucune autre structure qui soit légèrement plausible.
Bien sûr, la façon dont une pile est implémentée est un détail d'implémentation. Ce pourrait être une zone de mémoire (où vous gardez une trace d'un "sommet de pile actuel"), ce pourrait être une sorte de liste liée (où vous gardez une trace de "l'entrée actuelle dans la liste"), ou il pourrait être implémenté dans certains autrement. Peu importe que le matériel ait ou non un support intégré.
Remarque: Si une seule invocation d'une procédure peut être active à tout moment; vous pouvez ensuite allouer statiquement de l'espace pour "où retourner". Il s'agit toujours d'une pile (par exemple, une liste chaînée d'entrées allouées statiquement utilisées de manière FILO / LIFO).
Notez également qu'il y a certaines choses qui ne suivent pas la "sémantique d'appel de fonction". Ces choses incluent «une sémantique potentiellement très différente» (par exemple, passage de continuation, modèle d'acteur); et comprend également des extensions communes à la "sémantique des appels de fonctions" comme la concurrence (threads, fibres, etc.), setjmp
/longjmp
, etc. , la gestion des exceptions, etc.