Неможливо реалізувати семантику виклику функцій без використання якогось стека. Можна грати лише в ігри в слова (наприклад, використовувати іншу назву для цього, наприклад, "FILO return buffer").
Можна використовувати те, що не реалізує семантику виклику функцій (наприклад, стиль передачі продовження, актори), а потім над ним будувати семантику виклику функцій; але це означає додавати якусь структуру даних, щоб відстежувати, куди передається управління, коли функція повертається, і ця структура даних буде типом стеку (або стека з іншим іменем / описом).
Уявіть, що у вас є багато функцій, які можуть всі телефонувати один одному. Під час виконання кожна функція повинна знати, куди слід повернутися, коли функція закінчується. Якщо first
дзвінки, second
то у вас є:
second returns to somewhere in first
Потім, якщо у вас є second
дзвінки third
:
third returns to somewhere in second
second returns to somewhere in first
Потім, якщо у вас є third
дзвінки fourth
:
fourth returns to somewhere in third
third returns to somewhere in second
second returns to somewhere in first
Як називається кожна функція, більше інформації "куди повернути" повинна зберігатися десь.
Якщо функція повертається, то її інформація "куди повернути" використовується і більше не потрібна. Наприклад, якщо fourth
повертається десь назад, third
то кількість інформації "куди повернутися" стане такою:
third returns to somewhere in second
second returns to somewhere in first
В основному; "Семантика виклику функції" означає, що:
- у вас повинна бути інформація "куди повернути"
- кількість інформації зростає у міру виклику функцій та зменшується, коли функції повертаються
- перший фрагмент інформації "куди повернути" зберігається буде останнім фрагментом інформації "куди повернути"
Це описує буфер FILO / LIFO або стек.
Якщо ви намагаєтесь використовувати тип дерева, то кожен вузол на дереві ніколи не матиме більше однієї дитини. Примітка: вузол з кількома дітьми може статися лише в тому випадку, якщо функція викликає одночасно 2 або більше функцій , що вимагає певної одночасності (наприклад, потоки, fork () тощо), і це не було б "семантикою виклику функції". Якщо кожен вузол на дереві ніколи не матиме більше однієї дитини; тоді це "дерево" буде використовуватися лише як буфер FILO / LIFO або стек; і тому, що він використовується лише як буфер FILO / LIFO або стек, справедливо стверджувати, що "дерево" є стеком (і єдиною різницею є слова в ігри та / або деталі реалізації).
Це ж стосується будь-якої іншої структури даних, яка, можливо, може бути використана для реалізації "семантики виклику функцій" - вона буде використовуватися як стек (і єдиною різницею є слова в ігри та / або деталі реалізації); якщо це не порушує "семантику виклику функції". Примітка. Я б наводив приклади для інших структур даних, якби міг, але я не можу придумати будь-яку іншу структуру, яка є мало правдоподібною.
Звичайно, як стек реалізований - це деталь реалізації. Це може бути область пам’яті (де ви відстежуєте «поточну вершину стека»), це може бути якийсь пов'язаний список (де ви відстежуєте «поточний запис у списку»), або він може бути реалізований у деяких інший шлях. Також не має значення, чи має апаратне забезпечення вбудовану підтримку чи ні.
Примітка: Якщо в будь-який момент може бути активним лише один виклик будь-якої процедури; тоді ви можете статично виділити простір для інформації "куди повернутися до". Це все ще стек (наприклад, пов'язаний список статично виділених записів, використовуваних способом FILO / LIFO).
Також зауважте, що є деякі речі, які не відповідають "семантиці виклику функції". Ці речі включають "потенційно дуже різну семантику" (наприклад, продовження проходження, акторська модель); а також включає поширені розширення на "функцію семантики викликів", як паралельність (потоки, волокна, що завгодно), setjmp
/ longjmp
, обробка виключень тощо.