;;; -*-Mode:LISP; Base:8; Package:USER -*- (SPECIAL READTABLE STANDARD-INPUT READ-COMPARE-OBJECT READ-COMPARE-STOP READ-COMPARE-STRING) ;This is like READ-COMPARE, but eats the terminating space after an atom. (DEFUN READ-COMPARE-FOR-TOP-LEVEL (OBJECT PLACE-TO-STOP &AUX CH) (PROG1 (READ-COMPARE OBJECT STANDARD-INPUT) (AND (MEMQ ':LISTEN (FUNCALL STANDARD-INPUT ':WHICH-OPERATIONS)) (SETQ CH (FUNCALL STANDARD-INPUT ':LISTEN)) (OR (>= CH (RDTBL-ARRAY-SIZE)) (NOT (ZEROP (LOGAND 1 (RDTBL-BITS READTABLE CH))))) (FUNCALL STANDARD-INPUT ':TYI)))) ;Eat the space or other useless character ;READ-COMPARE reads from a stream comparing against a supplied object. ;When we reach the place in the object specified by READ-COMPARE-STOP ;(which should be a CONS, since a symbol can occur in many places) ;READ-COMPARE returns, leaving the input stream positioned to the text ;for that object. ;READ-COMPARE's value is NIL if the text and object do not match, ;T if they do but the place to stop was not encountered, ;or STOP if READ-COMPARE is returning having reached the stopping place. (DEFUN READ-COMPARE (OBJECT READ-COMPARE-STOP &OPTIONAL (STREAM STANDARD-INPUT)) (OR (BOUNDP 'READ-COMPARE-STRING) (SETQ READ-COMPARE-STRING (MAKE-ARRAY 100 ':TYPE ART-STRING ':LEADER-LENGTH 1))) (CATCH (READ-COMPARE-INTERNAL OBJECT STREAM) READ-COMPARE)) ;Read compare one object, processing nonsplicing macros, ;and handling splicing macros only if they don't match anything (like ;). (DEFUN READ-COMPARE-INTERNAL (OBJECT STREAM) (PROG (THING TYPE SPLICEP) A (MULTIPLE-VALUE (THING TYPE) (READ-COMPARE-THING OBJECT STREAM)) (COND ((EQ TYPE 'READER-MACRO) (MULTIPLE-VALUE (THING TYPE SPLICEP) (FUNCALL THING OBJECT NIL STREAM)) (AND SPLICEP (GO A)) (RETURN T)) ((EQ TYPE 'SPECIAL-TOKEN) (FERROR NIL "The special token ~S was read in where not expected" THING)) (T (RETURN T))))) ;READ-COMPARE-THING is analogous to XR-READ-THING. ;It is passed an object to compare and a stream to read from. ;The readtable finite state machine is used to gobble a string from the stream ;(using READ-COMPARE-STRING, which is reused each time). ;The final state of the FSM determines what function to call to ;compare the string (and perhaps more text which follows) with the object; ;except that some things are SPECIAL-TOKENs which just return ;the two values and SPECIAL-TOKEN to the caller. ;In that case, nothing has been matched, and the caller must take special action. ;Sometimes we detect a read macro. In that case, we return ;the function to call and READ-MACRO. Normally, we (that is, the ;comparison function) return T for succesful match, or throw to READ-COMPARE. ;When a read macro is processed by our caller, it should be passed these ;arguments: first, an object to match, if the macro is nonsplicing. ;Second, the list of the remaining objects to match, in case the ;macro is splicing. Third, the stream. ;The macro handler returns two values. The second is whether it was ;splicing. The first, in the case that it was splicing, ;is the list of things not matched (a tail of the original second argument). ;If the macro doesn't match, it throws, so there is no need to worry about that. ;Splicing macros, and nonsplicing ones which "do consing", ;must watch for READ-COMPARE-STOP and throw if it is encountered. (DEFUN READ-COMPARE-THING (READ-COMPARE-OBJECT STREAM) (PROG (CH NUM A B (STRING READ-COMPARE-STRING) REAL-CH (READTABLE-FSM (RDTBL-FSM READTABLE)) (FNPROP (GET (CONS NIL (RDTBL-PLIST READTABLE)) 'READ-COMPARE-FUNCTION-PROPERTY)) (STATE (RDTBL-STARTING-STATE READTABLE))) (MULTIPLE-VALUE (CH NUM REAL-CH) (XR-XRTYI-WHITE-OUT STREAM)) (SETQ STATE (AR-2 READTABLE-FSM STATE NUM)) (SETF (ARRAY-LEADER STRING 0) 0) (COND ((NOT (NUMBERP STATE)) (LET ((FLAG (CAR STATE)) (TODO (CDR STATE))) (SELECTQ FLAG (NO-UNTYI-QUOTE (RETURN TODO 'SPECIAL-TOKEN)) (LAST-CHAR (MULTIPLE-VALUE (A B) (FUNCALL (GET TODO FNPROP) STREAM NIL REAL-CH)) (RETURN A B)) (NO-UNTYI-FUNCTION (ARRAY-PUSH STRING CH) (MULTIPLE-VALUE (A B) (FUNCALL (GET TODO FNPROP) STREAM STRING)) (RETURN A B)) ((UNTYI-QUOTE UNTYI-FUNCTION) (FERROR NIL "Reader in infinite loop reading character: /"~C/"" REAL-CH)) (OTHERWISE (FERROR NIL "The reader found ~S in the finite state machine" FLAG)))))) L (ARRAY-PUSH-EXTEND STRING CH) (MULTIPLE-VALUE (CH NUM REAL-CH) (XR-XRTYI STREAM)) (SETQ STATE (AR-2 READTABLE-FSM STATE NUM)) (COND ((NUMBERP STATE) (GO L))) (LET ((FLAG (CAR STATE)) (TODO (CDR STATE))) (SELECTQ FLAG (UNTYI-FUNCTION (XR-XRUNTYI STREAM REAL-CH NUM) (MULTIPLE-VALUE (A B) (FUNCALL (GET TODO FNPROP) STREAM STRING)) (RETURN A B)) (LAST-CHAR (MULTIPLE-VALUE (A B) (FUNCALL (GET TODO FNPROP) STREAM STRING REAL-CH)) (RETURN A B)) (NO-UNTYI-FUNCTION (ARRAY-PUSH-EXTEND STRING CH) (MULTIPLE-VALUE (A B) (FUNCALL (GET TODO FNPROP) STREAM STRING)) (RETURN A B)) (UNTYI-QUOTE (XR-XRUNTYI STREAM REAL-CH NUM) (RETURN TODO 'SPECIAL-TOKEN)) (NO-UNTYI-QUOTE (RETURN TODO 'SPECIAL-TOKEN)) (OTHERWISE (FERROR NIL "The reader found ~S in the finite state machine" FLAG)))))) ;This ends the reader proper. The things from here on are called only if they appear in ;the readtable itself. Although this is somewhat special in that it handles splicing ;macros. Note that the second arg (FIFTY) should be a number (50) rather than a string ("(") ;due to the LAST-CHAR hack. (DEFUN (LIST STANDARD-READ-COMPARE-FUNCTION) (STREAM IGNORE FIFTY) (PROG ((LIST READ-COMPARE-OBJECT) THING TYPE SPLICEP) A ;; Handle the end of the list. (COND ((ATOM LIST) (MULTIPLE-VALUE (THING TYPE) (READ-COMPARE-THING NIL STREAM)) ;; Allow a splicing macro there. (COND ((EQ TYPE 'READER-MACRO) (MULTIPLE-VALUE (THING SPLICEP) (FUNCALL THING NIL LIST STREAM)) (COND ((NOT SPLICEP) (THROW NIL READ-COMPARE))) (SETQ LIST THING) (GO A))) ;; Aside from that, we must see a ")" or a ".". (OR (EQ TYPE 'SPECIAL-TOKEN) (THROW NIL READ-COMPARE)) (AND (EQ THING 'CONSING-DOT) (GO RDOT)) (AND (NULL LIST) (EQ THING 'CLOSE) (RETURN T)) (THROW NIL READ-COMPARE))) (AND (EQ LIST READ-COMPARE-STOP) (THROW 'STOP READ-COMPARE)) ;; Match the next element of the list. (MULTIPLE-VALUE (THING TYPE) (READ-COMPARE-THING (CAR LIST) STREAM)) (COND ((EQ TYPE 'READER-MACRO) (MULTIPLE-VALUE (THING SPLICEP) (FUNCALL THING (CAR LIST) LIST STREAM)) (COND (SPLICEP (SETQ LIST THING) (GO A)))) ((EQ TYPE 'SPECIAL-TOKEN) (COND ((EQ THING 'CONSING-DOT) (GO RDOT)) ((EQ THING 'CLOSE) (THROW NIL READ-COMPARE) (T (FERROR NIL "The special token ~S was read in the middle of a list" THING)))))) (SETQ LIST (CDR LIST)) (GO A) RDOT (MULTIPLE-VALUE (THING TYPE) (READ-COMPARE-THING LIST STREAM)) (AND (EQ TYPE 'SPECIAL-TOKEN) (FERROR NIL "The special token ~S was read after a dot" THING)) (COND ((EQ TYPE 'READER-MACRO) (MULTIPLE-VALUE (THING TYPE SPLICEP) (FUNCALL THING LIST NIL STREAM)) (AND SPLICEP (GO RDOT)))) (MULTIPLE-VALUE (THING TYPE) (READ-COMPARE-THING NIL STREAM)) (COND ((AND (EQ THING 'CLOSE) (EQ TYPE 'SPECIAL-TOKEN)) (RETURN LIST 'LIST)) (T (FERROR NIL "~S was read instead of a close paren" THING))))) (DEFUN (SHARP-LESSTHAN STANDARD-READ-COMPARE-FUNCTION) (STREAM STRING) STREAM (FERROR NIL "BARF! the reader just encountered a ~S" STRING)) (DEFPROP SC-SYMBOL READ-COMPARE-SYMBOL STANDARD-READ-COMPARE-FUNCTION) (DEFPROP SYMBOL READ-COMPARE-SYMBOL STANDARD-READ-COMPARE-FUNCTION) (DEFUN READ-COMPARE-SYMBOL (STREAM STRING &AUX SYMBOL TEM) (PROG () (AND (SETQ SYMBOL (INTERN-SOFT STRING)) (SETQ TEM (GET SYMBOL (GET (CONS NIL (RDTBL-PLIST READTABLE)) 'READ-COMPARE-MACRO-PROPERTY))) (RETURN TEM 'READER-MACRO)) (OR (AND (SYMBOLP READ-COMPARE-OBJECT) (STRING-EQUAL STRING READ-COMPARE-OBJECT)) (THROW NIL READ-COMPARE)) (RETURN T))) ;FOO: switches us to the package associated with the string "FOO" (DEFUN (PACKAGE-PREFIX STANDARD-READ-COMPARE-FUNCTION) (STREAM STRING IGNORE) (PROG (THING TYPE (PACKAGE (PKG-FIND-PACKAGE (OR STRING "") NIL PACKAGE))) (MULTIPLE-VALUE (THING TYPE) (READ-COMPARE-THING READ-COMPARE-OBJECT STREAM)) (RETURN THING TYPE))) (DEFPROP QUOTED-SYMBOL READ-COMPARE-STRING STANDARD-READ-COMPARE-FUNCTION) (DEFPROP STRING READ-COMPARE-STRING STANDARD-READ-COMPARE-FUNCTION) ;We use the winning LAST-CHAR hack to get the character to match (DEFUN READ-COMPARE-STRING (STREAM IGNORE MATCH &AUX TEM) (FUNCALL STREAM ':UNTYI MATCH) (OR (PROG1 (EQUAL READ-COMPARE-OBJECT (SETQ TEM (READ STREAM))) (AND (STRINGP TEM) (RETURN-ARRAY TEM))) (THROW NIL READ-COMPARE)) T) (DEFPROP SLASHED-SYMBOL READ-COMPARE-NUMBER STANDARD-READ-COMPARE-FUNCTION) (DEFPROP FIXNUM READ-COMPARE-NUMBER STANDARD-READ-COMPARE-FUNCTION) (DEFPROP FLONUM READ-COMPARE-NUMBER STANDARD-READ-COMPARE-FUNCTION) (DEFPROP SMALL-FLONUM READ-COMPARE-NUMBER STANDARD-READ-COMPARE-FUNCTION) (DEFUN READ-COMPARE-NUMBER (STREAM STRING) (OR (EQUAL READ-COMPARE-OBJECT (READ-FROM-STRING STRING)) (THROW NIL READ-COMPARE))) ;Standard reader macros: (PUTPROP '/' 'READ-COMPARE-QUOTE-MACRO 'STANDARD-READ-COMPARE-MACRO) (PUTPROP '/#/# 'READ-COMPARE-/#/#-MACRO 'STANDARD-READ-COMPARE-MACRO) (PUTPROP '/; 'READ-COMPARE-COMMENT-MACRO 'STANDARD-READ-COMPARE-MACRO) (PUTPROP '/` 'READ-COMPARE-BACKQUOTE-MACRO 'STANDARD-READ-COMPARE-MACRO) (PUTPROP '/, 'READ-COMPARE-COMMA-MACRO 'STANDARD-READ-COMPARE-MACRO) (PUTPROP '/#/Q 'READ-COMPARE-/#/Q-MACRO 'STANDARD-READ-COMPARE-MACRO) (PUTPROP '/#/M 'READ-COMPARE-/#/M-MACRO 'STANDARD-READ-COMPARE-MACRO) (DEFUN READ-COMPARE-QUOTE-MACRO (OBJECT IGNORE STREAM) (AND (EQ OBJECT READ-COMPARE-STOP) (THROW 'STOP READ-COMPARE)) (AND (LISTP OBJECT) (EQ (CADR OBJECT) READ-COMPARE-STOP) (THROW 'STOP READ-COMPARE)) (OR (AND (LISTP OBJECT) (EQ (CAR OBJECT) 'QUOTE) (NULL (CDDR OBJECT)) (READ-COMPARE-INTERNAL (CADR OBJECT) STREAM)) (THROW NIL READ-COMPARE)) T) (DEFUN READ-COMPARE-/#/#-MACRO (OBJECT IGNORE STREAM) (FUNCALL STREAM ':TYI) (OR (EQUAL OBJECT (FUNCALL STREAM ':TYI)) (THROW NIL READ-COMPARE)) T) (DEFUN READ-COMPARE-COMMENT-MACRO (IGNORE REST STREAM) (PROG (CH) A (SETQ CH (FUNCALL STREAM ':TYI)) (AND (OR (NULL CH) (EQ CH 215)) (RETURN REST T)) (GO A))) (DEFUN READ-COMPARE-BACKQUOTE-MACRO (OBJECT IGNORE STREAM &AUX OLD-COMMA-SYNTAX0 OLD-COMMA-SYNTAX1 VAL TYPE) (PROG NIL (SETQ OLD-COMMA-SYNTAX0 (AR-2 READTABLE 0 54) OLD-COMMA-SYNTAX1 (AR-2 READTABLE 1 54)) ;POOR MAN'S BIND. (AS-2 (AR-2 READTABLE 0 140) READTABLE 0 54) ;GIVE COMMA THE SYNTAX (AS-2 (AR-2 READTABLE 1 140) READTABLE 1 54) ; OF BACKQUOTE (SETQ VAL (READ STREAM '*EOF*)) ;*** FIGURE OUT EOF... (AND (EQ VAL '*EOF*) (THROW NIL READ-COMPARE)) (AS-2 OLD-COMMA-SYNTAX0 READTABLE 0 54) (AS-2 OLD-COMMA-SYNTAX1 READTABLE 1 54) (RETURN T))) (DEFUN READ-COMPARE-/#/Q-MACRO (OBJECT IGNORE STREAM) ;IN LISPM, GOBBLE FROB (READ-COMPARE-INTERNAL OBJECT STREAM)) (DEFUN READ-COMPARE-/#/M-MACRO (IGNORE REST STREAM) ;IN LISPM, FLUSH FROB (OR (EQ '*EOF* (READ STREAM '*EOF*)) (THROW NIL READ-COMPARE)) REST)