Why don't people like lisp?
Peter Seibel
peter at javamonkey.com
Wed Oct 22 04:05:39 EDT 2003
"Andrew Dalke" <adalke at mindspring.com> writes:
> Peter Seibel:
> > Okay, here's a Common Lisp version. Because Lisp functions take either
> > keyword or positional arguments, I choose to make the generated
> > functions use keyword arguments. But the variables are gathered in the
> > right order, so take out the '&key' below to use positional arguments:
>
> Cool code. I like that it identifies some of the error locations.
>
> > * (funcall (compile-rpn "a b +") :a "foo" :b 2)
> > Error: `"foo"' is not of the expected type `NUMBER'
>
> My Python code reports a line number for this.
Right. Well that's one disadvantage, such as it is, of having the
compiler built in--I'm at the mercy of its error reporting and Lisp
isn't big on line-numbers, perhaps because many definitions don't come
from a file. What I didn't show in the output was that I was actually
dropped into the debugger at that point so had all the capabilities
that it provided to figure out what was going wrong. Anyway, that's
the price I pay for getting machine code I guess. I could, if it was
really important wrap all the function calls in condition handling
code that reported the line number but it didn't seem worth it.
> In my reply to Erann Gat I noted that his eval approach might
> exclude the possibility of using names like 'a)' as identifiers. (I
> don't know if it does, because I don't know enough Lisp.)
>
> My AST solution could easily be changed to support that case, as
> well as variable like ";;b" and "#c" and ":d:".
>
> I'll ask the same of you. Does your code require that the RPN names
> also be valid Lisp tokens? If so, what happens if it isn't?
Sure. I just used the built in Lisp reader because the syntax you
specified was compatibile. But if I wanted to allow names including
special characters I could either tweak the readtable so the Lisp
reader didn't treat them as special or I could do something like this.
Notice that the actual change to the parse function is to one function
call, replacing a call to the built-in READ-FROM-STRING with my own
next-token function. The rest of the patch is my own simple tokenizer.
(And I had to redefine variablep to allow weird variable names.) The
tokenizer could probably be written better but it's late here and I
should be in bed.
==== //depot/lisp-book/code/rpn.cl#1 - /home/peter/localperforce/lisp-book/code/rpn.cl ====
@@ -10,7 +10,7 @@
(defun parse (input)
(let (stack variables (idx 0))
(loop
- (multiple-value-bind (tok next-idx) (read-from-string input nil nil :start idx)
+ (multiple-value-bind (tok next-idx) (next-token input :start idx)
(labels
((line-number () (1+ (count #\Newline input :end idx)))
(pop-arg ()
@@ -25,8 +25,35 @@
(t (error "Invalid token ~a at position ~d (line ~d)." tok idx (line-number))))
(setq idx next-idx))))))
-(defun variablep (sym)
- (and (symbolp sym) (every #'alpha-char-p (string sym))))
+
+
+(defun next-token (input &key (start 0))
+ (multiple-value-bind (str end) (next-string input :start start)
+ (when str
+ (values
+ (if (digit-char-p (char str 0))
+ (read-from-string str nil nil)
+ (intern (string-upcase str)))
+ end))))
+
+(defun next-string (input &key (start 0))
+ (let ((real-start (skip-white-space input :start start)))
+ (loop for idx from real-start below (length input)
+ while (not (white-space-p (char input idx)))
+ finally (return
+ (values
+ (if (= real-start idx) nil (subseq input real-start idx))
+ (skip-white-space input :start idx))))))
+
+(defun skip-white-space (input &key (start 0))
+ (loop for idx from start below (length input)
+ while (white-space-p (char input idx))
+ finally (return idx)))
+
+(defun white-space-p (char)
+ (member char '(#\Space #\Newline #\Tab)))
+
+(defun variablep (sym) (symbolp sym))
> (Looking at it, the key line is
> > ((not tok) (return `(lambda (&key ,@(nreverse
> variables)) (prog1 , at stack))))
>
> but I don't know what @() does nor what happens if a "strange"
> value is used as the list of keywords)
Actually the key line is the one I patched above. This is just
generating the form which Lisp knows how to compile. But since Lisp
symbols can actually contain any character, as long as they're
properly escaped I have no real problems.
>
> > And for grins here's the x86 machine code generated for the first
> function:
>
> I was never any good at Intel assembly, and I thankfully haven't
> touched it in about 15 years. I was trying to figure out if it
> optimized the additions into 15**a, but I could see neither the
> sequence 1, 2, 3, 4, 5 nor the value 15 (octal 17, hex F) anywhere
> in the code. Pointers?
Well, I know less about it than you. I just threw that in to point out
that my 24-line compiler generates machine code.
-Peter
--
Peter Seibel peter at javamonkey.com
Lisp is the red pill. -- John Fraser, comp.lang.lisp
More information about the Python-list
mailing list