;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; The data in this file contains enhancments. ;;;;; ;;; ;;;;; ;;; Copyright (c) 1984,1987 by William Schelter,University of Texas ;;;;; ;;; All rights reserved ;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; (c) Copyright 1980 Massachusetts Institute of Technology ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (in-package "MAXIMA") (macsyma-module buildq) ; Exported functions are $BUILDQ and MBUILDQ-SUBST ; TRANSLATION property for $BUILDQ in MAXSRC;TRANS5 > ;************************************************************************** ;****** ****** ;****** BUILDQ: A backquote-like construct for Macsyma ****** ;****** ****** ;************************************************************************** ;DESCRIPTION: ; Syntax: ; BUILDQ([],); ; is any single macsyma expression ; is a list of elements of the form or : ; Semantics: ; the s in the are evaluated left to right (the syntax ; is equivalent to :). then these values are substituted ; into in parallel. If any appears as a single ; argument to the special form SPLICE (i.e. SPLICE() ) inside ; , then the value associated with that must be a macsyma ; list, and it is spliced into instead of substituted. ;SIMPLIFICATION: ; the arguments to $BUILDQ need to be protected from simplification until ; the substitutions have been carried out. This code should affect that. (DEFPROP $BUILDQ SIMPBUILDQ OPERATORS) (DEFPROP %BUILDQ SIMPBUILDQ OPERATORS) ; This is modeled after SIMPMDEF, SIMPLAMBDA etc. in JM;SIMP > (DEFUN SIMPBUILDQ (X *IGNORE* SIMP-FLAGS) *IGNORE* ; no simplification takes place. SIMP-FLAGS ; ditto. (CONS '($BUILDQ SIMP) (CDR X))) ; Note that supression of simplification is very important to the semantics ; of BUILDQ. Consider BUILDQ([A:'[B,C,D]],SPLICE(A)+SPLICE(A)); ; If no simplification takes place, $BUILDQ returns B+C+D+B+C+D. ; If the expression is simplified into 2*SPLICE(A), then 2*B*C*D results. ;INTERPRETIVE CODE: (DEFMSPEC $BUILDQ (FORM) (SETQ FORM (CDR FORM)) (COND ((OR (NULL (CDR FORM)) (CDDR FORM)) (MERROR "BUILDQ takes 2 args:~%~M" `(($BUILDQ) ,@FORM))) (T (MBUILDQ (CAR FORM) (CADR FORM))))) ; this macro definition is NOT equivalent because of the way lisp macros ; are currently handled in the macsyma interpreter. When the subr form ; is returned the arguments get MEVAL'd (and hence simplified) before ; we get ahold of them. ; Lisp MACROS, and Lisp FEXPR's are meaningless to the macsyma evaluator ; and should be ignored, the proper things to use are MFEXPR* and ; MMACRO properties. -GJC ;(DEFMACRO ($BUILDQ DEFMACRO-FOR-COMPILING T) ; (VARLIST . EXPRESSIONS) ; (COND ((OR (NULL VARLIST) ; (NULL EXPRESSIONS) ; (CDR EXPRESSIONS)) ; (DISPLA `(($BUILDQ) ,VARLIST ,@EXPRESSIONS)) ; (MERROR "BUILDQ takes 2 args")) ; (T `(MBUILDQ ',VARLIST ',(CAR EXPRESSIONS))))) (DEFUN MBUILDQ (VARLIST EXPRESSION) (COND ((NOT ($LISTP VARLIST)) (MERROR "First arg to BUILDQ not a list: ~M" VARLIST))) (MBUILDQ-SUBST (MAPCAR #'(LAMBDA (FORM) ; make a variable/value alist (COND ((SYMBOLP FORM) (CONS FORM (MEVAL FORM))) ((AND (EQ (CAAR FORM) 'MSETQ) (SYMBOLP (CADR FORM))) (CONS (CADR FORM) (MEVAL (CADDR FORM)))) (T (MERROR "Illegal form in variable list--BUILDQ: ~M" FORM )))) (CDR VARLIST)) EXPRESSION)) ; this performs the substitutions for the variables in the expressions. ; it tries to be smart and only copy what list structure it has to. ; the first arg is an alist of pairs: ( . ) ; the second arg is the macsyma expression to substitute into. (DEFMFUN MBUILDQ-SUBST (ALIST EXPRESSION) (PROG (NEW-CAR) (COND ((ATOM EXPRESSION) (RETURN (MBUILDQ-ASSOCIATE EXPRESSION ALIST))) ((ATOM (CAR EXPRESSION)) (SETQ NEW-CAR (MBUILDQ-ASSOCIATE (CAR EXPRESSION) ALIST))) ((MBUILDQ-SPLICE-ASSOCIATE EXPRESSION ALIST) ; if the expression is a legal SPLICE, this clause is taken. ; a SPLICE should never occur here. It corresponds to `,@form (MERROR "SPLICE used in illegal context: ~M" EXPRESSION)) ((ATOM (CAAR EXPRESSION)) (SETQ NEW-CAR (MBUILDQ-ASSOCIATE (CAAR EXPRESSION) ALIST)) (COND ((EQ NEW-CAR (CAAR EXPRESSION)) (SETQ NEW-CAR (CAR EXPRESSION))) ((ATOM NEW-CAR) (SETQ NEW-CAR (CONS NEW-CAR (CDAR EXPRESSION)))) (T (RETURN `(,(CONS 'MQAPPLY (CDAR EXPRESSION)) ,NEW-CAR ,@(MBUILDQ-SUBST ALIST (CDR EXPRESSION))))))) ((SETQ NEW-CAR (MBUILDQ-SPLICE-ASSOCIATE (CAR EXPRESSION) ALIST)) (RETURN (APPEND (CDR NEW-CAR) (MBUILDQ-SUBST ALIST (CDR EXPRESSION))))) (T (SETQ NEW-CAR (MBUILDQ-SUBST ALIST (CAR EXPRESSION))))) (RETURN (LET ((NEW-CDR (MBUILDQ-SUBST ALIST (CDR EXPRESSION)))) (COND ((AND (EQ NEW-CAR (CAR EXPRESSION)) (EQ NEW-CDR (CDR EXPRESSION))) EXPRESSION) (T (CONS NEW-CAR NEW-CDR))))))) ; this function returns the appropriate thing to substitute for an atom ; appearing inside a backquote. If it's not in the varlist, it's the ; atom itself. (DEFUN MBUILDQ-ASSOCIATE (ATOM ALIST) (LET ((FORM)) (COND ((NOT (SYMBOLP ATOM)) ATOM) ((SETQ FORM (ASSQ ATOM ALIST)) (CDR FORM)) ((SETQ FORM (ASSQ ($VERBIFY ATOM) ALIST)) ;trying to match a nounified substitution variable (COND ((ATOM (CDR FORM)) ($NOUNIFY (CDR FORM))) ((MEMQ (CAAR (CDR FORM)) '(MQUOTE MLIST MPROG MPROGN LAMBDA)) ;list gotten from the parser. `((MQUOTE) ,(CDR FORM))) (T `( (,($NOUNIFY (CAAR (CDR FORM))) ,@(CDAR (CDR FORM))) ,@(CDR (CDR FORM)))))) ;; (( ...) ...) ==> (( ...) ...) (T ATOM)))) ;; give it a property so it is known as special for bothcases (setf (get '$splice '$bothcases) t) ; this function decides whether the SPLICE is one of ours or not. ; the basic philosophy is that the SPLICE is ours if it has exactly ; one symbolic argument and that arg appears in the current varlist. ; if it's one of ours, this function returns the list it's bound to. ; otherwise it returns nil. Notice that the list returned is an ; MLIST and hence the cdr of the return value is what gets spliced in. (DEFUN MBUILDQ-SPLICE-ASSOCIATE (EXPRESSION VARLIST) (AND (EQ (CAAR EXPRESSION) '$SPLICE) (CDR EXPRESSION) (NULL (CDDR EXPRESSION)) (LET ((MATCH (ASSQ (CADR EXPRESSION) VARLIST))) (COND ((NULL MATCH) () ) ((NOT ($LISTP (CDR MATCH))) (MERROR "~M returned ~M~%But SPLICE must return a list" EXPRESSION (CDR MATCH))) (T (CDR MATCH))))))