📄 ffe.texi
字号:
Because of that, and because sometimes these temporaries are notdiscovered until in the middle of of generating code for an expressionstatement (as in the case of the optimization for @samp{X**I}),it seems best to alwayspre-scan all the expressions that'll be expanded for a blockbefore 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 distinctstatements deserving their own blocks.That's because there's a requirementthat each I/O item be fully processed before the next one,which matters in cases like @samp{READ (*,*), I, A(I)}---theelement of @samp{A} read in the second item@emph{must} be determined from the valueof @samp{I} read in the first item.@node Transforming DO WHILE@subsection Transforming DO WHILE@samp{DO WHILE(expr)} @emph{must} be implementedso 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:@smallexamplefor (;;) @{ int temp0; @{ char temp1[large]; libg77_catenate (temp1, a, b); temp0 = libg77_ne (temp1, 'END'); @} if (! temp0) break; @dots{} @}@end smallexampleIn this case, it seems like a time/space tradeoffbetween allocating and deallocating @samp{temp1} for each iterationand 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 loopin 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 usedin specific circumstances.@node Transforming Iterative DO@subsection Transforming Iterative DOAn iterative @code{DO} loop(one that specifies an iteration variable)is required by the Fortran standardsto be implemented as though an iteration countis computed before entering the loop body,and that iteration count used to determinethe 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 variableto 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 IFConsider:@smallexampleSUBROUTINE X(A,B,C)CHARACTER*(*) A, B, CLOGICAL LFUNCIF (LFUNC (A//B)) THEN CALL SUBR1ELSE IF (LFUNC (A//C)) THEN CALL SUBR2ELSE CALL SUBR3END@end smallexampleThe arguments to the two calls to @samp{LFUNC}require dynamic allocation (at run time),but are not required during execution of the @code{CALL} statements.So, the scopes of those temporaries must be within blocks insidethe block corresponding to the Fortran @code{IF} block.This cannot be represented ``naturally''in vanilla C, nor in GBEL.The @code{if}, @code{elseif}, @code{else},and @code{endif} constructsprovided by both languages must,for a given @code{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 predeclaredat 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} statementswithin 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 neededto evaluate the expression---those temporaries shouldnot 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 smallexampleAnd that would leave temp[large] in scope during the CASE blocks(although a clever back end *could* see that it isn't referencedin 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 smallexampleNote 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 stringsin 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} constructsin 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@itemPre-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 @code{if}-related constructsto cope with @code{CHARACTER} selection.@itemMake @samp{temp0} above justlarge enough to hold the longest @code{CASE} stringthat'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 usedinto the fixed-length @samp{temp0}.@end itemizeBoth of these solutions require @code{SELECT CASE} implementationto be changed so all the corresponding @code{CASE} statementsare seen during the actual code generation for @code{SELECT CASE}.@node Transforming Expressions@section Transforming ExpressionsThe interactions between statements, expressions, and subexpressionsat program run time can be viewed as:@smallexample@var{action}(@var{expr})@end smallexampleHere, @var{action} is the series of stepsperformed to effect the statement,and @var{expr} is the expressionwhose value is used by @var{action}.Expanding the above shows a typical order of events at run time:@smallexampleEvaluate @var{expr}Perform @var{action}, using result of evaluation of @var{expr}Clean up after evaluating @var{expr}@end smallexampleSo, 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 thanafter @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} involvesevaluating all of its subexpressions,performing the @var{action} that computes theresult value of @var{expr},then cleaning up after evaluating those subexpressions.The recursive nature of this evaluation is implementedvia 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 codeto be executed at run time.Yet, from the above, it's clear that multiple streams of codemust effectively be simultaneously generatedduring the recursive-descent analysis of statements.The primary stream implements the primary @var{action} items,while at least two other streams implementthe evaluation and clean-up items.Requirements imposed by expressions include:@itemize @bullet@itemWhether the caller needs to have a temporary readyto hold the value of the expression.@itemOther stuff???@end itemize@node Internal Naming Conventions@section Internal Naming ConventionsNames exported by FFE modules have the following (regular-expression) forms.Note that all names beginning @code{ffe@var{mod}} or @code{FFE@var{mod}},where @var{mod} is lowercase or uppercase alphanumerics, respectively,are exported by the module @code{ffe@var{mod}},with the source code doing the exporting in @file{@var{mod}.h}.(Usually, the source code for the implementation is in @file{@var{mod}.c}.)Identifiers that don't fit the following formsare not considered exported,even if they are according to the C language.(For example, they might be made available to other modulessolely for use within expansions of exported macros,not for use within any source code in those other modules.)@table @code@item ffe@var{mod}The single typedef exported by the module.@item FFE@var{umod}_[A-Z][A-Z0-9_]*(Where @var{umod} is the uppercase for of @var{mod}.)A @code{#define} or @code{enum} constant of the type @code{ffe@var{mod}}.@item ffe@var{mod}[A-Z][A-Z][a-z0-9]*A typedef exported by the module.The portion of the identifier after @code{ffe@var{mod}} isreferred to as @code{ctype}, a capitalized (mixed-case) formof @code{type}.@item FFE@var{umod}_@var{type}[A-Z][A-Z0-9_]*[A-Z0-9]?(Where @var{umod} is the uppercase for of @var{mod}.)A @code{#define} or @code{enum} constant of the type@code{ffe@var{mod}@var{type}},where @var{type} is the lowercase form of @var{ctype}in an exported typedef.@item ffe@var{mod}_@var{value}A function that does or returns something,as described by @var{value} (see below).@item ffe@var{mod}_@var{value}_@var{input}A function that does or returns something basedprimarily on the thing described by @var{input} (see below).@end tableBelow are names used for @var{value} and @var{input},along with their definitions.@table @code@item colA column number within a line (first column is number 1).@item fileAn encapsulation of a file's name.@item findLooks up an instance of some type that matches specified criteria,and returns that, even if it has to create a new instance orcrash trying to find it (as appropriate).@item initializeInitializes, usually a module. No type.@item intA generic integer of type @code{int}.@item isA generic integer that contains a true (non-zero) or false (zero) value.@item lenA generic integer that contains the length of something.@item lineA line number within a source file,or a global line number.@item lookupLooks up an instance of some type that matches specified criteria,and returns that, or returns nil.@item nameA @code{text} that points to a name of something.@item newMakes a new instance of the indicated type.Might return an existing one if appropriate---if so,similar to @code{find} without crashing.@item ptPointer to a particular character (line, column pairs)in the input file (source code being compiled).@item runPerforms some herculean task. No typ
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -