I worked out a way to do this given your example input and output. I make no promises that this is the cleanest or most efficient way to do it!
(Actually I'm kind of hoping someone else will come along and tear it apart so I can learn from it.)
Tested with SBCL on Linux.
>>>>>
(defparameter +input-list+
'(abc xyz ef-gh ef-xy cl-f-a cl-f-b cl-x-y cl-x-az def))
(defun tree-insert (tree path)
(cond ((null path) ; no more path to traverse
tree)
((find (car path) tree :test 'node-equal-p) ; have child node
(let* ((olditem (find (car path) tree :test 'node-equal-p))
(newitem (typecase olditem
(symbol (tree-insert (list olditem) (cdr path)))
(list (tree-insert olditem (cdr path))))))
(substitute newitem olditem tree)))
(t (tree-insert (append tree (list (car path))) ; no child node
path))))
(defun node-equal-p (symb node)
; node could be symbol, or list starting w/ symbol
(typecase node
(symbol (eq node symb))
(list (eq (car node) symb))))
(defun symbol-dash-list (symbol)
"Return 'parent' symbols of a symbol with dashes in its name, in order"
(let ((s (symbol-name symbol)))
(mapcar (lambda (pos) (intern (subseq s 0 pos)))
(loop for pos = (position #\- s)
then (position #\- s :start (1+ pos))
until (null pos)
collect (1+ pos) into ret
finally (return (nconc ret (list (length s))))))))
(defun expand-symbol-list (list)
(let ((tree nil))
(dolist (s list)
(setf tree (tree-insert tree (symbol-dash-list s))))
tree))
(expand-symbol-list +input-list+)
<<<<<
Output:
((ABC) (XYZ) (EF- (EF-GH) (EF-XY))
(CL- (CL-F- (CL-F-A) (CL-F-B)) (CL-X- (CL-X-Y) (CL-X-AZ))) (DEF))