4

Parsing Lisp in <50 LOC

Submitted by 365degrees in lisp (edited )

Alright, code is data and other cool crap, but you only get strings as input and you need S-expressions. No big deal, here's a parser I made for practise. Consider it licensed under the public domain cause it's incredibly simple and there's roughly one way to parse Lisp. (JS-based syntax highlighting breaks on #\Characters.)

(defun read-list (stream)
  (if (char= (peek-char t stream) #\))
      (progn
        (read-char stream) 
        nil)
      (cons (read-sexp stream)
            (read-list stream))))

(defun read-atom (stream &optional (collected nil))
  (let ((char (peek-char (null collected) stream nil :eof)))
    (cond
      ((eql char :eof)
       (intern
        (string-upcase
         (coerce (nreverse collected) 'string))))
      ((member char
               '(#\Space #\Newline #\Tab #\( #\))
               :test #'char=)
       (intern
        (string-upcase
         (coerce (nreverse collected) 'string))))
      (t
       (read-atom stream
                  (cons (read-char stream)
                        collected))))))

(defun read-string (stream &optional (collected nil))
  (let ((char (read-char stream)))
    (if (char= char #\")
        (coerce (nreverse collected) 'string)
        (read-string stream
                     (cons char collected)))))

(defun read-sexp (stream)
  (let ((char (read-char stream)))
    (case char
      (#\(
       (read-list stream))
      (#\"
       (read-string stream (list char)))
      (otherwise
       (read-atom stream (list char))))))
   
(defun read-from-string* (string)
  (with-input-from-string (stream string)
(read-sexp stream)))

I've tried everything I can think of to break it, but it seems rigid enough.

Comments

You must log in or register to comment.