TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: hmspe on June 29, 2015, 01:39:57 PM

Title: Create variable list by parsing a lisp file
Post by: hmspe on June 29, 2015, 01:39:57 PM
I've been toying with writing a routine that will parse the variable names in a .lsp file.  Since Bricscad does not have a GUI for writing lisp this is a manual process now.  I've tried LispLink and it more or less works for finding variable names, but I don't like it much as an editor.  The concept at this point is to write a routine that will read a .lsp file, parse it, then output a text file that lists each defun header, with the variables listed just below the associated header. 

Questions:
1.  Has someone already done this?  I've found a few routines online but they either require running the code to get a list of atoms, or they have restrictions on the variable names (ie., can't start with '#'), or they require manual pre-processing of the .lsp file.

2.  Is there anything in lisp that creates local variables other than a 'set' or a 'setq'?  Is the name after 'foreach' considered a local variable?



Any help or suggestions would be appreciated.
Title: Re: Create variable list by parsing a lisp file
Post by: roy_043 on June 30, 2015, 05:01:45 AM
Writing code for this will be quite a challenge:
Code: [Select]
(mapcar
  '(lambda (a)
    (set a 1)
  )
  '(varA varB varC)
)
Code: [Select]
(set (read "varD") 1)
Code: [Select]
(setq varE 1 varF 1)
Code: [Select]
(eval (read "(setq varG 1)"))
The foreach function has its own namespace. The variable name after foreach does not exist outside the foreach loop. The same applies to vlax-for.

I also use BricsCAD and write Lisp code. Making sure that variables are localized is a manual process for me as well. To make this easier I try to keep my functions short and limit the number of variables. Using fewer variables has the added advantage of making code run faster, generally speaking.

