[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Computed goto's
Date: Mon, 30 Mar 87 19:43 EST
From: Barry Margolin <barmar@Think.COM>
I don't think an array of compiled function objects should be
significantly more expensive than what you want, though. The only added
expense I can think of is that you have to push a stack frame to
transfer and you have to indirect through the lexical environment to
reference variables that would have been local.
And if one of the lexical references is a go tag itself, many
implementations will arrange to do a THROW to someplace in containing
tagbody which will just invoke another computed-go...
I think it would be pretty easy to write a macro that does this. In
fact, I think this does a simple subcase:
(defmacro on-goto (key &body clauses) ;remember BASIC?
(let ((array (map '(array function)
#'(lambda (clause)
(compile nil `(lambda () . ,clause)))
clauses)))
`(funcall (aref ,array ,key))))
Well, it's not as easy as I thought -- the above macro doesn't do the
right thing with lexical variables in the clauses. But I'm pretty sure
it could be done....
It's not a good idea to go off and call the compiler at macro expansion
time. I'm not sure the above could work in the interpreter if you were
able to fix the lexical reference bug. What about a computed-goto out
of range, which I think means fall-through? DLA was right: CASE on
integers and hope the compiler will notice all the bodies are GO
statements and do the right thing.
(defmacro on-goto (key &rest wheres)
`(case ,key
,@(do ((index 1 (1+ index)) ; fortrash 1 based?
(wheres wheres (cdr wheres))
(clauses '() (cons `(,index (go ,(car wheres))) clauses)))
((null wheres) (reverse clauses)))))
(on-goto foobar here there anywhere)
=> (CASE FOOBAR
(1 (GO HERE))
(2 (GO THERE))
(3 (GO ANYWHERE)))