Re: Crossreference, code documentation
- To: mathgroup at christensen.cybernetics.net
- Subject: [mg1621] Re: Crossreference, code documentation
- From: <larso171 at maroon.tc.umn.edu>
- Date: Thu, 6 Jul 1995 23:33:01 -0400
- Organization: University of Minnesota, Twin Cities
Hi all,
I wrote looking for a documentation and maintenance package.
Here is a solution to two of my major problems (since I asked such long
questions, maybe I'm adding insult to injury by providing long answers,
rather than being helpful. But I think code documentation and maintenance
tools will be very helpful to a lot of people. I post this also to save
anyone who is inclined to spend the time to respond with solutions to my
original messages -- I'm content that I've solved 3 of my 4 problems).
I haven't gotten any responses yet except one suggesting developing in C++
or Common Lisp instead, so I thought I'd go ahead and develop the three
tools I needed immediately.
One of my needs is something that takes a source code .m file,
and, given a table of "old variable name, new variable name" produces a new
source code .m file with these variable name replacements. I believe I've
found a good answer to this problem. The main secret is to
create a list, called specCharsL, of all special characters, i.e. all
characters that are non-alphanumeric and not $. The significance of
these special characters is that they cannot be part of a variable or
function name.
Then I use the specCharsL as a TokenWords, when I ReadList my source code
file into programAr:
programAr = ReadList[filename,Word,rsn,TokenWords -> specCharsL];
^- recordSeparators -> {}
programAr is the source code from filename, but parsed into a list of
elements. Some elements of the list are alphanumeric strings (strings
containing letters, digits, and $ only), and other elements being special
characters only. The alphanumeric strings are generally whole variable
names or function names. (They might also be regular words in comments,
but that doesn't bother me).
The other major step, is that given a list of old variable name -> new
variable name replacement rules, I then use ReplaceAll (the /. operator)
to replace all instances of old variable names with their corresponding
new variable names:
newProgramAr = programAr /. oldNewReplacementRuleL;
The complete program is below (it works, but I'm still developing related
tools, so things are still open and global):
rsn = ( RecordSeparators -> {} )
specialCharsGL = Map[FromCharacterCode, Join[ Range[0,35], Range[37,47],
Range[58,64], Range[91,96], Range[123,127] ] ];
oldNewVarbsGL = { { "crL", "chromeL" }, {"grL", "grandTotL"},
{"ebPL", "ebGPL"}, { "nebPL", "nebXYZ" } };
(*##### FAR f### findAndReplace #######*)
findAndReplace[fname_,oldNewL_,specCharsL_] := Module[{},
(* programAr is a list whose elements consist of either
names or special characters *)
programAr = ReadList[fname,Word,rsn,TokenWords -> specCharsL];
(* oldNewReplacementRuleL is the oldnewL matrix
converted to a list of replacement rules *)
oldNewReplacementRuleL = Map[ ( # /. {a_,b_} -> a -> b )&, oldNewL ];
newProgramAr = programAr /. oldNewReplacementRuleL;
newProgramCodeStr = StringJoin @@ newProgramAr;
Print["Result is in newProgramCodeStr. Here are first 1000 characters:"];
Print[]; Print[StringTake[newProgramCodeStr,1000]];
ans = Input["Do you want to save to output file \"out\"? (y/n): "];
If[ ToUpperCase[ToString[ans]] == "Y",
WriteString["out", newProgramCodeStr]; Close["out"] ]; (* If *)
] (* end findAndReplace *)
I've also made sure that the above does not have a substring replacement
problem. That is, given replacement rules such as:
{ "len" -> "strLength", "maxlen" -> "maxVectorLength" }
I don't have to worry about the "len" in "maxlen" being replaced by
"strLength" to yield the horribly wrong maxstrLength. With the way the
file is parsed in programAr, and the way that the /. operator works, only
complete strings are replaced by complete strings.
I believe that another need of mine, finding variable names that don't
match an "approved" list of variable names, is easily obtained by using
MemberQ, i.e. along the lines of
For[i = 1, i<= Length[programAr], i++,
If[ !MemberQ[programAr[[i]],approvedL],
AppendTo[unmatchedNameL, programAr] ] ]
It will be pretty inefficient, in that most of the elements in programAr
are single special characters like "[" which needn't be checked against
the approvedL. (I use the suffix "L" to mean a list). I might weed those
out first.
I'd also probably run my "comment stripper" program on the file
first before producing programAr and running the above program. So as not
to compare every lousy word in a comment against the approved list, and
adding it to the unmatchedNameL in the usual case that there isn't a match.
The third tool I needed was the comment stripper program, which removes
all comments from a .m file. I have that working well. But its so long,
ugly, inelegant, and would take a lot of documentation to explain that I
wouldn't think of posting it. But anyone interested in complete working
versions of these tools can email me -- though I might take a week or two
to clean things up first.
The only major item remaining in my wish list is a program to build the
function variable cross reference table:
function variable global global
name name local? used? modified?
========= ======== ====== ======= ==========
func1 xabcF1 Y N N
func1 xdefF1G N Y N
func2 x123F2 Y N N
This one looks tough.
Jim Larson