[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)))