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