The interactions between statements, expressions, and subexpressions at program run time can be viewed as:
Here, action is the series of steps performed to effect the statement, and expr is the expression whose value is used by action.
Expanding the above shows a typical order of events at run time:
Evaluate expr Perform action, using result of evaluation of expr Clean up after evaluating expr
So, if evaluating expr requires allocating memory, that memory can be freed before performing action only if it is not needed to hold the result of evaluating expr. Otherwise, it must be freed no sooner than after action has been performed.
The above are recursive definitions, in the sense that they apply to subexpressions of expr.
That is, evaluating expr involves evaluating all of its subexpressions, performing the action that computes the result value of expr, then cleaning up after evaluating those subexpressions.
The recursive nature of this evaluation is implemented via recursive-descent transformation of the top-level statements, their expressions, their subexpressions, and so on.
However, that recursive-descent transformation is, due to the nature of the GBEL, focused primarily on generating a single stream of code to be executed at run time.
Yet, from the above, it's clear that multiple streams of code must effectively be simultaneously generated during the recursive-descent analysis of statements.
The primary stream implements the primary action items, while at least two other streams implement the evaluation and clean-up items.
Requirements imposed by expressions include: