From: fft1976 Date: 2009-08-02T14:30:09+09:00 Subject: RUBY vs COMMON LISP On Aug 1, 8:55 pm, p...@informatimago.com (Pascal J. Bourguignon) wrote: > w_a_x_man writes: > > On Aug 1, 9:32 am, Bata wrote: > >> Use (cl-ppcre:split " " string-name) to get a list of the different > >> words in the string. > > >> Check out the cl-ppcre package's functionality, its quite amazing. > > > Ruby: > > > string_name.split > > Don't you realize how ugly Ruby syntax is? > > Here is in 150 lines of lisp, a simplified lisp reader that is able to > read all the lisp syntax needed to write it. > > Try to parse Ruby syntax in Ruby and see how useless a language it is. I much prefer CL to Ruby, but this argument is useless. How many lines of code do you need to read Brainfuck in Brainfuck? (If you wanted to show the inferiority of Ruby to Common Lisp, the shootout makes a much more compelling argument) > > -----(simple-reader.lisp)------------------------------------------------------ > ;;;; -*- mode:lisp;coding:utf-8 -*- > ;;;;************************************************************************** > ;;;;FILE:               simple-reader.lisp > ;;;;LANGUAGE:           Common-Lisp > ;;;;SYSTEM:             Common-Lisp > ;;;;USER-INTERFACE:     NONE > ;;;;DESCRIPTION > ;;;;     > ;;;;    Simple Lisp Reader. > ;;;;    This reader implements a subset of the Common Lisp reader, > ;;;;    but it should be extensible enough to be able to read most > ;;;;    of Common Lisp syntax. > ;;;;    Not supported: the preserving whitespace flag, the recursive flag > ;;;;    (therefore no references), character traits (escapes). > ;;;;    Otherwise, reader macros and dispatching  macros can be written > ;;;;    to read most of CL syntax. > ;;;;    Only integers, keywords and symbol tokens are parsed (a more > ;;;;    sophisticated parse-token function can be configured). > ;;;;     > ;;;;AUTHORS > ;;;;     Pascal J. Bourguignon > ;;;;MODIFICATIONS > ;;;;    2009-08-02 Created. > ;;;;BUGS > ;;;;LEGAL > ;;;;    GPL > ;;;;     > ;;;;    Copyright Pascal J. Bourguignon 2009 - 2009 > ;;;;     > ;;;;    This program is free software; you can redistribute it and/or > ;;;;    modify it under the terms of the GNU General Public License > ;;;;    as published by the Free Software Foundation; either version > ;;;;    2 of the License, or (at your option) any later version. > ;;;;     > ;;;;    This program is distributed in the hope that it will be > ;;;;    useful, but WITHOUT ANY WARRANTY; without even the implied > ;;;;    warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR > ;;;;    PURPOSE.  See the GNU General Public License for more details. > ;;;;     > ;;;;    You should have received a copy of the GNU General Public > ;;;;    License along with this program; if not, write to the Free > ;;;;    Software Foundation, Inc., 59 Temple Place, Suite 330, > ;;;;    Boston, MA 02111-1307 USA > ;;;;************************************************************************** > > (defstruct character-description >   non-terminating-p >   reader-macro >   dispatching-macro-characters) > > (defstruct (simple-readtable (:constructor %make-simple-readtable)) >   (default-character-description (make-character-description)) >   (macro-characters (make-hash-table)) >   (parse-token (function identity)) >   (whitespaces  #(#\space #\tab #\newline #\linefeed #\return #\page #\vt))) > > (defun simple-get-macro-character (character &optional (readtable *simple-readtable*)) >   (let ((description (or (gethash character (simple-readtable-macro-characters readtable)) >                          (simple-readtable-default-character-description readtable)))) >     (values (character-description-reader-macro description) >             (character-description-non-terminating-p description)))) > > (defun simple-set-macro-character (character function &optional non-terminating-p >                                    (readtable *simple-readtable*)) >   (setf (gethash character (simple-readtable-macro-characters readtable)) >         (make-character-description :non-terminating-p non-terminating-p >                                     :reader-macro function)) >   't) > > (defun simple-get-dispatch-macro-character (character subchar >                                             &optional (readtable *simple-readtable*)) >   (setf subchar (char-upcase subchar)) >   (let ((description (gethash character (simple-readtable-macro-characters readtable)))) >     (unless (and description >                  (character-description-dispatching-macro-characters description)) >       (error "#\\~C is not a dispatching macro character" character)) >     (gethash subchar (character-description-dispatching-macro-characters description)))) > > (defun simple-set-dispatch-macro-character (character subchar function >                                             &optional (readtable *simple-readtable*)) >   (setf subchar (char-upcase subchar)) >   (let ((description (gethash character (simple-readtable-macro-characters readtable)))) >     (when (or (null description) >               (null (character-description-dispatching-macro-characters description))) >       (setf (gethash character (simple-readtable-macro-characters readtable)) >             (make-character-description :non-terminating-p t >                                         :reader-macro (function simple-reader-dispatching-macro) >                                         :dispatching-macro-characters (make-hash-table))))) >   (let ((description (gethash character (simple-readtable-macro-characters readtable)))) >     (setf (gethash subchar  (character-description-dispatching-macro-characters description)) >           function)) >   't) > > (defun simple-reader-dispatching-macro (character stream) >   (let* ((subchar  (read-char stream)) >          (macro    (simple-get-dispatch-macro-character character subchar))) >     (assert macro () "~C~C is not a dispatching macro" character subchar) >     (funcall macro character subchar stream))) > > (defun simple-read-vector-dmacro (char subchar stream) >   (declare (ignore char)) >   (let ((contents (simple-read-list-macro subchar stream))) >     (coerce contents 'vector))) > > (defvar *character-names* (list (cons "SPACE"    (code-char 32)) >                                 (cons "NEWLINE"  (code-char 10)) >                                 (cons "RETURN"   (code-char 13)) >                                 (cons "PAGE"     (code-char 12)) >                                 (cons "VT"       (code-char 11)) >                                 (cons "LINEFEED" (code-char 10)) >                                 (cons "TAB"      (code-char 9))) >   "An a-list mapping character names to characters.") > > (defun simple-read-character-dmacro (char subchar stream) >   (declare (ignore char subchar)) >   (let ((object (read-char stream))) >     (if (alpha-char-p (peek-char nil stream nil #\space)) >         (loop >            :with buffer = (make-array 8 :element-type 'character :adjustable t :fill-pointer 1 >                                       :initial-element object) >            :do (vector-push-extend (read-char stream) buffer) >            :while (alpha-char-p (peek-char nil stream nil #\space)) >            :finally (return (or (cdr (assoc (string-upcase buffer) *character-names* >                                             :test (function string=))) >                                 (aref buffer 0)))) >         object))) > > (defun simple-parse-token (buffer) >   ;; We only deal with integers, keywords and symbols. >   (or (ignore-errors (parse-integer buffer :junk-allowed nil)) >       (if (char= #\: (aref buffer 0)) >           (intern (string-upcase (subseq buffer (position #\: buffer :test (function char/=)))) >                   "KEYWORD") >           ;; We don't deal with other packages in this simple parse-token. >           (intern (string-upcase buffer))))) > > (defun simple-read-quote-macro (character stream) >   (declare (ignore character)) >   (list 'quote (simple-read stream))) > > (defun simple-read-list-macro (character stream) >   (declare (ignore character)) >   (loop >      :until (char= #\) (peek-char t stream)) >      :collect (simple-read stream) >      :finally (read-char stream))) > > (defun simple-read-string-macro (character stream) >   (handler-case >       (loop >          :with buffer = (make-array 8 :element-type 'character :adjustable t :fill-pointer 0) >          :for ch = (read-char stream) >          :until (char= character ch) >          :do (vector-push-extend (if (char= #\\ ch) >                                      (read-char stream) >                                      ch) >                                  buffer) >          :finally (return (copy-seq buffer))))) > > (defun simple-read-comment-macro (character stream) >   (declare (ignore character)) >   (read-line stream) >   (values)) > > (defun make-simple-readtable () >   (let ((readtable >          (%make-simple-readtable >           :default-character-description (make-character-description :non-terminating-p t) >           :parse-token (function simple-parse-token)))) >     (simple-set-macro-character #\( (function simple-read-list-macro)     nil readtable) >     (simple-set-macro-character #\) nil                                   nil readtable) >     (simple-set-macro-character #\' (function simple-read-quote-macro)    nil readtable) >     (simple-set-macro-character #\" (function simple-read-string-macro)   nil readtable) >     (simple-set-macro-character #\; (function simple-read-comment-macro)  nil readtable) >     (simple-set-dispatch-macro-character #\# #\\ (function simple-read-character-dmacro) readtable) >     (simple-set-dispatch-macro-character #\# #\( (function simple-read-vector-dmacro)    readtable) >     readtable)) > > (defparameter *simple-readtable* (make-simple-readtable)) > > (defun simple-read (&optional (stream *standard-input*) (eof-error-p t) eof-value) >   (peek-char t stream nil) >   (let ((char (read-char stream nil nil))) >     (cond >       (char >        (multiple-value-bind (macro non-terminating-p) (simple-get-macro-character char) >          (if macro >              (let ((object (multiple-value-list (funcall macro char stream)))) >                (if object (first object) (simple-read stream eof-error-p eof-value)))         >              (loop >                 :with buffer = (make-array 8 :element-type 'character :adjustable t :fill-pointer 0) >                 :for ch = (peek-char nil stream nil #\space) >                 :initially (vector-push-extend char buffer) >                 :until (or (position ch (simple-readtable-whitespaces *simple-readtable*)) >                            (not (nth-value 1 (simple-get-macro-character ch)))) >                 :do (vector-push-extend (read-char stream eof-error-p eof-value) buffer) >                 :finally (return (funcall (simple-readtable-parse-token *simple-readtable*) >                                           buffer)))))) >       (eof-error-p (error 'end-of-file :stream stream)) >       (t eof-value)))) > > -------------------------------------------------------------------------------- > > (with-open-file (input "simple-reader.lisp") >   (loop >      :for sexp = (simple-read input nil input) >      :until (eq sexp input) >      :do (pprint sexp) (terpri))) > > -- > __Pascal Bourguignon__