/*-*-macsyma-*-*/ /* George Carrette, 2:35pm Thursday, 21 August 1980 */ /* A macro for defining substitution macros. */ EVAL_WHEN([TRANSLATE,BATCH,DEMO], IF GET('SHAREM,'VERSION) = FALSE THEN LOADFILE(AUTOLO,FASL,DSK,SHAREM))$ EVAL_WHEN(BATCH,TTYOFF:TRUE)$ /* e.g. DEFM(RECT_RULE('EXP,'X,A,B,DX), BLOCK([%_SUM:0.0], FOR X:A THRU B STEP DX DO %_SUM:%_SUM+EXP, %_SUM))$ defines a rectangle-rule numerical integration macro. The DEFM macro provides a more convenient interface to the usual tools of macro processing. The first argument definition gives the name of the macro and the formal parameters. The second gives a body into which the substitutions are made. The substitutions are made with the built-in macro BUILDQ. [1] If a formal parameter appears as 'FOO then the actual parameter is directly substituted for FOO. This is somewhat like the call-by-name semantics some languages have. [2] If the first two characters in the name of a symbol on the right is "%_" then when the macro defined expands, that symbol will be a unique generated symbol (GENSYM). This is used to avoid name conflicts with symbols in substituted expressions. This is remincent of algol 60. [3] If a formal parameter appears as FOO then the macro defined will assure that FOO will be the value of the actual parameter. e.g. DEFM(EXAMPLE(FOO),BAR(FOO,FOO)) is like DEFM(EXAMPLE(FOO),BLOCK([%_FOO:FOO],BAR(%_FOO,%_FOO))) note: that EXAMPLE(FOO):=BAR(FOO,FOO) a function call, has exactly the same evaluation semantics as EXAMPLE(FOO)=>BAR(FOO,FOO), however, in the macro case the code for EXAMPLE would be duplicated wherever there was a call to it, which may be bad if the code is large. This is sometimes know as "open compilations". Generated symbols are introduced to avoid name conflicts. */ HERALD_PACKAGE(DEFM)$ EVAL_WHEN([TRANSLATE],TRANSCOMPILE:TRUE, /* PACKAGEFILE:TRUE, bug in MEVAL makes this lose now. */ MODEDECLARE(FUNCTION(GETCHARN),FIXNUM, FUNCTION(SYMBOLP,GENSYM_CONVENTIONP),BOOLEAN))$ EVAL_WHEN(TRANSLATE,DECLARE(%_GENSYMS,SPECIAL))$ GENSYM_CONVENTIONP(X):= IF (SYMBOLP(X) AND NOT(MEMBER(X,%_GENSYMS)) AND GETCHAR(X,1)='% AND GETCHAR(X,2)='_) THEN PUSH(X,%_GENSYMS)$ %_CHECK(EXP):= /* This give a syntactic coverage of the "variables" in the code, not a semantic one. The BUILDQ macro which does the substitution is similarly non-semantic */ IF ATOM(EXP) THEN GENSYM_CONVENTIONP(EXP) ELSE (%_CHECK(PART(EXP,0)), FOR EXP IN ARGS(EXP) DO(%_CHECK(EXP)))$ %_GENSYMS(EXP):=BLOCK([%_GENSYMS:[]],%_CHECK(EXP),%_GENSYMS)$ DEFM(HEADER,BODY)::= BLOCK([BUILD_SUBST:[], /* the subsitutions the buildq will make */ EVAL_ONCE:[], /* From unquoted arguments. */ FORMAL_ARGS:[] ], /* Of the constructed macro. */ FOR U IN %_GENSYMS(BODY) DO PUSH(BUILDQ([U],U:?GENSYM()),BUILD_SUBST), FOR ARG IN ARGS(HEADER) DO(IF ATOM(ARG) /* F(X)=>BAR(X) is F(G001)::=BUILDQ([G001,X:?GENSYM()],BLOCK([X:G001],BODY)) */ THEN BLOCK([G:?GENSYM()], PUSH(G,FORMAL_ARGS), PUSH(G,BUILD_SUBST), PUSH(BUILDQ([ARG],ARG:?GENSYM()),BUILD_SUBST), PUSH(BUILDQ([ARG,G],ARG:G),EVAL_ONCE)) ELSE IF PART(ARG,0)="'" THEN (ARG:PART(ARG,1), PUSH(ARG,BUILD_SUBST), PUSH(ARG,FORMAL_ARGS)) ELSE ERROR("Bad formal arg to DEFM",ARG)), FORMAL_ARGS:REVERSE(FORMAL_ARGS), EVAL_ONCE:REVERSE(EVAL_ONCE), /* preserve order of evaluation. */ BUILDQ([FORMAL_ARGS,EVAL_ONCE,BUILD_SUBST,NAME:PART(HEADER,0),BODY], NAME(SPLICE(FORMAL_ARGS))::= BUILDQ(BUILD_SUBST, BLOCK(EVAL_ONCE,BODY))))$ /* Define an optional syntax for DEFM. */ /* := 180 ANY 20 ANY ANY INFIX(operator, lbp[180], rbp[180], lpos[ANY], rpos[ANY],pos[ANY]) */ EVAL_WHEN([TRANSLATE,BATCH,DEMO], INFIX("=>",180,20), "=>"(X,Y)::=BUILDQ([X,Y],DEFM(X,Y)))$ EVAL_WHEN([TRANSLATE], TRANSLATE("=>"), /* Yes Virginia, good lisp is reentrant. */ /* This hack deflects the syntax to another file */ SAVE([DEFM,SYNTAX,DSK,SHAREM],"=>"))$ /* By default, don't load syntax. EVAL_WHEN([LOADFILE], /* This is evaluated once we are translated and then loaded. */ LOADFILE(DEFM,SYNTAX,DSK,SHAREM))$ */ EVAL_WHEN(DEMO, RECT_RULE('EXP,'X,A,B,DX)=>BLOCK([%_SUM:0.0], FOR X:A THRU B STEP DX DO %_SUM:%_SUM+EXP, %_SUM)); EVAL_WHEN(DEMO,MACROEXPAND(RECT_RULE(X^3*A,X,A^2,A*B^2,0.5))); EVAL_WHEN(BATCH,TTYOFF:FALSE)$