Re: Crossreference, code documentation

*To*: mathgroup at christensen.cybernetics.net*Subject*: [mg1619] Re: Crossreference, code documentation*From*: wagner at bullwinkle.cs.Colorado.EDU (Dave Wagner)*Date*: Thu, 6 Jul 1995 23:12:59 -0400*Organization*: University of Colorado, Boulder

In article <3t5fb2$8i5 at news0.cybernetics.net>, <larso171 at maroon.tc.umn.edu> wrote: >Given that this simple exercise took me so much time, it seems wise to ask >around if there is a tool that does an even more complex job -- >providing a crossreference table of functions and the variables they use, >particularly global variables. I have developed a function for the book that I'm writing that I think might help you. This function finds all symbols in an expression without allowing anything to evaluate: In[1]:= SetAttributes[FindSymbols, HoldFirst] FindSymbols[expr_] := Switch[Head[Unevaluated[expr]], String | Integer | Real | Complex | Rational, {}, Symbol, {HoldForm[expr]}, _, Union[Flatten[ReleaseHold[ Map[FindSymbols, Apply[List, Hold[expr], {1}], {2}] ]], FindSymbols @@ HeldPart[Hold[expr], 1, 0] ] ] I'm not going to explain all the nuances of this function here (buy the book when it comes out! :-)) but the basic idea is: if what you're looking at is an atom or a symbol, you're done; otherwise, recursively descend into the expression by mapping FindSymbols onto all of the parts of the expression, and the head itself. The hard part is keeping things from evaluating while doing all of this. In the following example, all of the symbols have values, including those in the head of the expression. In[3]:= {a,b,c, f, g} = {1,2,3, func1, func2}; FindSymbols[f[a][b, g[c]]] Out[4]= {a, b, c, f, g} The returned value is a list of symbols wrapped in HoldForm. In[5]:= InputForm[%] Out[5]//InputForm= {HoldForm[a], HoldForm[b], HoldForm[c], HoldForm[f], HoldForm[g]} Now I started thinking about how you could apply this to your problem and this is what I came up with. First, let's define a function that uses a few of these symbols and has more than one rule. In[6]:= h[x_] := a + f[b] h[x_,y_] := g[c] In[8]:= DownValues[h] Out[8]= {Literal[h[x_]] :> a + f[b], Literal[h[x_, y_]] :> g[c]} We want to apply FindSymbols to the RHS of each of the above rules. Easy: In[9]:= Map[MapAt[FindSymbols, #, {2}]&, %] Out[9]= {Literal[h[x_]] :> FindSymbols[a + f[b]], Literal[h[x_, y_]] :> FindSymbols[g[c]]} Slightly trickier: extracting the FindSymbols expressions from the delayed rules, thus causing them to evaluate: In[10]:= % /. Literal[_ :> rhs_] -> rhs Out[10]= {{a, b, f, Plus}, {c, g}} In[11]:= Union[Flatten[%]] Out[11]= {a, b, c, f, g, Plus} As soon as you have found a list of all symbols upon which each one of your functions depends, you shouldn't have any problem inverting these lists to find all functions that depend on any particular symbol. "Left as an exercise for the reader." :-) >I'm aware of the Names["Global*`"] command, which will give me a list of >all globals. But I can't think of a simple way to find out which functions >use them or modify them. Be careful not to confuse what's in the Global context with the concept of "global variables". In Mathematica, even local symbol names are in the global context. For example (starting with a fresh kernel): In[1]:= Names["Global`*"] Out[1]= {} In[2]:= f[x_] := Module[{y=2x}, y+z] In[3]:= Names["Global`*"] Out[3]= {f, x, y, y$, z} Dave Wagner Principia Consulting (303) 786-8371 dbwagner at princon.com http://www.princon.com/princon