Author Topic: Create variable list by parsing a lisp file  (Read 6235 times)

0 Members and 1 Guest are viewing this topic.

hmspe

  • Bull Frog
  • Posts: 362
Create variable list by parsing a lisp file
« 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.
"Science is the belief in the ignorance of experts." - Richard Feynman

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Create variable list by parsing a lisp file
« Reply #1 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.
« Last Edit: June 30, 2015, 05:08:59 AM by roy_043 »

ronjonp

  • Needs a day job
  • Posts: 7526
Re: Create variable list by parsing a lisp file
« Reply #2 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...  :)
« Last Edit: June 30, 2015, 09:44:32 AM by ronjonp »

Windows 11 x64 - AutoCAD /C3D 2023

Custom Build PC

dgorsman

  • Water Moccasin
  • Posts: 2437
Re: Create variable list by parsing a lisp file
« Reply #3 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:
If you are going to fly by the seat of your pants, expect friction burns.

try {GreatPower;}
   catch (notResponsible)
      {NextTime(PlanAhead);}
   finally
      {MasterBasics;}

hmspe

  • Bull Frog
  • Posts: 362
Re: Create variable list by parsing a lisp file
« Reply #4 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.
"Science is the belief in the ignorance of experts." - Richard Feynman

dgorsman

  • Water Moccasin
  • Posts: 2437
Re: Create variable list by parsing a lisp file
« Reply #5 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.
If you are going to fly by the seat of your pants, expect friction burns.

try {GreatPower;}
   catch (notResponsible)
      {NextTime(PlanAhead);}
   finally
      {MasterBasics;}

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Create variable list by parsing a lisp file
« Reply #6 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))
« Last Edit: July 01, 2015, 06:58:33 AM by roy_043 »

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Create variable list by parsing a lisp file
« Reply #7 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.

ChrisCarlson

  • Guest
Re: Create variable list by parsing a lisp file
« Reply #8 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.

JohnK

  • Administrator
  • Seagull
  • Posts: 10605
Re: Create variable list by parsing a lisp file
« Reply #9 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).
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

hmspe

  • Bull Frog
  • Posts: 362
Re: Create variable list by parsing a lisp file
« Reply #10 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.
"Science is the belief in the ignorance of experts." - Richard Feynman

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Create variable list by parsing a lisp file
« Reply #11 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
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

AIberto

  • Guest
Re: Create variable list by parsing a lisp file
« Reply #12 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

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Create variable list by parsing a lisp file
« Reply #13 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.



kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Create variable list by parsing a lisp file
« Reply #14 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.