;; -*- Fonts: CPTFONT; Mode:Lisp; Package: BOXER -*- ;;; (C) Copyright 1985 Massachusetts Institute of Technology ;;; ;;; Permission to use, copy, modify, distribute, and sell this software ;;; and its documentation for any purpose is hereby granted without fee, ;;; provided that the above copyright notice appear in all copies and that ;;; both that copyright notice and this permission notice appear in ;;; supporting documentation, and that the name of M.I.T. not be used in ;;; advertising or publicity pertaining to distribution of the software ;;; without specific, written prior permission. M.I.T. makes no ;;; representations about the suitability of this software for any ;;; purpose. It is provided "as is" without express or implied warranty. ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; ;;; A "Pratt Parser" for BOXER, by Leigh Klotz. (KLOTZ@MIT-MC) ;;; ;;; Modeled after the VAX NIL parser, by George Carrette (GJC@MIT-MC) ;;; ;;; ;;; ;;; Based on a theory of parsing presented in: ;;; ;;; ;;; ;;; Pratt, Vaughan R., ``Top Down Operator Precedence,'' ;;; ;;; ACM Symposium on Principles of Programming Languages ;;; ;;; Boston, MA; October, 1973. ;;; ;;; ;;; ;;; The PARSE function takes a list describing BOXER code, and returns ;;; ;;; a list suitable for EVAL. ;;; ;;; Two optional arguments specify symbols that should be considered ;;; ;;; variables or procedures, but are not currently bound to the proper ;;; ;;; object. ;;; ;;; ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;Special variables for the token stuff. ;Has to be a symbol so we can put a rbp property on it. ;It has to be in the boxer package to keep from confusing it ;with something in the bu package. (DEFCONST *END-OF-LINE* '*END-OF-LINE*) (DEFVAR *CURRENT-TOKEN*) (DEFVAR *PRATT-PEEK-TOKEN?*) (DEFVAR *PRATT-READ-LIST*) (DEFVAR *TOKEN-TYPE*) (DEFVAR *OP*) (DEFVAR *SYMBOLS-TO-BE-CONSIDERED-VARIABLES-IN-PARSING*) (DEFVAR *SYMBOLS-TO-BE-CONSIDERED-PROCEDURES-IN-PARSING*) (DEFVAR *SYMBOLS-IN-ARGLIST*) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; Low-Level and setup stuff. ;;; (DEFSUBST COERCE-NUMBER-TO-BOX (NUMBER) (MAKE-INSTANCE 'DATA-BOX ':FIRST-INFERIOR-ROW (MAKE-ROW (NCONS NUMBER)))) ;The functions for getting the tokens from the input list, one-at-a-time. (DEFUN READ-TOKEN () (IF *PRATT-READ-LIST* (SETQ *CURRENT-TOKEN* (POP *PRATT-READ-LIST*)) (SETQ *CURRENT-TOKEN* *END-OF-LINE*)) ;; get rid of number here for now (probably the wrong place to do it) (WHEN (NUMBERP *CURRENT-TOKEN*) (SETQ *CURRENT-TOKEN* (COERCE-NUMBER-TO-BOX *CURRENT-TOKEN*))) *CURRENT-TOKEN*) (DEFUN PRATT-READ-REST-OF-LINE () (IF *PRATT-PEEK-TOKEN?* (CONS *CURRENT-TOKEN* (PROG1 *PRATT-READ-LIST* (SETQ *PRATT-READ-LIST* NIL *PRATT-PEEK-TOKEN?* NIL))) (PROG1 *PRATT-READ-LIST* (SETQ *PRATT-READ-LIST* NIL)))) (DEFUN PRATT-PEEK-TOKEN () (IF *PRATT-PEEK-TOKEN?* *CURRENT-TOKEN* (SETQ *PRATT-PEEK-TOKEN?* T) (READ-TOKEN))) (DEFUN PRATT-READ-TOKEN () (COND (*PRATT-PEEK-TOKEN?* (SETQ *PRATT-PEEK-TOKEN?* NIL) *CURRENT-TOKEN*) (T (READ-TOKEN)))) (DEFUN PRATT-READ-TOKEN-NO-EOL () (LET ((RESULT (PRATT-READ-TOKEN))) (IF (EQ RESULT *END-OF-LINE*) (PARSER-BARF "Not enough stuff on line.") RESULT))) ;;; Code generators. ;This reminds me of writing APPLY in Logo. (defun ENSHROUD-BOX-OR-VARIABLE (it) (cond ((box? it) (list 'quote it)) ((symbolp it) (boxer-variable-reference it)) (t it))) (defun boxer-variable-reference (symbol) `(boxer-symeval ',symbol)) (defun extract-entry (thing) (if (label-pair? thing) (label-pair-element thing) thing)) (defun parser-token-type (lex) (cond ((label-pair? lex) 'LABEL-PAIR) ((numberp lex) 'NUMBER) ((access-pair? lex) 'ACCESS-PAIR) (t (or (cdr (assq (typep lex) '((:symbol . symbol) (:string . string) (data-box . data-box) (port-box . port-box) (doit-box . doit-box) (sprite-box . sprite-box) (GRAPHICS-BOX . GRAPHICS-BOX) (GRAPHICS-data-BOX . GRAPHICS-data-BOX)))) (ferror nil "~S -- Unknown type in parser." lex))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; The top-level parsing function. Given a list describing a boxer expression, ;;; it returns a list suitable for EVAL. The caller should take this list ;;; and do one of several things, like eval it, wrap a lambda around it, ;;; or glom it together with some other ones in a PROGN. ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun parse (exp &optional (variables nil) (procedures nil) (inputs nil)) (if (null exp) nil (let ((*pratt-read-list* (SUBSET-NOT #'NAMED-BOX-P exp)) (*current-token*) (*PRATT-PEEK-TOKEN?*) (*OP* "Something") ;crock for now... (*SYMBOLS-TO-BE-CONSIDERED-VARIABLES-IN-PARSING* variables) (*SYMBOLS-TO-BE-CONSIDERED-PROCEDURES-IN-PARSING* procedures) (*SYMBOLS-IN-ARGLIST* inputs)) (pratt-parse 0)))) ;;; NUD -- NUll left Denotation (op has nothing to its left (prefix)) ;;; LED -- LEft Denotation (op has something to left (postfix or infix)) ;;; ;;; LBP -- Left Binding Power (the stickiness to the left) ;;; RBP -- Right Binding Power (the stickiness to the right) ;;; (PRATT-PARSE ) ;;; ;;; This will parse an expression containing operators which have a higher ;;; left binding power than , returning as soon as an operator of ;;; lesser or equal binding power is seen. ;note that the error reporting depends on the special variable *OP*... (DEFUN PRATT-PARSE (RBP) (LET ((RESULT (PRATT-PARSE-ALLOW-EOL RBP))) (IF (EQ RESULT *END-OF-LINE*) (PARSER-BARF "~A needs more inputs." *OP*) RESULT))) (DEFUN PRATT-PARSE-ALLOW-EOL (RBP) (DO ((EXPRESSION (PRATT-NUD-CALL (PRATT-READ-TOKEN) (parser-token-type *current-token*)) (PRATT-LED-CALL (PRATT-READ-TOKEN) (parser-token-type *current-token*) EXPRESSION))) ((>= RBP (PRATT-LBP (PRATT-PEEK-TOKEN) (parser-token-type (pratt-peek-token)))) EXPRESSION))) (DEFUN PRATT-NUD-CALL (LEX TYP) (funcall (OR (get typ 'NUD-TYPE-HANDLER) #'(LAMBDA (U) (FERROR "~S unknown datatype in parsing." U))) LEX)) (DEFUN PRATT-LED-CALL (LEX TYP EXP) (LET ((F (AND (EQ TYP 'SYMBOL) (GET LEX 'LED)))) (IF F (FUNCALL F LEX EXP) (if (eq (car exp) 'boxer-symeval) (PARSER-BARF "/~A/ is not a defined procedure." (cadr (cadr exp))) ;extracts variable reference. crock. (parser-barf "Too many commands on one line, just before ~A" lex) ;; (parser-barf "/"~A/" is not an infix operator." lex) )))) ;If a function has no precedence, then it's assumed to be less than ;the lowest infix function. (DEFUN PRATT-BP (LEX TYP P) (or (and (eq typ 'symbol) (get lex p)) 50)) (DEFUN PRATT-LBP (LEX &OPTIONAL (TYP 'SYMBOL)) (PRATT-BP LEX TYP 'LBP)) (DEFUN PRATT-RBP (LEX &OPTIONAL (TYP 'SYMBOL)) (PRATT-BP LEX TYP 'RBP)) (defun end-of-line-fun (*op*) *op*) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; Things for dealing with different funny datatypes in the prefix position. ;;; Funcalled by PRATT-NUD-CALL. ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;This function is nonstandard, in that it understands what to ;;;do with special boxer datatypes. If the symbol is on the ;;;lambda-list of the currently-being-parsed box, then it is not ;;;special and is a variable. ;;; ;;;Otherwise, If the token is a sumbol and it has a NUD ;;;property, then this NUD property is funcalled with the ;;;current-token as input. That's for parsing infix and special ;;;forms. (DEFUN (:PROPERTY SYMBOL NUD-TYPE-HANDLER) (LEX) (LET ((PARSING-FUN (GET LEX 'NUD)) ;Special form property. (NARGS (PARSER-PROCEDURE-SYMBOL-DESCRIPTOR-NUMBER-OF-ARGS (ASSQ LEX *SYMBOLS-TO-BE-CONSIDERED-PROCEDURES-IN-PARSING*)))) (COND ((OR (MEMQ LEX *SYMBOLS-IN-ARGLIST*) (ASSQ LEX *SYMBOLS-TO-BE-CONSIDERED-VARIABLES-IN-PARSING*)) (BOXER-VARIABLE-REFERENCE LEX)) ;It's definitely a varible. ((NUMBERP NARGS) (PRATT-PARSE-MULTIPREFIX LEX NARGS)) ;It's certainly a function. (parsing-fun (FUNCALL parsing-fun LEX)) ;Special form ((BOXER-FDEFINED? LEX) ;It's a currently-defined function (PRATT-PARSE-MULTIPREFIX LEX (PARSER-NUMBER-OF-ARGS LEX))) ((sprite-box? (boxer-symeval lex)) (list 'quote (port-to-internal (boxer-symeval lex)))) (T (BOXER-VARIABLE-REFERENCE LEX))))) ;Must be a variable or undefined function ;;;If it's a data-box, then it parses into 'BOX. Self-evaling ;;;things (numbers, strings) parse into themseves. Other things ;;;are probably broken anyway. ;;; ;;;Things which are currently-defined functions are parsed as ;;;multiple-input prefix functions according to the number of ;;;inputs they have. (DEFUN (:PROPERTY NUMBER NUD-TYPE-HANDLER) (LEX) LEX) (DEFUN (:PROPERTY STRING NUD-TYPE-HANDLER) (LEX) LEX) (DEFUN (:PROPERTY GRAPHICS-BOX NUD-TYPE-HANDLER) (LEX) (LIST 'QUOTE LEX)) (DEFUN (:PROPERTY DATA-BOX NUD-TYPE-HANDLER) (LEX) (LIST 'QUOTE LEX)) (DEFUN (:PROPERTY graphics-DATA-BOX NUD-TYPE-HANDLER) (LEX) (LIST 'QUOTE LEX)) (defun (:property sprite-box nud-type-handler) (lex) (list 'quote (port-to-internal lex))) (DEFUN (:PROPERTY DOIT-BOX NUD-TYPE-HANDLER) (LEX) (PRATT-PARSE-MULTIPREFIX LEX (PARSER-NUMBER-OF-ARGS LEX))) (defun (:property port-box nud-type-handler) (lex) (let ((obj (tell lex :ports))) (cond ((data-box? obj) (list 'quote lex)) ((doit-box? obj) (pratt-parse-multiprefix lex (parser-number-of-args obj))) ((GRAPHICS-BOX? OBJ) (list 'quote lex)) ((sprite-box? obj) (list 'quote obj)) ((graphics-data-box? obj) (list 'quote lex)) (t (ferror "Tried to parse a reference to a port which wasn't a port to a doit or data box: ~S" lex))))) (DEFUN (:PROPERTY LABEL-PAIR NUD-TYPE-HANDLER) (LEX) (PRATT-NUD-CALL (LABEL-PAIR-ELEMENT LEX) (PARSER-TOKEN-TYPE (LABEL-PAIR-ELEMENT LEX)))) ;This is a crock. These things shouldn't be put in procedure lambdas, ;but should be parsed when doit'd explcitly. There's no way to tell, ;though. We really need some other way of doing initial variable assignment. ;(defun (:property NAME-PAIR NUD-TYPE-HANDLER) (lex) ; (let ((name (name-pair-name lex)) ; (val (name-pair-element lex))) ; (if (box? val) (tell val :set-name name)) ; `(PROGN ; (BOXER-MAKE ',name ; ',val) ; ':NOPRINT))) ;;And if you think THAT was a crock... ;(defun (:property ACCESS-PAIR NUD-TYPE-HANDLER)(lex) ; (let* ((superbox (access-pair-superbox lex)) ; (subbox (access-pair-subbox lex))) ; `(progn ; (boxer-tell (boxer-eval ',superbox) ; (let ((eval-subbox (caar (get-pre-box-rows (boxer-eval ',subbox))))) ; `(,eval-subbox)))))) ;;; Parsing functions for various pieces of syntax. ;;; (PRATT-PARSE-MULTIPREFIX <*OP*> ) ;;; Parses prefix forms with multiple args -- e.g, REMAINDER 2 3 ;;; ;;; This is the default parsing property for symbols. It fires after any ;;; symbol currently defined as a function has been seen. It parses ;;; forward looking for NARGS more expressions according to its right binding ;;; power, returning a proper boxer-funcall expression. (defun pratt-parse-multiprefix (*OP* nargs) (LIST* 'BOXER-FUNCALL (ENSHROUD-BOX-OR-VARIABLE *OP*) ;; Get nargs args. (let ((rbp (PRATT-RBP *OP*))) (do ((args nil (cons (LET ((IT (PRATT-PARSE rbp))) (IF (EQ *END-OF-LINE* IT) (PARSER-BARF "~A needs more inputs." *OP*) (ENSHROUD-BOX-OR-VARIABLE it))) args)) (nargs nargs (1- nargs))) ((zerop nargs) (nreverse args)))))) ;;; (PRATT-PARSE-PREFIX <*OP*>) ;;; ;;; Parses prefix forms -- eg, - X or + X. ;;; ;;; This should be the NUD property on an operator. It fires after ;;; has been seen. It parses forward looking for one more expression ;;; according to its right binding power, returning (<*OP*> ). (DEFUN PRATT-PARSE-PREFIX (*OP*) (LIST 'BOXER-FUNCALL (ENSHROUD-BOX-OR-VARIABLE *OP*) ;; Convert single argument for use (ENSHROUD-BOX-OR-VARIABLE (PRATT-PARSE (PRATT-RBP *OP*))))) ;;; (PRATT-PARSE-POSTFIX <*OP*> ) ;;; ;;; Parses postfix forms. eg, X !. ;;; ;;; This should be the LED property of an operator. It fires after ;;; has been accumulated and has been seen and gobbled up. It returns ;;; (<*OP*> ). (DEFUN PRATT-PARSE-POSTFIX (*OP* left) (LIST 'BOXER-FUNCALL (ENSHROUD-BOX-OR-VARIABLE *OP*) left)) ;;; (PRATT-PARSE-INFIX <*OP*> ) ;;; ;;; Parses infix (non-nary) forms. eg, 5 mod 3. ;;; For things like +, see PRATT-PARSE-NARY. ;;; ;;; This should be the led property of an operator. It fires after ;;; has been accumulated and <*OP*> has been seen and gobbled up. (DEFUN PRATT-PARSE-INFIX (*OP* arg1) (LIST 'BOXER-FUNCALL *OP* ARG1 ;; Look for an arg2 (ENSHROUD-BOX-OR-VARIABLE (PRATT-PARSE (PRATT-RBP *OP*))))) ;;; (PRATT-PARSE-NARY <*OP*> ) ;;; ;;; Parses nary forms. Eg, form1*form2*... or form1+form2+... ;;; This should be the LED property on an operator. It fires after ;;; has been seen, accumulating and returning ;;; (<*OP*> ...). ;;; ;;; <*OP*> is the being parsed. ;;; is the stuff that has been seen to the left of <*OP*> which ;;; rightly belongs to <*OP*> on the basis of parse precedence rules. (DEFUN PRATT-PARSE-NARY (*OP* L) (LIST* 'BOXER-FUNCALL *OP* (ENSHROUD-BOX-OR-VARIABLE L) ;; Search for other args (PRATT-PARSE-NARY-SUB *OP* (PRATT-LBP *OP*)))) ;;; (PRATT-PARSE-NARY-SUB <*OP*> ) ;;; ;;; Parses an nary operator tail E.G., ...form2+form3+... or ...form2*form3*.. ;;; ;;; Expects to be entered after the leading form and the first call to an ;;; nary operator has been seen and popped. Returns a list of parsed forms ;;; which belong to that operator. Eg, for X+Y+Z; this should be called ;;; after the first + is popped. Returns (Y Z). ;;; ;;; <*OP*> is the nary operator in question. ;;; is (LBP <*OP*>) and is provided for efficiency. It is for use in ;;; recursive parses as a binding power to parse for. (DEFUN PRATT-PARSE-NARY-SUB (*OP* RBP) (DO ((NL (LIST (PRATT-PARSE RBP)) ;Get at least one form (CONS (PRATT-PARSE RBP) NL))) ;and keep getting forms ((NOT (EQ *OP* (PRATT-PEEK-TOKEN))) ;until a parse pops on a new op (NREVERSE NL)) ;at which time return forms (PRATT-READ-TOKEN))) ;otherwise pop *OP* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Boxer Special Form parser ;;; It's like DEFUN, but the special arg declarations are in lists instead ;;; of being flattened out -- for example: ;;; (defboxer-macro set (("e variable) value) ;;; `(progn ;;; (boxer-set ',variable ,value) ;;; ':NOPRINT)) ;;; There are subtlties about "e and also about whether you put a quote before ;;; a comma. (defmacro defboxer-special (name arglist &body body) (let* ((argnames (mapcar #'(lambda (entry) (if (symbolp entry) entry (cadr entry))) arglist)) (bu-name (intern-in-bu-package name)) (values (mapcar #'(lambda (entry) (if (symbolp entry) '(pratt-parse (pratt-rbp *OP*)) (selectq (car entry) ("e '(extract-entry (pratt-read-token-no-eol))) (&rest '(pratt-read-rest-of-line)) (otherwise (ferror "Bad arglist element in DEFBOXER-SPECIAL ~S" entry))))) arglist))) `(progn 'compile (putprop ',bu-name ',argnames 'arglist) (defun (:property ,bu-name nud) (*op*) (let ,(mapcar #'list argnames values) .,body))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; Parsers for special forms. ;;; These functions are on the Null Left Denotation property of the function ;;; name. They get one argument, which is the name of the function (for ;;; functions that want to handle multiple ones.) They should return some ;;; eval-able lisp code. ;;; ;;; This stuff should be replaced with a macro that takes a function name ;;; and an arglist and does the right thing. ;;;REPEAT 3 (defboxer-special repeat (times stuff) `(catch 'iteration-tag (dotimes (repeat-times (NUMBERIZE ,TIMES)) ,stuff))) ;;;IF BOX BOX ;;;IF BOX BOX BOX (defprop bu:if (PREDICATE CONSEQUENT ALTERNATIVE) ARGLIST) (defun (:property BU:IF nud) (*OP*) (let ((predicate (pratt-parse (pratt-rbp *OP*))) (consequent (pratt-parse (pratt-rbp *OP*)))) (if (eq (pratt-peek-token) *end-of-line*) `(COND ((TRUE? ,predicate) ,consequent)) `(COND ((TRUE? ,predicate) ,consequent) (t ,(pratt-parse (pratt-rbp *OP*))))))) ;;;TELL BOX DOITBOX ;;;=> (boxer-tell 'box '(list of elements on rest of line)) ;;;or (boxer-tell-rowlist 'box '(list of rows)) ;this parsing isn't quite right (defboxer-special tell (who (&rest what)) (if (and (null (cdr what)) (doit-box? (car what))) `(boxer-tell-rowlist ,who ',(tell (car what) :rows)) `(boxer-tell ,who ',what))) ;;;; A real quick one here (defboxer-special tell-all (whos (&rest what)) (if (and (null (cdr what)) (doit-box? (car what))) `(loop for box in (subset #'box? (tell ,whos :elements)) do (boxer-tell-rowlist box ',(tell (car what) :rows))) `(loop for box in (subset #'box? (tell ,whos :elements)) do (boxer-tell box ',what)))) ;;;DEFINE-INSIDE-BOX ;; Actually, TELL should take care of this special form, but for reasons that ;; are momentarily unclear, it doesn't. This procedure allows you to create ;; a binding inside another box, as in ;; DEFINE-INSIDE-BOX FOO NEW-FOO-PROC . ;; Perhaps the result of such a call should be that the new binding is actually ;; displayed somewhere inside FOO (as in, at least, the local library of FOO). ;; Right now, this doesn't happen -- so use this at your own risk. (defboxer-special define-inside-box (box ("e name)("e value)) `(tell ,box :add-static-variable-pair ',name ',value)) ;;;SET x 3 ;;;SET does searching. (defboxer-special set (("e variable) value) `(progn (boxer-set ',variable ,value) ':NOPRINT)) ;;;MAKE X box ;;;Make always affects the current box environment. If there's no variable ;;;named X, it adds one. If there's nothing running (i.e. toplevel inside ;;;a box) it adds it permanently, otherwise it adds it to the copy. (defboxer-special make (("e variable) value) `(progn (boxer-make ',variable ,value) ':noprint)) ;;;FILE is like MAKE, but doesn't eval the second arg. ;;;FILE X box (defboxer-special file (("e variable) ("e value)) `(PROGN (boxer-make ',variable ',value) ':noprint)) ;;;TEXT name-or-box (defboxer-special text (("e box-or-name)) `(datafy ,(cond ((box? box-or-name) (LIST 'QUOTE box-or-name)) ((symbolp box-or-name) (LIST 'QUOTE (BOXER-SYMEVAL box-or-name))) (t (parser-barf "TEXT doesn't like ~A as input. It expects a doit-box or the name of a doit-box." box-or-name))))) ;;; STOP ;;; This isn't quite worked out yet. (defboxer-special stop () `(throw 'iteration-tag ':NOPRINT)) (defboxer-special return (value) `(throw 'iteration-tag ,value)) ;;;The Local Library might have an INPUT/INPUTS line in it, and it doesn't go through ;;;;parse-code-into-lambda which excises the inputs line before parsing the ;;;;whole thing (as a speed hack). (defboxer-special input ((&rest ignore)) '':NOPRINT) (defboxer-special inputs ((&rest ignore)) '':NOPRINT) ;;Exporting variables (DEFBOXER-FUNCTION BU:SHOW-EXPORTS (BOX) (LET ((EXPORTING-VARS (TELL BOX :GET-EXPORTS))) (IF (NULL EXPORTING-VARS) (MAKE-BOX ()) (MAKE-BOX (MAPCAR #'NCONS EXPORTING-VARS))))) (DEFBOXER-FUNCTION BU:EXPORT-ALL (BOX) (TELL BOX :EXPORT-ALL-VARIABLES)) (DEFBOXER-SPECIAL BU:EXPORT (("E VARIABLE) BOX) `(PROGN (TELL ,BOX :EXPORT-VARIABLE ',VARIABLE) ':NOPRINT)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; Setup stuff. This function should be made readable. ;;; (DEFUN ENTER-PRATT-OP (OP &REST P) (LET (LBP RBP) (do ((list p (cddr list))) ((null list)) (LET ((K (car list)) (v (cadr list))) (COND ((EQ K 'LBP) (SETQ LBP V)) ((EQ K 'RBP) (SETQ RBP V)) ('ELSE (PUTPROP OP (IF (AND (MEMQ K '(NUL LED)) (SYMBOLP V)) (FSYMEVAL V) V) K))))) (LET ((EXISTING-LBP (GET OP 'LBP)) (EXISTING-RBP (GET OP 'RBP))) (COND ((NOT LBP) (COMMENT IGNORE OMITTED ARG)) ((NOT EXISTING-LBP) (SETF (GET OP 'LBP) LBP)) ((NOT (EQUAL EXISTING-LBP LBP)) (FERROR "Incompatible LBP's defined for ~S operator" OP))) (COND ((NOT RBP) (COMMENT IGNORE OMITTED ARG)) ((NOT EXISTING-RBP) (SETF (GET OP 'RBP) RBP)) ((NOT (EQUAL EXISTING-RBP RBP)) (FERROR "Incompatible RBP's defined for ~S operator" OP)))))) (EVAL-WHEN (LOAD EVAL) (MAPC #'(LAMBDA (L) (APPLY #'ENTER-PRATT-OP L)) '((BU:|^| LED PRATT-PARSE-INFIX LBP 140. RBP 139.) (BU:|*| LED PRATT-PARSE-NARY LBP 120.) (BU:|//| LED PRATT-PARSE-INFIX LBP 120. RBP 120.) (BU:|+| NUD PRATT-PARSE-PREFIX LBP 100. RBP 100. LED PRATT-PARSE-NARY) (BU:|-| NUD PRATT-PARSE-PREFIX LBP 100. RBP 134. LED PRATT-PARSE-NARY) (BU:|=| LED PRATT-PARSE-INFIX LBP 80. RBP 80.) (BU:|>| LED PRATT-PARSE-INFIX LBP 80. RBP 80.) (BU:|>=| LED PRATT-PARSE-INFIX LBP 80. RBP 80.) (BU:|| LED PRATT-PARSE-INFIX LBP 80 RBP 80) (BU:|<| LED PRATT-PARSE-INFIX LBP 80. RBP 80.) (BU:|<=| LED PRATT-PARSE-INFIX LBP 80. RBP 80.) (BU:|| LED PRATT-PARSE-INFIX LBP 80. RBP 80.) (bu:|| LED PRATT-PARSE-INFIX LBP 80. RBP 80.) (*END-OF-LINE* NUD end-of-line-fun LBP -1))) ); End of Eval-when.