git.fiddlerwoaroof.com
src/ops-compile.lisp
5092d8a5
 ;;; ****************************************************************
 ;;; OPS5 Interpreter ***********************************************
 ;;; ****************************************************************
 ;;; This Common Lisp version of OPS5 is in the public domain.  It is based
 ;;; in part on based on a Franz Lisp implementation done by Charles L. Forgy
 ;;; at Carnegie-Mellon University, which was placed in the public domain by
 ;;; the author in accordance with CMU policies.  Ported to Common Lisp by 
 ;;; George Wood and Jim Kowalski. CMU Common Lisp modifications by
 ;;; Dario Guise, Skef Wholey, Michael Parzen, and Dan Kuokka. 
 ;;; Modified to work in CLtL1, CLtL2 and X3J13 compatible lisps by 
 ;;; Mark Kantrowitz on 14-OCT-92.
 ;;; 
 ;;; This code is made available is, and without warranty of any kind by the
 ;;; authors or by Carnegie-Mellon University.
 ;;;
 
 ;;;; This file contains functions compile productions.
 
 (in-package "OPS")
983cb74c
 ;;(shadow '(remove write))    ; Should get this by requiring ops-rhs
 ;;(export '--> )
5092d8a5
 
 
 ;;; External global variables
 
6c4d2158
 (defvar *real-cnt* nil)
 (defvar *virtual-cnt* nil)
 (defvar *last-node* nil)
 (defvar *first-node* nil)
 (defvar *pcount* nil)
5092d8a5
 
 
 ;;; Internal global variables
 
6c4d2158
 (defvar *matrix* nil)
 (defvar *curcond* nil)
 (defvar *feature-count* nil)
 (defvar *ce-count* nil)
 (defvar *vars* nil)
 (defvar *ce-vars* nil)
 (defvar *rhs-bound-vars* nil)
 (defvar *rhs-bound-ce-vars* nil)
 (defvar *last-branch* nil)
 (defvar *subnum* nil)
 (defvar *cur-vars* nil)
 (defvar *action-type* nil)
5092d8a5
 
 
 
 (defun compile-init ()
   (setq *real-cnt* (setq *virtual-cnt* 0.))
   (setq *pcount* 0.)
   (make-bottom-node))
 
 
 ;;; LHS Compiler
 
 (defun ops-p (z) 
   (finish-literalize)
   (princ '*) 
983cb74c
   ;;(drain) commented out temporarily
5092d8a5
   (force-output)			;@@@ clisp drain?
   (compile-production (car z) (cdr z))) 
 
 
 (defun compile-production (name matrix)
   ;; jgk inverted args to catch and quoted tag
   (setq *p-name* name)
   (catch '!error! (cmp-p name matrix))
   (setq *p-name* nil))
983cb74c
 
 #+(or)
5092d8a5
 (defun compile-production (name matrix) ;jgk inverted args to catch 
   (prog (erm)				;and quoted tag
983cb74c
      (setq *p-name* name)
      (setq erm (catch '!error! (cmp-p name matrix)))
      (setq *p-name* nil)))
 
5092d8a5
 
 (defun peek-lex ()
   (car *matrix*)) 
 
 (defun lex ()
   (pop *matrix*)) 
 
 (defun end-of-p () (atom *matrix*)) 
 
 (defun rest-of-p () *matrix*) 
 
 (defun prepare-lex (prod) (setq *matrix* prod)) 
 
 
 (defun peek-sublex () (car *curcond*)) 
 
 (defun sublex ()
   (pop *curcond*)) 
 
 (defun end-of-ce () (atom *curcond*)) 
 
 (defun rest-of-ce () *curcond*) 
 
 (defun prepare-sublex (ce) (setq *curcond* ce)) 
 
 (defun make-bottom-node ()
   (setq *first-node* (list '&bus nil))) 
 
 (defun cmp-p (name matrix)
   (prog (m bakptrs)
983cb74c
      (cond ((or (null name) (consp  name))	;dtpr\consp gdw
             (%error '|illegal production name| name))
            ((equal (gethash name *production-table*) matrix)
             (return nil)))
      (prepare-lex matrix)
      (excise-p name)
      (setq bakptrs nil)
      (incf *pcount*)		;"plus" changed to "+" by gdw
      (setq *feature-count* 0.)
      (setq *ce-count* 0)
      (setq *vars* nil)
      (setq *ce-vars* nil)
      (setq *rhs-bound-vars* nil)
      (setq *rhs-bound-ce-vars* nil)
      (setq *last-branch* nil)
      (setq m (rest-of-p))
    l1   (and (end-of-p) (%error '|no '-->' in production| m))
      (cmp-prin)
      (setq bakptrs (cons *last-branch* bakptrs))
      (or (eq '--> (peek-lex)) (go l1))
      (lex)
      (check-rhs (rest-of-p))
      (link-new-node (list '&p
                           *feature-count*
                           name
                           (encode-dope)
                           (encode-ce-dope)
                           (cons 'progn (rest-of-p))))
      (setf (gethash name *backpointers-table*) (cdr (nreverse bakptrs)))
      (setf (gethash name *production-table*) matrix)
      (setf (gethash name *topnode-table*) *last-node*))) 
5092d8a5
 
 (defun rating-part (pnode) (cadr pnode)) 
 
 (defun var-part (pnode) (car (cdddr pnode))) 
 
 (defun ce-var-part (pnode) (cadr (cdddr pnode))) 
 
 (defun rhs-part (pnode) (caddr (cdddr pnode))) 
 
 (defun cmp-prin nil
   (setq *last-node* *first-node*)
   (cond ((null *last-branch*) (cmp-posce) (cmp-nobeta))
983cb74c
         ((eq (peek-lex) '-) (cmp-negce) (cmp-not))
         (t (cmp-posce) (cmp-and)))) 
5092d8a5
 
 (defun cmp-negce nil (lex) (cmp-ce)) 
 
 (defun cmp-posce nil
   (setq *ce-count* (1+ *ce-count*))		;"plus" changed to "+" by gdw
   (cond ((eq (peek-lex) '\{) (cmp-ce+cevar))	;"plus" changed to "+" by gdw
983cb74c
         (t (cmp-ce)))) 
5092d8a5
 
 (defun cmp-ce+cevar ()
   (prog (z)
983cb74c
      (lex)
      (cond ((atom (peek-lex)) (cmp-cevar) (cmp-ce))
            (t (cmp-ce) (cmp-cevar)))
      (setq z (lex))
      (or (eq z '\}) (%error '|missing '}'| z)))) 
5092d8a5
 
 (defun new-subnum (k)
   (or (numberp k) (%error '|tab must be a number| k))
   (setq *subnum* (floor k))) 
 
 (defun incr-subnum ()
   (incf *subnum*)) 
 
 (defun cmp-ce ()
   (prog (z)
983cb74c
      (new-subnum 0.)
      (setq *cur-vars* nil)
      (setq z (lex))
      (and (atom z)
           (%error '|atomic conditions are not allowed| z))
      (prepare-sublex z)
    la   (and (end-of-ce) (return nil))
      (incr-subnum)
      (cmp-element)
      (go la))) 
5092d8a5
 
 (defun cmp-element nil
   (when (eq (peek-sublex) '^)
     (cmp-tab))
   (cond ((eq (peek-sublex) '\{) (cmp-product))
983cb74c
         (t (cmp-atomic-or-any))))
5092d8a5
 
 (defun cmp-atomic-or-any ()
   (cond ((eq (peek-sublex) '<<) (cmp-any))
983cb74c
         (t (cmp-atomic))))
5092d8a5
 
 (defun cmp-any ()
   (prog (a z)
983cb74c
      (sublex)
      (setq z nil)
    la   (cond ((end-of-ce) (%error '|missing '>>'| a)))
      (setq a (sublex))
      (cond ((not (eq '>> a)) (setq z (cons a z)) (go la)))
      (link-new-node (list '&any nil (current-field) z)))) 
5092d8a5
 
 (defun cmp-tab nil
   (prog (r)
983cb74c
      (sublex)
      (setq r (sublex))
      (setq r ($litbind r))
      (new-subnum r))) 
5092d8a5
 
 (defun get-bind (x)
   (when (symbolp x)
     (literal-binding-of x))) 
 
 (defun cmp-atomic nil
   (prog (test x)
983cb74c
      (setq x (peek-sublex))
      (cond ((eq x '= ) (setq test 'eq) (sublex))
            ((eq x '<>) (setq test 'ne) (sublex))
            ((eq x '<) (setq test 'lt) (sublex))
            ((eq x '<=) (setq test 'le) (sublex))
            ((eq x '>) (setq test 'gt) (sublex))
            ((eq x '>=) (setq test 'ge) (sublex))
            ((eq x '<=>) (setq test 'xx) (sublex))
            (t (setq test 'eq)))
      (cmp-symbol test))) 
5092d8a5
 
 (defun cmp-product ()
   (prog (save)
983cb74c
      (setq save (rest-of-ce))
      (sublex)
    la   (cond ((end-of-ce)
                (cond ((member '\} save :test #'equal) 
                       (%error '|wrong contex for '}'| save))
                      (t (%error '|missing '}'| save))))
               ((eq (peek-sublex) '\}) (sublex) (return nil)))
      (cmp-atomic-or-any)
      (go la))) 
5092d8a5
 
 (defun cmp-symbol (test)
   (let ((flag t))
     (when (eq (peek-sublex) '//)
       (sublex)
       (setq flag nil))
     (cond ((and flag (variablep (peek-sublex)))
983cb74c
            (cmp-var test))
           ((numberp (peek-sublex)) (cmp-number test))
           ((symbolp (peek-sublex)) (cmp-constant test))
           (t (%error '|unrecognized symbol| (sublex)))))) 
5092d8a5
 
 (defun cmp-constant (test)   ;jgk inserted concatenate form
   (or (member test '(eq ne xx))
       (%error '|non-numeric constant after numeric predicate| (sublex)))
   (link-new-node (list (intern (concatenate 'string
983cb74c
                                             "T"
                                             (symbol-name  test)
                                             "A"))
                        nil
                        (current-field)
                        (sublex)))) 
5092d8a5
 
 (defun cmp-number (test)		;jgk inserted concatenate form
   (link-new-node (list (intern (concatenate 'string
983cb74c
                                             "T"
                                             (symbol-name  test)
                                             ;;@@@ error? reported by laird fix\	    "A"
                                             "N"))
                        nil
                        (current-field)
                        (sublex)))) 
5092d8a5
 
 (defun current-field () (field-name *subnum*)) 
 
 (defun field-name (num)
   (if (< 0 num 127)
       (svref '#(nil *c1* *c2* *c3* *c4* *c5* *c6* *c7* *c8* *c9* *c10* *c11*
983cb74c
                 *c12* *c13* *c14* *c15* *c16* *c17* *c18* *c19* *c20* *c21*
                 *c22* *c23* *c24* *c25* *c26* *c27* *c28* *c29* *c30* *c31*
                 *c32* *c33* *c34* *c35* *c36* *c37* *c38* *c39* *c40* *c41*
                 *c42* *c43* *c44* *c45* *c46* *c47* *c48* *c49* *c50* *c51*
                 *c52* *c53* *c54* *c55* *c56* *c57* *c58* *c59* *c60* *c61*
                 *c62* *c63* *c64* *c65* *c66* *c67* *c68* *c69* *c70* *c71*
                 *c72* *c73* *c74* *c75* *c76* *c77* *c78* *c79* *c80* *c81*
                 *c82* *c83* *c84* *c85* *c86* *c87* *c88* *c89* *c90* *c91*
                 *c92* *c93* *c94* *c95* *c96* *c97* *c98* *c99* *c100*
                 *c101* *c102* *c103* *c104* *c105* *c106* *c107* *c108*
                 *c109* *c110* *c111* *c112* *c113* *c114* *c115* *c116*
                 *c117* *c118* *c119* *c120* *c121* *c122* *c123* *c124*
                 *c125* *c126* *c127*)
              num)
5092d8a5
       (%error '|condition is too long| (rest-of-ce))))
 
 ;;; Compiling variables
983cb74c
 ;;
 ;;
 ;;
 ;; *cur-vars* are the variables in the condition element currently 
 ;; being compiled.  *vars* are the variables in the earlier condition
 ;; elements.  *ce-vars* are the condition element variables.  note
 ;; that the interpreter will not confuse condition element and regular
 ;; variables even if they have the same name.
 ;;
 ;; *cur-vars* is a list of triples: (name predicate subelement-number)
 ;; eg:		( (<x> eq 3)
 ;;		  (<y> ne 1)
 ;;		  . . . )
 ;;
 ;; *vars* is a list of triples: (name ce-number subelement-number)
 ;; eg:		( (<x> 3 3)
 ;;		  (<y> 1 1)
 ;;		  . . . )
 ;;
 ;; *ce-vars* is a list of pairs: (name ce-number)
 ;; eg:		( (ce1 1)
 ;;		  (<c3> 3)
 ;;		  . . . )
5092d8a5
 
 ;;; used only in this file.
 (defmacro var-dope (var) `(assoc ,var *vars*))
 
 (defmacro ce-var-dope (var) `(assoc ,var *ce-vars*))
 
 (defun cmp-var (test)
   (let* ((name (sublex))
983cb74c
          (old (assoc name *cur-vars*)))
5092d8a5
     (cond ((and old (eq (cadr old) 'eq))
983cb74c
            (cmp-old-eq-var test old))
           ((and old (eq test 'eq)) (cmp-new-eq-var name old))
           (t (cmp-new-var name test))))) 
5092d8a5
 
 (defun cmp-new-var (name test)
   (push (list name test *subnum*) 
983cb74c
         *cur-vars*)) 
5092d8a5
 
 (defun cmp-old-eq-var (test old)	; jgk inserted concatenate form
   (link-new-node (list (intern (concatenate 'string
983cb74c
                                             "T"
                                             (symbol-name  test)
                                             "S"))
                        nil
                        (current-field)
                        (field-name (caddr old))))) 
5092d8a5
 
 (defun cmp-new-eq-var (name old)	;jgk inserted concatenate form
   (prog (pred next)
983cb74c
      (setq *cur-vars* (delete old *cur-vars* :test #'eq))
      (setq next (assoc name *cur-vars*))
      (cond (next (cmp-new-eq-var name next))
            (t (cmp-new-var name 'eq)))
      (setq pred (cadr old))
      (link-new-node (list (intern (concatenate 'string
                                                "T"
                                                (symbol-name  pred)
                                                "S"))
                           nil
                           (field-name (caddr old))
                           (current-field))))) 
5092d8a5
 
 (defun cmp-cevar nil
   (let* ((name (lex))
983cb74c
          (old (assoc name *ce-vars*)))
5092d8a5
     (when old
       (%error '|condition element variable used twice| name))
     (push (list name 0.) 
983cb74c
           *ce-vars*))) 
5092d8a5
 
 (defun cmp-not nil (cmp-beta '&not)) 
 
 (defun cmp-nobeta nil (cmp-beta nil)) 
 
 (defun cmp-and nil (cmp-beta '&and)) 
 
 (defun cmp-beta (kind)
   (prog (tlist vdope vname #|vpred vpos|# old)
983cb74c
      (setq tlist nil)
    la   (and (atom *cur-vars*) (go lb))
      (setq vdope (car *cur-vars*))
      (setq *cur-vars* (cdr *cur-vars*))
      (setq vname (car vdope))
      ;;  (setq vpred (cadr vdope))    Dario - commented out (unused)
      ;;  (setq vpos (caddr vdope))
      (setq old (assoc vname *vars*))
      (cond (old (setq tlist (add-test tlist vdope old)))
            ((not (eq kind '&not)) (promote-var vdope)))
      (go la)
    lb   (and kind (build-beta kind tlist))
      (or (eq kind '&not) (fudge))
      (setq *last-branch* *last-node*))) 
5092d8a5
 
 (defun add-test (list new old) ; jgk inserted concatenate form
   (prog (ttype lloc rloc)
983cb74c
      (incf *feature-count*)
      (setq ttype (intern (concatenate 'string "T"
                                       (symbol-name (cadr new))
                                       "B")))
      (setq rloc (encode-singleton (caddr new)))
      (setq lloc (encode-pair (cadr old) (caddr old)))
      (return (cons ttype (cons lloc (cons rloc list)))))) 
5092d8a5
 
983cb74c
 ;; the following two functions encode indices so that gelm can
 ;; decode them as fast as possible
5092d8a5
 
 (defun encode-pair (a b) (+ (* 10000. (1- a)) (1- b))) 
983cb74c
 ;;"plus" changed to "+" by gdw
5092d8a5
 
 (defun encode-singleton (a) (1- a)) 
 
 (defun promote-var (dope)
   (prog (vname vpred vpos new)
983cb74c
      (setq vname (car dope))
      (setq vpred (cadr dope))
      (setq vpos (caddr dope))
      (or (eq 'eq vpred)
          (%error '|illegal predicate for first occurrence|
                  (list vname vpred)))
      (setq new (list vname 0. vpos))
      (setq *vars* (cons new *vars*)))) 
5092d8a5
 
 (defun fudge nil
   (mapc #'fudge* *vars*)
   (mapc #'fudge* *ce-vars*)) 
 
 (defun fudge* (z)
   (let ((a (cdr z)))
     (incf (car a)))) 
 
 (defun build-beta (type tests)
   (prog (rpred lpred lnode lef)
983cb74c
      (link-new-node (list '&mem nil nil (protomem)))
      (setq rpred *last-node*)
      (cond ((eq type '&and)
             (setq lnode (list '&mem nil nil (protomem))))
            (t (setq lnode (list '&two nil nil))))
      (setq lpred (link-to-branch lnode))
      (cond ((eq type '&and) (setq lef lpred))
            (t (setq lef (protomem))))
      (link-new-beta-node (list type nil lef rpred tests)))) 
5092d8a5
 
 (defun protomem nil (list nil)) 
 
 (defun memory-part (mem-node) (car (cadddr mem-node))) 
 
 (defun encode-dope nil
   (prog (r all z k)
983cb74c
      (setq r nil)
      (setq all *vars*)
    la   (and (atom all) (return r))
      (setq z (car all))
      (setq all (cdr all))
      (setq k (encode-pair (cadr z) (caddr z)))
      (setq r (cons (car z) (cons k r)))
      (go la))) 
5092d8a5
 
 (defun encode-ce-dope nil
   (prog (r all z k)
983cb74c
      (setq r nil)
      (setq all *ce-vars*)
    la   (and (atom all) (return r))
      (setq z (car all))
      (setq all (cdr all))
      (setq k (cadr z))
      (setq r (cons (car z) (cons k r)))
      (go la))) 
5092d8a5
 
 
 
 ;;; Linking the nodes
 
 (defun link-new-node (r)
   (cond ((not (member (car r) '(&p &mem &two &and &not) :test #'equal))
983cb74c
          (setq *feature-count* (1+ *feature-count*))))
5092d8a5
   (setq *virtual-cnt* (1+ *virtual-cnt*))
   (setq *last-node* (link-left *last-node* r))) 
 
 (defun link-to-branch (r)
   (setq *virtual-cnt* (1+ *virtual-cnt*))
   (setq *last-branch* (link-left *last-branch* r))) 
 
 (defun link-new-beta-node (r)
   (setq *virtual-cnt* (1+ *virtual-cnt*))
   (setq *last-node* (link-both *last-branch* *last-node* r))
   (setq *last-branch* *last-node*)) 
 
 (defun link-left (pred succ)
   (prog (a r)
983cb74c
      (setq a (left-outs pred))
      (setq r (find-equiv-node succ a))
      (and r (return r))
      (setq *real-cnt* (1+ *real-cnt*))
      (attach-left pred succ)
      (return succ))) 
5092d8a5
 
 (defun link-both (left right succ)
   (prog (a r)
983cb74c
      (setq a (intersection (left-outs left) (right-outs right)))
      (setq r (find-equiv-beta-node succ a))
      (and r (return r))
      (setq *real-cnt* (1+ *real-cnt*))
      (attach-left left succ)
      (attach-right right succ)
      (return succ))) 
5092d8a5
 
 (defun attach-right (old new)
   (rplaca (cddr old) (cons new (caddr old)))) 
 
 (defun attach-left (old new)
   (rplaca (cdr old) (cons new (cadr old)))) 
 
 (defun right-outs (node) (caddr node)) 
 
 (defun left-outs (node) (cadr node)) 
 
 (defun find-equiv-node (node list)
   (prog (a)
983cb74c
      (setq a list)
    l1   (cond ((atom a) (return nil))
               ((equiv node (car a)) (return (car a))))
      (setq a (cdr a))
      (go l1))) 
5092d8a5
 
 (defun find-equiv-beta-node (node list)
   (prog (a)
983cb74c
      (setq a list)
    l1   (cond ((atom a) (return nil))
               ((beta-equiv node (car a)) (return (car a))))
      (setq a (cdr a))
      (go l1))) 
5092d8a5
 
983cb74c
 ;; do not look at the predecessor fields of beta nodes; they have to be
 ;; identical because of the way the candidate nodes were found
5092d8a5
 
 (defun equiv (a b)
   (and (eq (car a) (car b))
        (or (eq (car a) '&mem)
983cb74c
            (eq (car a) '&two)
            (equal (caddr a) (caddr b)))
5092d8a5
        (equal (cdddr a) (cdddr b)))) 
 
 (defun beta-equiv (a b)
   (and (eq (car a) (car b))
        (equal (cddddr a) (cddddr b))
        (or (eq (car a) '&and) (equal (caddr a) (caddr b))))) 
 
983cb74c
 ;; the equivalence tests are set up to consider the contents of
 ;; node memories, so they are ready for the build action
5092d8a5
 
 
 
 ;;; Check the RHSs of productions 
 
 
 (defun check-rhs (rhs) (mapc #'check-action rhs))
 
 (defun check-action (x)
   (if (atom x)
       (%warn '|atomic action| x)
       (let ((a (car x)))
983cb74c
         (setq *action-type* a)
         (case a
           (bind (check-bind x))
           (cbind (check-cbind x))
           (make (check-make x))
           (modify (check-modify x))
           (remove (check-remove x))
           (write (check-write x))	
           (call (check-call x))		
           (halt (check-halt x))
           (openfile (check-openfile x))
           (closefile (check-closefile x))
           (default (check-default x))
           (build (check-build x))
           (t (%warn '|undefined rhs action| a))))))
 
 
 ;;(defun chg-to-write (x)
 ;;	(setq x (cons 'write (cdr x))))
5092d8a5
 
 (defun check-build (z)
   (when (null (cdr z))
     (%warn '|needs arguments| z))
   (check-build-collect (cdr z)))
 
 (defun check-build-collect (args)
   (prog (r)
983cb74c
    top	(and (null args) (return nil))
      (setq r (car args))
      (setq args (cdr args))
      (cond ((consp  r) (check-build-collect r))	;dtpr\consp gdw
            ((eq r '\\)
             (and (null args) (%warn '|nothing to evaluate| r))
             (check-rhs-value (car args))
             (setq args (cdr args))))
      (go top)))
5092d8a5
 
 (defun check-remove (z) 				;@@@ kluge by gdw
   (when (null (cdr z))
     (%warn '|needs arguments| z))
   (mapc (function check-rhs-ce-var) (cdr z))) 
 
983cb74c
 ;;(defun check-remove (z) 					;original
 ;; (and (null (cdr z)) (%warn '|needs arguments| z))
 ;;(mapc (function check-rhs-ce-var) (cdr z))) 
5092d8a5
 
 (defun check-make (z)
   (when (null (cdr z))
     (%warn '|needs arguments| z))
   (check-change& (cdr z))) 
 
 (defun check-openfile (z)
   (when (null (cdr z))
     (%warn '|needs arguments| z))
   (check-change& (cdr z))) 
 
 (defun check-closefile (z)
   (when (null (cdr z))
     (%warn '|needs arguments| z))
   (check-change& (cdr z))) 
 
 (defun check-default (z)
   (when (null (cdr z))
     (%warn '|needs arguments| z))
   (check-change& (cdr z))) 
 
 (defun check-modify (z)
   (when (null (cdr z))
     (%warn '|needs arguments| z))
   (check-rhs-ce-var (cadr z))
   (when (null (cddr z))
     (%warn '|no changes to make| z))
   (check-change& (cddr z))) 
 
 (defun check-write (z)				;note this works w/write
   (when (null (cdr z))
     (%warn '|needs arguments| z))
   (check-change& (cdr z))) 
 
 (defun check-call (z)
   (when (null (cdr z))
     (%warn '|needs arguments| z))
   (let ((f (cadr z)))
     (when (variablep f)
       (%warn '|function name must be a constant| z))
     (unless (symbolp f)
       (%warn '|function name must be a symbolic atom| f))
     (unless (externalp f)
       (%warn '|function name not declared external| f))
     (check-change& (cddr z)))) 
 
 (defun check-halt (z)
   (unless (null (cdr z))
     (%warn '|does not take arguments| z))) 
 
 (defun check-cbind (z)
   (unless (= (length z) 2.)
     (%warn '|takes only one argument| z))
   (let ((v (cadr z)))
     (unless (variablep v)
       (%warn '|takes variable as argument| z))
     (note-ce-variable v))) 
 
 (defun check-bind (z)
   (unless (> (length z) 1.)
     (%warn '|needs arguments| z))
   (let ((v (cadr z)))
     (unless (variablep v)
       (%warn '|takes variable as argument| z))
     (note-variable v)
     (check-change& (cddr z)))) 
 
 (defun check-change& (z)
   (prog (r tab-flag)
983cb74c
      (setq tab-flag nil)
    la   (and (atom z) (return nil))
      (setq r (car z))
      (setq z (cdr z))
      (cond ((eq r '^)
             (and tab-flag
                  (%warn '|no value before this tab| (car z)))
             (setq tab-flag t)
             (check-tab-index (car z))
             (setq z (cdr z)))
            ((eq r '//) (setq tab-flag nil) (setq z (cdr z)))
            (t (setq tab-flag nil) (check-rhs-value r)))
      (go la))) 
5092d8a5
 
 (defun check-rhs-ce-var (v)
   (cond ((and (not (numberp v)) (not (ce-bound? v)))
983cb74c
          (%warn '|unbound element variable| v))
         ((and (numberp v) (or (< v 1.) (> v *ce-count*)))
          (%warn '|numeric element designator out of bounds| v)))) 
5092d8a5
 
 (defun check-rhs-value (x)
   (if (consp x)				;dtpr\consp gdw 
       (check-rhs-function x)
       (check-rhs-atomic x))) 
 
 (defun check-rhs-atomic (x)
   (when (and (variablep x) 
983cb74c
              (not (bound? x)))
5092d8a5
     (%warn '|unbound variable| x)))
 
 (defun check-rhs-function (x)
   (let ((a (car x)))
     (case a
       (compute (check-compute x))
       (arith (check-compute x))
       (substr (check-substr x))
       (accept (check-accept x))
       (acceptline (check-acceptline x))
       (crlf (check-crlf x))
       (genatom (check-genatom x))
       (litval (check-litval x))
       (tabto (check-tabto x))
       (rjust (check-rjust x))
       (otherwise 
        (when (not (externalp a))
983cb74c
          (%warn '"rhs function not declared external" a))))))
5092d8a5
 
 (defun externalp (x)
983cb74c
   ;;  (cond ((symbolp x) (gethash x *external-routine-table*)) 	;) @@@
   ;;ok, I'm eliminating this temporarily @@@@
5092d8a5
   (cond ((symbolp x) t)
983cb74c
         (t (%warn '|not a legal function name| x) nil)))
5092d8a5
 
 (defun check-litval (x) 
   (unless (= (length x) 2)
     (%warn '|wrong number of arguments| x))
   (check-rhs-atomic (cadr x)))
 
 (defun check-accept (x)
   (cond ((= (length x) 1) nil)
983cb74c
         ((= (length x) 2) (check-rhs-atomic (cadr x)))
         (t (%warn '|too many arguments| x))))
5092d8a5
 
 (defun check-acceptline (x)
   (mapc #'check-rhs-atomic (cdr x)))
 
 (defun check-crlf (x) 
   (check-0-args x)) 
 
 (defun check-genatom (x) (check-0-args x)) 
 
 (defun check-tabto (x)
   (unless (= (length x) 2)
     (%warn '|wrong number of arguments| x))
   (check-print-control (cadr x)))
 
 (defun check-rjust (x)
   (unless (= (length x) 2)
     (%warn '|wrong number of arguments| x))
   (check-print-control (cadr x)))
 
 (defun check-0-args (x)
   (unless (= (length x) 1.)
     (%warn '|should not have arguments| x))) 
 
 (defun check-substr (x)
   (unless (= (length x) 4.)
     (%warn '|wrong number of arguments| x))
   (check-rhs-ce-var (cadr x))
   (check-substr-index (caddr x))
   (check-last-substr-index (cadddr x))) 
 
 (defun check-compute (x) (check-arithmetic (cdr x))) 
 
 (defun check-arithmetic (l)
   (cond ((atom l)
983cb74c
          (%warn '|syntax error in arithmetic expression| l))
         ((atom (cdr l)) (check-term (car l)))
         ;; "plus" changed to "+" by gdw 
         ;; "quotient" added by mk, for backward compatability with the
         ;; old definition of //.
         ((not (member (cadr l) '(+ - * // \\ quotient)))	
          (%warn '|unknown operator| l))
         (t (check-term (car l)) (check-arithmetic (cddr l))))) 
5092d8a5
 
 (defun check-term (x)
   (if (consp x)				;dtpr\consp gdw
       (check-arithmetic x)
       (check-rhs-atomic x))) 
 
 (defun check-last-substr-index (x)
   (or (eq x 'inf) (check-substr-index x))) 
 
 (defun check-substr-index (x)
   (if (bound? x) x
       (let ((v ($litbind x)))
983cb74c
         (cond ((not (numberp v))
                (%warn '|unbound symbol used as index in substr| x))
               ((or (< v 1.) (> v 127.))
                (%warn '|index out of bounds in tab| x)))))) 
5092d8a5
 
 (defun check-print-control (x)
   (cond ((bound? x) x)
983cb74c
         ((or (not (numberp x)) (< x 1.) (> x 127.))
          (%warn '|illegal value for printer control| x)))) 
5092d8a5
 
 (defun check-tab-index (x)
   (if (bound? x) x
       (let ((v ($litbind x)))
983cb74c
         (cond ((not (numberp v))
                (%warn '|unbound symbol occurs after ^| x))
               ((or (< v 1.) (> v 127.))
                (%warn '|index out of bounds after ^| x)))))) 
5092d8a5
 
 (defun note-variable (var)
   (push var *rhs-bound-vars*))
 
 (defun bound? (var)
   (or (member var *rhs-bound-vars*)
       (var-dope var)))
 
 (defun note-ce-variable (ce-var)
   (push ce-var *rhs-bound-ce-vars*))
 
 (defun ce-bound? (ce-var)
   (or (member ce-var *rhs-bound-ce-vars*)
       (ce-var-dope ce-var)))
 
 ;;; *EOF*