Warning: this is an htmlized version!
The original is here, and
the conversion rules are here.
/*
 * This file:
 *   http://anggtwu.net/lisptree/lisptree.mac.html
 *   http://anggtwu.net/lisptree/lisptree.mac
 *               (find-lisptree "lisptree.mac")
 *      See:  http://anggtwu.net/lisptree.html
 *       https://github.com/edrx/lisptree
 * Author: Eduardo Ochs <eduardoochs@gmail.com>
 * License: Public Domain.
 * Version: 20241104.
 *
 * Long story short:
 * LispTree Draw Maxima objects as trees (using Lisp).
 * This Maxima command
 *
 *   lisptree(f(2,g(3,4));
 *
 * prints this:
 *
 *   f__.   
 *   |  |   
 *   2  g__.
 *      |  |
 *      3  4
 *
 * Here is a longer explanation.
 * A "Maxima object" is something like f(2,g(3,4)).
 * A "Maxima tree"   is something like [f,2,[g,3,4]].
 * A "Lispy tree "   is something like ($F 2 ($G 3 4)).
 * A "2D tree"       is something like this,
 *
 *     f__.
 *     |  |
 *     2  g__.
 *        |  |
 *        3  4
 *
 * as a string with newlines.
 * The main functions in this file do these conversions:
 *
 *   lisptree:    Maxima object --> Maxima tree --> Lispy Tree --> 2D tree
 *   lisptreeq:   Maxima object --> Maxima tree --> Lispy Tree --> 2D tree
 *   lispytree:   Maxima object --> Maxima tree --> Lispy tree --> string
 *   lispytreeq:  Maxima object --> Maxima tree --> Lispy tree --> string
 *   lisptree0:   Maxima object --> Maxima tree
 *
 * The versions that end in "q" are macros that quote their arguments.
 * `lisptree0' is very configurable. See `lisptree0_config' below.
 *
 * (defun e () (interactive) (find-angg "luatree/lisptree.mac"))
 * (find-angg "MAXIMA/luatree3.mac")
 *
 * «.load-lisp»			(to "load-lisp")
 * «.format»			(to "format")
 * «.atoms»			(to "atoms")
 * «.atoms-test»		(to "atoms-test")
 * «.lisptree0»			(to "lisptree0")
 * «.lisptree0-tests»		(to "lisptree0-tests")
 * «.config»			(to "config")
 * «.config-tests»		(to "config-tests")
 * «.lisptree»			(to "lisptree")
 * «.lisptree-tests»		(to "lisptree-tests")
*/


/* «load-lisp»  (to ".load-lisp")
 * Outer part:  this file.
 * Middle part: (find-lisptree "lisptree-middle.lisp")
 * Inner part:  (find-lisptree "lisptree.lisp")
*/
lisptreedir : pathname_directory(load_pathname);
load(concat(lisptreedir, "lisptree.lisp"));
load(concat(lisptreedir, "lisptree-middle.lisp"));


/* «format»  (to ".format")
*/
format([args]) := apply(?format, append([false], args));
format0    (o) := format("~s",o); /* the Lisp representation of o, as a string */
stringp    (o) := ?stringp(o);         /* instead of an autoload to stringproc */


/* «atoms»  (to ".atoms")
 * See: (find-maximanode "Lisp and Maxima" "Lisp symbol" "?foo")
 *      (find-maximanode "Nouns and Verbs" "verb form" "$")
 *      (find-maximanode "Nouns and Verbs" "noun form" "%")
 *      (find-es "maxima" "low-level-nouns")
 *
 * Note: THIS IS BUGGY!
 * See the test below!
*/
lisptree0_string0(o) := o;                 /* send strings to Lisp unchanged */
lisptree0_string1(o) := format("~s", o); /* add double quotes to all strings */
lisptree0_number0(o) := o;                 /* send numbers to Lisp unchanged */
lisptree0_number1(o) := string(o);

