I actually wrote a blog post on writing parsers:
http://formlis.wordpress.com/2010/07/07 ... t-regexps/.
This operation is non-trivial; there are three 3 states: Reading Text, Skipping Whitespace, and Handling Quotes. There are also three diferent character classes: Regular characters, Spaces, and Quotes. A State Machine is a matrix of functions, there will be one function per combination of state and character class. The string is processed one character at a time, the character class is determined by the input character, while the machine state is a variable that is changed throughout the computation.
This idea is embodied in the code I've provided. The only trick is that I've seperated the "Action to Run" from the "State to Transition To".
(defun char-class (char) (if (char-equal char #\Space) 0 (if (char-equal char #\") 1 2)))
(defconstant +white-mode+ 0)
(defconstant +read-mode+ 1)
(defconstant +quote-mode+ 2)
(defvar *collected*)
(defun skip (pos) (declare (ignore pos)))
(defun collect (pos) (declare (ignore pos)))
(defun startq (pos) (push (list (1+ pos) (1+ pos)) *collected*))
(defun startw (pos) (push (list pos pos) *collected*))
(defun finish (pos) (setf (second (car *collected*)) pos))
(defun reopen (pos)
(setf (second (car *collected*)) pos)
(push (list (1+ pos) (1+ pos)) *collected*))
(defvar *sm* (make-array 18 :initial-contents
;; SPACE QUOTE OTHER
(list #'skip +white-mode+ #'startq +quote-mode+ #'startw +read-mode+ ;; WHITEMODE
#'finish +white-mode+ #'reopen +quote-mode+ #'collect +read-mode+ ;; READMODE
#'collect +quote-mode+ #'finish +white-mode+ #'collect +quote-mode+)));; QUOTEMODE
(defun shlex-split (string)
(setf *collected* nil)
(loop for i upfrom 0
for c across string
with state = +white-mode+
do (let ((offset (+ (* state 6) (* 2 (char-class c)))))
(funcall (svref *sm* offset) i)
(setf state (svref *sm* (1+ offset))))
finally (unless (= state +white-mode+) (finish (length string))))
(mapcar #'(lambda (a) (apply #'subseq string a)) (nreverse *collected*)))
(shlex-split "independent single\"compound word\" alone selfish friendless \"buddy words\"")
;; Results: ("independent" "single" "compound word" "alone" "selfish" "friendless" "buddy words")
This may not be easily read, but the operation you have described is complex. My blog entry, and its link to the original paper of this technique in Forth, may help you understand how this parser works, as well as teach you an important programming technique.
Need an online wiki database? My Lisp startup
http://www.formlis.com combines a wiki with forms and reports.