Notepad++, my editor of choice, will highlight all occurrences of a selected word. This makes it easier to find setq etc.
Title: Re: Create variable list by parsing a lisp file
Post by: ronjonp on June 30, 2015, 09:37:02 AM
Maybe something along these lines would help:
Code - Auto/Visual Lisp: [Select]
  1. ;; Get atoms
  2. (or *atoms* (setq *atoms* (atoms-family 1)))
  3. ;; Your code here
  4. (mapcar '(lambda (x) (set x 1)) '(vara varb varc v))
  5. ;; Look for items that did not exist in list '*atoms*'
  6. (setq atoms2 (vl-remove-if '(lambda (x) (vl-position x *atoms*)) (atoms-family 1)))
  7. ;; Localize
  8. (mapcar '(lambda (x) (set x nil)) (mapcar 'read atoms2))
  9. ;; Print results
  10. (print (strcat "( / " (apply 'strcat (mapcar '(lambda (x) (strcat x " ")) (vl-sort atoms2 '<))) ")"))
Quote
but they either require running the code to get a list of atoms
Or not...  :)
Title: Re: Create variable list by parsing a lisp file
Post by: dgorsman on June 30, 2015, 10:18:49 AM
Don't use Bricscad, but I allocate local variables manually during the design process.  There's a few I know I need at the start, and I add the other definitions as they are needed.  Arguments work the same way - most of the time I determine what they are before I write a single line of code.  Gotta keep it organized, and more code isn't going to do that like a good work process.   :police:
Title: Re: Create variable list by parsing a lisp file
Post by: hmspe on June 30, 2015, 12:39:19 PM
Thanks for the comments.  Agreed that this is not easy.  Maybe not worth the effort.  My concern is more for code that I download than for what I write.  There is a lot of code out there where there was little to no attempt made to localize variables.  In my office we sometimes see commands, both built-in and custom, start to be shown as 'unknown command' if we work in one file for several hours.  We use lisp routines extensively.  There seems to be a correlation between non-localized variables in lisp routines and how long we can work before we see the unknown command issue.  The correlation may be imaginary rather than real.  The programmers at Bricsys have not been able to duplicate the unknown command problem.
Title: Re: Create variable list by parsing a lisp file
Post by: dgorsman on June 30, 2015, 04:17:21 PM
Most internet code is more for example rather than use in a production environment, at least not without some massaging.  Part of my job is to ensure anything made live on the system is ready to go and error-free first, and if that requires a full re-write then that's what it gets.
Title: Re: Create variable list by parsing a lisp file
Post by: roy_043 on July 01, 2015, 06:55:17 AM
@ hmspe:
This code may help.

Test 1:
Does running AtomsClean every 15 minutes or so avoid the issue you have mentioned?

Test 2:
If the issue occurs does running AtomsClean solve the problem (unlikely...)?

Note:
AtomsClean will set all 'new' global variables that are symbols, but not *atoms_default*, to nil. Some applications rely on global symbols. So use with care.

Code - Auto/Visual Lisp: [Select]
  1. ; Load your Lisp files here...
  2.  
  3. (defun c:AtomsClean ( / lst)
  4.   (princ
  5.     (strcat
  6.       "\nNumber of extra atoms: "
  7.       (itoa
  8.         (-
  9.           (length (setq lst (vl-remove '*atoms_default* (atoms-family 0))))
  10.           (length *atoms_default*)
  11.         )
  12.       )
  13.     )
  14.   )
  15.   (mapcar
  16.     '(lambda (atm)
  17.       (if
  18.         (and
  19.           atm
  20.           (= 'sym (type atm))
  21.           (not (vl-position atm *atoms_default*))
  22.         )
  23.         (progn
  24.           (print (vl-princ-to-string atm))
  25.           (setq atm nil)
  26.         )
  27.       )
  28.     )
  29.     lst
  30.   )
  31.   (gc)
  32.   (princ)
  33. )
  34.  
  35. (setq *atoms_default* (atoms-family 0))
Title: Re: Create variable list by parsing a lisp file
Post by: roy_043 on July 01, 2015, 07:32:30 AM
@ hmspe:
If you have not already done so, take a look at lispex.dll.cfg in the BricsCAD program folder. The file contains a number of 'LISP virtual memory management settings'. Changing them may (or may not) help with your problem.
Title: Re: Create variable list by parsing a lisp file
Post by: ChrisCarlson on July 01, 2015, 08:17:59 AM
I know VLide within AutoCAD can create a list of variables used in a lisp routine. LISP is a decently old language so I'm pretty confident a standalone executable or even a more advanced editor should be able to parse or list the used variables.
Title: Re: Create variable list by parsing a lisp file
Post by: JohnK on July 01, 2015, 08:45:19 AM
Why don't you download a more powerful editor? Emacs is the undisputed champion for lisp programming and since Emacs is customize with lisp, I would imagine that if it doesn't already do what you want you can write an extension with very little problem(s).
Title: Re: Create variable list by parsing a lisp file
Post by: hmspe on July 01, 2015, 09:55:36 AM
@Roy:  Thanks.  I'll look at AtomsClean and lispex.dll.cfg.  This is a difficult problem to work on -- it generally takes several of hours before we start seeing problems, and we haven't been able to find a way to reproduce the symptoms reliably or to find a pattern on which operations seem to trigger the problems.  We load about 900K of lisp files when we run Bricscad.  VM_MAXIMUM_MEM may well be the key to making the symptoms go away. 

@Chris:  I still have a legacy copy of Autocad loaded and I do use the VLide on occasion.  I also have a copy of LispLink, which has a function to list local variables.  Most text editors that handle multiple programming languages don't have functions to list variables.

@Ron:  Thanks for your suggestion for looking at atoms.  It may well be the best approach. 

@John:  Thanks.  It has been a long time since I used Emacs.  I'll take a look.
Title: Re: Create variable list by parsing a lisp file
Post by: T.Willey on July 01, 2015, 10:33:35 AM
If you think it is certain lisps that are causing the issue, then maybe you could use a reactor in combination with the atoms-family.  Create a list of atoms-family when a drawing is opened, then use a reactor to check a newly created atoms-family list after the lisp runs, and compare the two.  Then you would be able to see if there are variables left global after a lisp is ran, and I think you can get the lisp's program name, but sure about the file it is loaded from.

Here is a link to an old discussion on the subject of tracking lisps with a reactor.  I do not seem to have the code handy on my computer, but on the first page I posted something (I did not check further to see if I posted any updates to the code).
http://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/lisp-usage-tracking/m-p/1383532
Title: Re: Create variable list by parsing a lisp file
Post by: AIberto on August 18, 2015, 10:40:22 PM
Maybe something along these lines would help:
Code - Auto/Visual Lisp: [Select]
  1. ;; Get atoms
  2. (or *atoms* (setq *atoms* (atoms-family 1)))
  3. ;; Your code here
  4. (mapcar '(lambda (x) (set x 1)) '(vara varb varc v))
  5. ;; Look for items that did not exist in list '*atoms*'
  6. (setq atoms2 (vl-remove-if '(lambda (x) (vl-position x *atoms*)) (atoms-family 1)))
  7. ;; Localize
  8. (mapcar '(lambda (x) (set x nil)) (mapcar 'read atoms2))
  9. ;; Print results
  10. (print (strcat "( / " (apply 'strcat (mapcar '(lambda (x) (strcat x " ")) (vl-sort atoms2 '<))) ")"))
Quote
but they either require running the code to get a list of atoms
Or not...  :)

Dear ronjonp
How test for this function ?
Code: [Select]
(defun test ( / fun1 fun2 s1 s2 d g)
(defun fun1 (p / a b c)
(setq a 10)
(setq b 20)
(setq c (+ a b))
(setq d (* p c))
d
);_end_defun_fun1
(defun fun2 (/ e f )
(fun1 3)
(setq e 2)
(setq f 10)
(setq g (* d (* e f)))
g
);_end_defun_fun2
(fun2)
(setq s1 20)
(setq s2 (* s1 g))
s2
);_end defun
Title: Re: Create variable list by parsing a lisp file
Post by: Kerry on August 19, 2015, 05:02:56 AM

I've tried several schemes for checking for stray global variables.

Using the ronjonp's code is the simplest.
... but as Roy identifies the code must be  run so that the variables and values are assigned.
This will NOT necessarily catch all variables that have potential to be global because the variable may live in a conditional branch that is not tested.



Title: Re: Create variable list by parsing a lisp file
Post by: roy_043 on August 19, 2015, 06:30:08 AM
How test for this function ?
Replace line 4 in ronjonp's code with:
Code: [Select]
(defun test ( / fun1 fun2 s1 s2 d g)
...
)
(test)
And load the code in a new drawing.
Title: Re: Create variable list by parsing a lisp file
Post by: AIberto on August 19, 2015, 07:10:11 AM
How test for this function ?
Replace line 4 in ronjonp's code with:
Code: [Select]
(defun test ( / fun1 fun2 s1 s2 d g)
...
)
(test)
And load the code in a new drawing.


Many Thanks roy

returns : "( / *ATOMS* TEST )"

This result is right?


Title: Re: Create variable list by parsing a lisp file
Post by: roy_043 on August 19, 2015, 07:27:22 AM
Yes. Your code has added a function definition.