verbp            (o) := symbolp(o) and (o = verbify(o));
nounp            (o) := symbolp(o) and (o = nounify(o));
specialnounp     (o) := nounp(o) and (string(o)#concat("",o));

lisptree0_symbol0(o) := o;                 /* send symbols to Lisp unchanged */
lisptree0_symbol1(o) := format0(o);   /* Low-level names: %FOO, $FOO and FOO */
lisptree0_symbol3(o) :=
  if nounp(o) then concat("'",string(o))  /* %DERIVATIVE -> 'diff            */
  else                        string(o);  /* $FOO        -> foo, FOO -> ?foo */
lisptree0_symbol4(o) :=
  if specialnounp(o) then concat("",o)    /* %DERIVATIVE -> derivative       */
  elseif nounp(o)    then concat("'",o)   /* %F          -> 'f               */
  else                    string(o);      /* $FOO        -> foo, FOO -> ?foo */

/* «atoms-test»  (to ".atoms-test")
* (eepitch-maxima)
* (eepitch-kill)
* (eepitch-maxima)
load("lisptree.mac");
_qfoo      : op('foo(42));
_qdiff     : op('diff(y,x));
mysymbols  : [?foo, foo, _qfoo, diff, _qdiff];
lsymbol(n) := parse_string(concat("lisptree0_symbol", n));
lsyline(n) := map(lsymbol(n),mysymbols);
lsylines   :  matrix(lsyline(0), lsyline(1), lsyline(3), lsyline(4));

propline(o) := [format0(o), verbp(o), nounp(o), specialnounp(o)];
topline     : rhs(fundef(propline));
otherlines  : map('propline, mysymbols);
proplines   : apply('matrix, append([topline],otherlines));

*/

/* «config»  (to ".config")
*/

lisptree0_config ([opts]) := makelist(lisptree0_config1(opt), opt, opts);
lisptree0_config1(opt)    :=
  if     opt = 'nq then lisptree0_string (o) := lisptree0_string0(o) /* no quotes */
  elseif opt = 'q  then lisptree0_string (o) := lisptree0_string1(o) /* use quotes */
  elseif opt = 'n0 then lisptree0_number (o) := lisptree0_number0(o)
  elseif opt = 'n1 then lisptree0_number (o) := lisptree0_number1(o)
  elseif opt = 's0 then lisptree0_symbol (o) := lisptree0_symbol0(o)
  elseif opt = 's1 then lisptree0_symbol (o) := lisptree0_symbol1(o)
  elseif opt = 's3 then lisptree0_symbol (o) := lisptree0_symbol3(o)
  elseif opt = 's4 then lisptree0_symbol (o) := lisptree0_symbol4(o)
  elseif opt = 'raw    then lisptree0_config('nq,'n0,'s0)
  elseif opt = 'lisp   then lisptree0_config( 'q,'n1,'s1)
  elseif opt = 'maxima then lisptree0_config('nq,'n1,'s4)
  elseif opt = 'Maxima then lisptree0_config( 'q,'n1,'s4)
  else error();

/* «config-tests»  (to ".config-tests")
* (eepitch-maxima)
* (eepitch-kill)
* (eepitch-maxima)
load("lisptree.mac");
lisptree0_config(nq,s0)$    lisptree0(f("foo", ?f));
lisptree0_config(q, s4)$    lisptree0(f("foo", ?f));

fundef(format);
lisptree0_config('raw)$     lisptree(fundef(format));
lisptree0_config('lisp)$    lisptree(fundef(format));
lisptree0_config('maxima)$  lisptree(fundef(format));
lisptree0_config('Maxima)$  lisptree(fundef(format));

*/


/* «lisptree0»  (to ".lisptree0")
*/
lisptree0_string (o) := lisptree0_string0(o);  /* Default: don't add double quotes */
lisptree0_number (o) := lisptree0_string1(o);  /* Default: convert to string */
lisptree0_symbol (o) := lisptree0_symbol3(o);  /* Default: "'diff" */
lisptree0_apatom (o) := append([       lisptree0(op(o))], map(lisptree0, args(o)));
lisptree0_apother(o) := append(["ap",  lisptree0(op(o))], map(lisptree0, args(o)));
lisptree0_subvarp(o) := append(["[_]", lisptree0(op(o))], map(lisptree0, args(o)));

lisptree0(o) :=
  if     stringp(o)  then lisptree0_string (o)
  elseif symbolp(o)  then lisptree0_symbol (o)
  elseif numberp(o)  then lisptree0_number (o)
  elseif subvarp(o)  then lisptree0_subvarp(o)
  elseif atom(op(o)) then lisptree0_apatom (o)
  else                    lisptree0_apother(o);

/* «lisptree0-tests»  (to ".lisptree0-tests")
* (eepitch-maxima)
* (eepitch-kill)
* (eepitch-maxima)
load("lisptree.mac");
lisptree0(f(a,g(b,c)));

*/



/* «lisptree»  (to ".lisptree")
 * See: (find-lisptree "lisptree-middle.lisp")
 * These are the high-level words.
*/
lispytree (o)  := tolispytreestr(lisptree0(o));
lispytreeq(o) ::= block([simp:false], tolispytreestr(lisptree0(o)));

lisptree_ (o)  := tolisptree2d_(lisptree0(o));
lisptree  (o)  := tolisptree2d (lisptree0(o));
lisptreeq (o) ::= block([simp:false], tolisptree2d(lisptree0(o)));

/* «lisptree-tests»  (to ".lisptree-tests")
* (eepitch-maxima)
* (eepitch-kill)
* (eepitch-maxima)
load("lisptree.mac");
lisptree0_config(nq,s0,n0)$  lisptreeq(a+2+3);
lisptree0_config(q, s3,n0)$  lisptreeq(a+2+3);
lisptree0_config(nq,s0,n0)$  lispytreeq(a+2+3);
lisptree0_config(q, s3,n0)$

lisptree (a+2+3);
lisptreeq(a+2+3);
lisptreeq(a[b][c][d]);
lisptreeq(a(b)(c)(d));
lisptree0_config(q, s0)$  lisptreeq('diff(x^2,x));  "%DERIVATIVE"$
lisptree0_config(nq,s4)$  lisptreeq('diff(x^2,x));  "derivative"$
lisptree0_config(nq,s3)$  lisptreeq('diff(x^2,x));  "'diff"$
lisptree0_config(q, s3)$  lisptreeq('diff(x^2,x));  "'diff"$

*/