From: Craig Burley Date: Sat, 17 Apr 1999 11:45:01 +0000 (-0400) Subject: forgot to add ffe.texi, the actual g77 front-end internals docs X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=8a19a44a1fc162ba149500603e9951cc9cccf2d2;p=gcc.git forgot to add ffe.texi, the actual g77 front-end internals docs From-SVN: r26518 --- diff --git a/gcc/f/ffe.texi b/gcc/f/ffe.texi new file mode 100644 index 00000000000..4948050074a --- /dev/null +++ b/gcc/f/ffe.texi @@ -0,0 +1,883 @@ +@node Front End +@chapter Front End +@cindex GNU Fortran Front End (FFE) +@cindex FFE +@cindex @code{g77}, front end +@cindex front end, @code{g77} + +This chapter describes some aspects of the design and implementation +of the @code{g77} front end. + +@menu +* Philosophy of Code Generation:: +* Two-pass Design:: +* Challenges Posed:: +* Transforming Statements:: +* Transforming Expressions:: +@end menu + +@node Philosophy of Code Generation +@section Philosophy of Code Generation + +Don't poke the bear. + +The @code{g77} front end generates code +via the @code{gcc} back end. + +@cindex GNU Back End (GBE) +@cindex GBE +@cindex @code{gcc}, back end +@cindex back end, gcc +@cindex code generator +The @code{gcc} back end (GBE) is a large, complex +labyrinth of intricate code +written in a combination of the C language +and specialized languages internal to @code{gcc}. + +While the @emph{code} that implements the GBE +is written in a combination of languages, +the GBE itself is, +to the front end for a language like Fortran, +best viewed as a @emph{compiler} +that compiles its own, unique, language. + +The GBE's ``source'', then, is written in this language, +which consists primarily of +a combination of calls to GBE functions +and @dfn{tree} nodes +(which are, themselves, created +by calling GBE functions). + +So, the @code{g77} generates code by, in effect, +translating the Fortran code it reads +into a form ``written'' in the ``language'' +of the @code{gcc} back end. + +@cindex GBEL +@cindex GNU Back End Language (GBEL) +This language will heretofore be referred to as @dfn{GBEL}, +for GNU Back End Language. + +GBEL is an evolving language, +not fully specified in any published form +as of this writing. +It offers many facilities, +but its ``core'' facilities +are those that corresponding most directly +to those needed to support @code{gcc} +(compiling code written in GNU C). + +The @code{g77} Fortran Front End (FFE) +is designed and implemented +to navigate the currents and eddies +of ongoing GBEL and @code{gcc} development +while also delivering on the potential +of an integrated FFE +(as compared to using a converter like @code{f2c} +and feeding the output into @code{gcc}). + +Goals of the FFE's code-generation strategy include: + +@itemize @bullet +@item +High likelihood of generation of correct code, +or, failing that, producing a fatal diagnostic or crashing. + +@item +Generation of highly optimized code, +as directed by the user +via GBE-specific (versus @code{g77}-specific) constructs, +such as command-line options. + +@item +Fast overall (FFE plus GBE) compilation. + +@item +Preservation of source-level debugging information. +@end itemize + +The strategies historically, and currently, used by the FFE +to achieve these goals include: + +@itemize @bullet +@item +Use of GBEL constructs that most faithfully encapsulate +the semantics of Fortran. + +@item +Avoidance of GBEL constructs that are so rarely used, +or limited to use in specialized situations not related to Fortran, +that their reliability and performance has not yet been established +as sufficient for use by the FFE. + +@item +Flexible design, to readily accommodate changes to specific +code-generation strategies, perhaps governed by command-line options. +@end itemize + +@cindex Bear-poking +@cindex Poking the bear +``Don't poke the bear'' somewhat summarizes the above strategies. +The GBE is the bear. +The FFE is designed and implemented to avoid poking it +in ways that are likely to just annoy it. +The FFE usually either tackles it head-on, +or avoids treating it in ways dissimilar to how +the @code{gcc} front end treats it. + +For example, the FFE uses the native array facility in the back end +instead of the lower-level pointer-arithmetic facility +used by @code{gcc} when compiling @code{f2c} output). +Theoretically, this presents more opportunities for optimization, +faster compile times, +and the production of more faithful debugging information. +These benefits were not, however, immediately realized, +mainly because @code{gcc} itself makes little or no use +of the native array facility. + +Complex arithmetic is a case study of the evolution of this strategy. +When originally implemented, +the GBEL had just evolved its own native complex-arithmetic facility, +so the FFE took advantage of that. + +When porting @code{g77} to 64-bit systems, +it was discovered that the GBE didn't really +implement its native complex-arithmetic facility properly. + +The short-term solution was to rewrite the FFE +to instead use the lower-level facilities +that'd be used by @code{gcc}-compiled code +(assuming that code, itself, didn't use the native complex type +provided, as an extension, by @code{gcc}), +since these were known to work, +and, in any case, if shown to not work, +would likely be rapidly fixed +(since they'd likely not work for vanilla C code in similar circumstances). + +However, the rewrite accommodated the original, native approach as well +by offering a command-line option to select it over the emulated approach. +This allowed users, and especially GBE maintainers, to try out +fixes to complex-arithmetic support in the GBE +while @code{g77} continued to default to compiling more code correctly, +albeit producing (typically) slower executables. + +As of April 1999, it appeared that the last few bugs +in the GBE's support of its native complex-arithmetic facility +were worked out. +The FFE was changed back to default to using that native facility, +leaving emulation as an option. + +Other Fortran constructs---arrays, character strings, +complex division, @code{COMMON} and @code{EQUIVALENCE} aggregates, +and so on---involve issues similar to those pertaining to complex arithmetic. + +So, it is possible that the history +of how the FFE handled complex arithmetic +will be repeated, probably in modified form +(and hopefully over shorter timeframes), +for some of these other facilities. + +@node Two-pass Design +@section Two-pass Design + +The FFE does not tell the GBE anything about a program unit +until after the last statement in that unit has been parsed. +(A program unit is a Fortran concept that corresponds, in the C world, +mostly closely to functions definitions in ISO C. +That is, a program unit in Fortran is like a top-level function in C. +Nested functions, found among the extensions offered by GNU C, +correspond roughly to Fortran's statement functions.) + +So, while parsing the code in a program unit, +the FFE saves up all the information +on statements, expressions, names, and so on, +until it has seen the last statement. + +At that point, the FFE revisits the saved information +(in what amounts to a second @dfn{pass} over the program unit) +to perform the actual translation of the program unit into GBEL, +ultimating in the generation of assembly code for it. + +Some lookahead is performed during this second pass, +so the FFE could be viewed as a ``two-plus-pass'' design. + +@menu +* Two-pass Code:: +* Why Two Passes:: +@end menu + +@node Two-pass Code +@subsection Two-pass Code + +Most of the code that turns the first pass (parsing) +into a second pass for code generation +is in @file{@value{path-g77}/std.c}. + +It has external functions, +called mainly by siblings in @file{@value{path-g77}/stc.c}, +that record the information on statements and expressions +in the order they are seen in the source code. +These functions save that information. + +It also has an external function that revisits that information, +calling the siblings in @file{@value{path-g77}/ste.c}, +which handles the actual code generation +(by generating GBEL code, +that is, by calling GBE routines +to represent and specify expressions, statements, and so on). + +@node Why Two Passes +@subsection Why Two Passes + +The need for two passes was not immediately evident +during the design and implementation of the code in the FFE +that was to produce GBEL. +Only after a few kludges, +to handle things like incorrectly-guessed @code{ASSIGN} label nature, +had been implemented, +did enough evidence pile up to make it clear +that @file{std.c} had to be introduced to intercept, +save, then revisit as part of a second pass, +the digested contents of a program unit. + +Other such missteps have occurred during the evolution of the FFE, +because of the different goals of the FFE and the GBE. + +Because the GBE's original, and still primary, goal +was to directly support the GNU C language, +the GBEL, and the GBE itself, +requires more complexity +on the part of most front ends +than it requires of @code{gcc}'s. + +For example, +the GBEL offers an interface that permits the @code{gcc} front end +to implement most, or all, of the language features it supports, +without the front end having to +make use of non-user-defined variables. +(It's almost certainly the case that all of K&R C, +and probably ANSI C as well, +is handled by the @code{gcc} front end +without declaring such variables.) + +The FFE, on the other hand, must resort to a variety of ``tricks'' +to achieve its goals. + +Consider the following C code: + +@smallexample +int +foo (int a, int b) +@{ + int c = 0; + + if ((c = bar (c)) == 0) + goto done; + + quux (c << 1); + +done: + return c; +@} +@end smallexample + +Note what kinds of objects are declared, or defined, before their use, +and before any actual code generation involving them +would normally take place: + +@itemize @bullet +@item +Return type of function + +@item +Entry point(s) of function + +@item +Dummy arguments + +@item +Variables + +@item +Initial values for variables +@end itemize + +Whereas, the following items can, and do, +suddenly appear ``out of the blue'' in C: + +@itemize @bullet +@item +Label references + +@item +Function references +@end itemize + +Not surprisingly, the GBE faithfully permits the latter set of items +to be ``discovered'' partway through GBEL ``programs'', +just as they are permitted to in C. + +Yet, the GBE has tended, at least in the past, +to be reticent to fully support similar ``late'' discovery +of items in the former set. + +This makes Fortran a poor fit for the ``safe'' subset of GBEL. +Consider: + +@smallexample + FUNCTION X (A, ARRAY, ID1) + CHARACTER*(*) A + DOUBLE PRECISION X, Y, Z, TMP, EE, PI + REAL ARRAY(ID1*ID2) + COMMON ID2 + EXTERNAL FRED + + ASSIGN 100 TO J + CALL FOO (I) + IF (I .EQ. 0) PRINT *, A(0) + GOTO 200 + + ENTRY Y (Z) + ASSIGN 101 TO J +200 PRINT *, A(1) + READ *, TMP + GOTO J +100 X = TMP * EE + RETURN +101 Y = TMP * PI + CALL FRED + DATA EE, PI /2.71D0, 3.14D0/ + END +@end smallexample + +Here are some observations about the above code, +which, while somewhat contrived, +conforms to the FORTRAN 77 and Fortran 90 standards: + +@itemize @bullet +@item +The return type of function @samp{X} is not known +until the @samp{DOUBLE PRECISION} line has been parsed. + +@item +Whether @samp{A} is a function or a variable +is not known until the @samp{PRINT *, A(0)} statement +has been parsed. + +@item +The bounds of the array of argument @samp{ARRAY} +depend on a computation involving +the subsequent argument @samp{ID1} +and the blank-common member @samp{ID2}. + +@item +Whether @samp{Y} and @samp{Z} are local variables, +additional function entry points, +or dummy arguments to additional entry points +is not known +until the @samp{ENTRY} statement is parsed. + +@item +Similarly, whether @samp{TMP} is a local variable is not known +until the @samp{READ *, TMP} statement is parsed. + +@item +The initial values for @samp{EE} and @samp{PI} +are not known until after the @samp{DATA} statement is parsed. + +@item +Whether @samp{FRED} is a function returning type @code{REAL} +or a subroutine +(which can be thought of as returning type @code{void} +@emph{or}, to support alternate returns in a simple way, +type @code{int}) +is not known +until the @samp{CALL FRED} statement is parsed. + +@item +Whether @samp{100} is a @code{FORMAT} label +or the label of an executable statement +is not known +until the @samp{X =} statement is parsed. +(These two types of labels get @emph{very} different treatment, +especially when @code{ASSIGN}'ed.) + +@item +That @samp{J} is a local variable is not known +until the first @samp{ASSIGN} statement is parsed. +(This happens @emph{after} executable code has been seen.) +@end itemize + +Very few of these ``discoveries'' +can be accommodated by the GBE as it has evolved over the years. +The GBEL doesn't support several of them, +and those it might appear to support +don't always work properly, +especially in combination with other GBEL and GBE features, +as implemented in the GBE. + +(Had the GBE and its GBEL originally evolved to support @code{g77}, +the shoe would be on the other foot, so to speak---most, if not all, +of the above would be directly supported by the GBEL, +and a few C constructs would probably not, as they are in reality, +be supported. +Both this mythical, and today's real, GBE caters to its GBEL +by, sometimes, scrambling around, cleaning up after itself---after +discovering that assumptions it made earlier during code generation +are incorrect.) + +So, the FFE handles these discrepancies---between the order in which +it discovers facts about the code it is compiling, +and the order in which the GBEL and GBE support such discoveries---by +performing what amounts to two +passes over each program unit. + +(A few ambiguities can remain at that point, +such as whether, given @samp{EXTERNAL BAZ} +and no other reference to @samp{BAZ} in the program unit, +it is a subroutine, a function, or a block-data---which, in C-speak, +governs its declared return type. +Fortunately, these distinctions are easily finessed +for the procedure, library, and object-file interfaces +supported by @code{g77}.) + +@node Challenges Posed +@section Challenges Posed + +Consider the following Fortran code, which uses various extensions +(including some to Fortran 90): + +@smallexample +SUBROUTINE X(A) +CHARACTER*(*) A +COMPLEX CFUNC +INTEGER*2 CLOCKS(200) +INTEGER IFUNC + +CALL SYSTEM_CLOCK (CLOCKS (IFUNC (CFUNC ('('//A//')')))) +@end smallexample + +The above poses the following challenges to any Fortran compiler +that uses run-time interfaces, and a run-time library, roughly similar +to those used by @code{g77}: + +@itemize @bullet +@item +Assuming the library routine that supports @code{SYSTEM_CLOCK} +expects to set an @code{INTEGER*4} variable via its @code{COUNT} argument, +the compiler must make available to it a temporary variable of that type. + +@item +Further, after the @code{SYSTEM_CLOCK} library routine returns, +the compiler must ensure that the temporary variable it wrote +is copied into the appropriate element of the @samp{CLOCKS} array. +(This assumes the compiler doesn't just reject the code, +which it should if it is compiling under some kind of a "strict" option.) + +@item +To determine the correct index into the @samp{CLOCKS} array, +(putting aside the fact that the index, in this particular case, +need not be computed until after +the @code{SYSTEM_CLOCK} library routine returns), +the compiler must ensure that the @code{IFUNC} function is called. + +That requires evaluating its argument, +which requires, for @code{g77} +(assuming @code{-ff2c} is in force), +reserving a temporary variable of type @code{COMPLEX} +for use as a repository for the return value +being computed by @samp{CFUNC}. + +@item +Before invoking @samp{CFUNC}, +is argument must be evaluated, +which requires allocating, at run time, +a temporary large enough to hold the result of the concatenation, +as well as actually performing the concatenation. + +@item +The large temporary needed during invocation of @code{CFUNC} +should, ideally, be deallocated +(or, at least, left to the GBE to dispose of, as it sees fit) +as soon as @code{CFUNC} returns, +which means before @code{IFUNC} is called +(as it might need a lot of dynamically allocated memory). +@end itemize + +@code{g77} currently doesn't support all of the above, +but, so that it might someday, it has evolved to handle +at least some of the above requirements. + +Meeting the above requirements is made more challenging +by conforming to the requirements of the GBEL/GBE combination. + +@node Transforming Statements +@section Transforming Statements + +Most Fortran statements are given their own block, +and, for temporary variables they might need, their own scope. +(A block is what distinguishes @samp{@{ foo (); @}} +from just @samp{foo ();} in C. +A scope is included with every such block, +providing a distinct name space for local variables.) + +Label definitions for the statement precede this block, +so @samp{10 PRINT *, I} is handled more like +@samp{fl10: @{ @dots{} @}} than @samp{@{ fl10: @dots{} @}} +(where @samp{fl10} is just a notation meaning ``Fortran Label 10'' +for the purposes of this document). + +@menu +* Statements Needing Temporaries:: +* Transforming DO WHILE:: +* Transforming Iterative DO:: +* Transforming Block IF:: +* Transforming SELECT CASE:: +@end menu + +@node Statements Needing Temporaries +@subsection Statements Needing Temporaries + +Any temporaries needed during, but not beyond, +execution of a Fortran statement, +are made local to the scope of that statement's block. + +This allows the GBE to share storage for these temporaries +among the various statements without the FFE +having to manage that itself. + +(The GBE could, of course, decide to optimize +management of these temporaries. +For example, it could, theoretically, +schedule some of the computations involving these temporaries +to occur in parallel. +More practically, it might leave the storage for some temporaries +``live'' beyond their scopes, to reduce the number of +manipulations of the stack pointer at run time.) + +Temporaries needed across distinct statement boundaries usually +are associated with Fortran blocks (such as @code{DO}/@code{END DO}). +(Also, there might be temporaries not associated with blocks at all---these +would be in the scope of the entire program unit.) + +Each Fortran block @emph{should} get its own block/scope in the GBE. +This is best, because it allows temporaries to be more naturally handled. +However, it might pose problems when handling labels +(in particular, when they're the targets of @code{GOTO}s outside the Fortran +block), and generally just hassling with replicating +parts of the @code{gcc} front end +(because the FFE needs to support +an arbitrary number of nested back-end blocks +if each Fortran block gets one). + +So, there might still be a need for top-level temporaries, whose +``owning'' scope is that of the containing procedure. + +Also, there seems to be problems declaring new variables after +generating code (within a block) in the back end, leading to, e.g., +@samp{label not defined before binding contour} or similar messages, +when compiling with @samp{-fstack-check} or +when compiling for certain targets. + +Because of that, and because sometimes these temporaries are not +discovered until in the middle of of generating code for an expression +statement (as in the case of the optimization for @samp{X**I}), +it seems best to always +pre-scan all the expressions that'll be expanded for a block +before generating any of the code for that block. + +This pre-scan then handles discovering and declaring, to the back end, +the temporaries needed for that block. + +It's also important to treat distinct items in an I/O list as distinct +statements deserving their own blocks. +That's because there's a requirement +that each I/O item be fully processed before the next one, +which matters in cases like @samp{READ (*,*), I, A(I)}---the +element of @samp{A} read in the second item +@emph{must} be determined from the value +of @samp{I} read in the first item. + +@node Transforming DO WHILE +@subsection Transforming DO WHILE + +@samp{DO WHILE(expr)} @emph{must} be implemented +so that temporaries needed to evaluate @samp{expr} +are generated just for the test, each time. + +Consider how @samp{DO WHILE (A//B .NE. 'END'); @dots{}; END DO} is transformed: + +@smallexample +for (;;) + @{ + int temp0; + + @{ + char temp1[large]; + + libg77_catenate (temp1, a, b); + temp0 = libg77_ne (temp1, 'END'); + @} + + if (! temp0) + break; + + @dots{} + @} +@end smallexample + +In this case, it seems like a time/space tradeoff +between allocating and deallocating @samp{temp1} for each iteration +and allocating it just once for the entire loop. + +However, if @samp{temp1} is allocated just once for the entire loop, +it could be the wrong size for subsequent iterations of that loop +in cases like @samp{DO WHILE (A(I:J)//B .NE. 'END')}, +because the body of the loop might modify @samp{I} or @samp{J}. + +So, the above implementation is used, +though a more optimal one can be used +in specific circumstances. + +@node Transforming Iterative DO +@subsection Transforming Iterative DO + +An iterative @code{DO} loop +(one that specifies an iteration variable) +is required by the Fortran standards +to be implemented as though an iteration count +is computed before entering the loop body, +and that iteration count used to determine +the number of times the loop body is to be performed +(assuming the loop isn't cut short via @code{GOTO} or @code{EXIT}). + +The FFE handles this by allocating a temporary variable +to contain the computed number of iterations. +Since this variable must be in a scope that includes the entire loop, +a GBEL block is created for that loop, +and the variable declared as belonging to the scope of that block. + +@node Transforming Block IF +@subsection Transforming Block IF + +Consider: + +@smallexample +SUBROUTINE X(A,B,C) +CHARACTER*(*) A, B, C +LOGICAL LFUNC + +IF (LFUNC (A//B)) THEN + CALL SUBR1 +ELSE IF (LFUNC (A//C)) THEN + CALL SUBR2 +ELSE + CALL SUBR3 +END +@end smallexample + +The arguments to the two calls to @samp{LFUNC} +require dynamic allocation (at run time), +but are not required during execution of the @samp{CALL} statements. + +So, the scopes of those temporaries must be within blocks inside +the block corresponding to the Fortran @code{IF} block. + +This cannot be represented ``naturally'' +in vanilla C, nor in GBEL. +The @samp{if}, @samp{elseif}, @samp{else}, +and @samp{endif} constructs +provided by both languages must, +for a given @samp{if} block, +share the same C/GBE block. + +Therefore, any temporaries needed during evaluation of @samp{expr} +while executing @samp{ELSE IF(expr)} +must either have been predeclared +at the top of the corresponding @code{IF} block, +or declared within a new block for that @code{ELSE IF}---a block that, +since it cannot contain the @code{else} or @code{else if} itself +(due to the above requirement), +actually implements the rest of the @code{IF} block's +@code{ELSE IF} and @code{ELSE} statements +within an inner block. + +The FFE takes the latter approach. + +@node Transforming SELECT CASE +@subsection Transforming SELECT CASE + +@code{SELECT CASE} poses a few interesting problems for code generation, +if efficiency and frugal stack management are important. + +Consider @samp{SELECT CASE (I('PREFIX'//A))}, +where @samp{A} is @code{CHARACTER*(*)}. +In a case like this---basically, +in any case where largish temporaries are needed +to evaluate the expression---those temporaries should +not be ``live'' during execution of any of the @code{CASE} blocks. + +So, evaluation of the expression is best done within its own block, +which in turn is within the @code{SELECT CASE} block itself +(which contains the code for the CASE blocks as well, +though each within their own block). + +Otherwise, we'd have the rough equivalent of this pseudo-code: + +@smallexample +@{ + char temp[large]; + + libg77_catenate (temp, 'prefix', a); + + switch (i (temp)) + @{ + case 0: + @dots{} + @} +@} +@end smallexample + +And that would leave temp[large] in scope during the CASE blocks +(although a clever back end *could* see that it isn't referenced +in them, and thus free that temp before executing the blocks). + +So this approach is used instead: + +@smallexample +@{ + int temp0; + + @{ + char temp1[large]; + + libg77_catenate (temp1, 'prefix', a); + temp0 = i (temp1); + @} + + switch (temp0) + @{ + case 0: + @dots{} + @} +@} +@end smallexample + +Note how @samp{temp1} goes out of scope before starting the switch, +thus making it easy for a back end to free it. + +The problem @emph{that} solution has, however, +is with @samp{SELECT CASE('prefix'//A)} +(which is currently not supported). + +Unless the GBEL is extended to support arbitrarily long character strings +in its @code{case} facility, +the FFE has to implement @code{SELECT CASE} on @code{CHARACTER} +(probably excepting @code{CHARACTER*1}) +using a cascade of +@code{if}, @code{elseif}, @code{else}, and @code{endif} constructs +in GBEL. + +To prevent the (potentially large) temporary, +needed to hold the selected expression itself (@samp{'prefix'//A}), +from being in scope during execution of the @code{CASE} blocks, +two approaches are available: + +@itemize @bullet +@item +Pre-evaluate all the @code{CASE} tests, +producing an integer ordinal that is used, +a la @samp{temp0} in the earlier example, +as if @samp{SELECT CASE(temp0)} had been written. + +Each corresponding @code{CASE} is replaced with @samp{CASE(@var{i})}, +where @var{i} is the ordinal for that case, +determined while, or before, +generating the cascade of @samp{if}-related constructs +to cope with @code{CHARACTER} selection. + +@item +Make @samp{temp0} above just +large enough to hold the longest @code{CASE} string +that'll actually be compared against the expression +(in this case, @samp{'prefix'//A}). + +Since that length must be constant +(because @code{CASE} expressions are all constant), +it won't be so large, +and, further, @samp{temp1} need not be dynamically allocated, +since normal @code{CHARACTER} assignment can be used +into the fixed-length @samp{temp0}. +@end itemize + +Both of these solutions require @code{SELECT CASE} implementation +to be changed so all the corresponding @code{CASE} statements +are seen during the actual code generation for @code{SELECT CASE}. + +@node Transforming Expressions +@section Transforming Expressions + +The interactions between statements, expressions, and subexpressions +at program run time can be viewed as: + +@smallexample +@var{action}(@var{expr}) +@end smallexample + +Here, @var{action} is the series of steps +performed to effect the statement, +and @var{expr} is the expression +whose value is used by @var{action}. + +Expanding the above shows a typical order of events at run time: + +@smallexample +Evaluate @var{expr} +Perform @var{action}, using result of evaluation of @var{expr} +Clean up after evaluating @var{expr} +@end smallexample + +So, if evaluating @var{expr} requires allocating memory, +that memory can be freed before performing @var{action} +only if it is not needed to hold the result of evaluating @var{expr}. +Otherwise, it must be freed no sooner than +after @var{action} has been performed. + +The above are recursive definitions, +in the sense that they apply to subexpressions of @var{expr}. + +That is, evaluating @var{expr} involves +evaluating all of its subexpressions, +performing the @var{action} that computes the +result value of @var{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, @emph{their} subexpressions, and so on. + +However, that recursive-descent transformation is, +due to the nature of the GBEL, +focused primarily on generating a @emph{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 @var{action} items, +while at least two other streams implement +the evaluation and clean-up items. + +Requirements imposed by expressions include: + +@itemize @bullet +@item +Whether the caller needs to have a temporary ready +to hold the value of the expression. + +@item +Other stuff??? + + +@end itemize