home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / D / CLISP / CLISPSRC.TAR / clisp-1995-01-01 / src / control.d < prev    next >
Encoding:
Text File  |  1994-12-06  |  96.6 KB  |  2,352 lines

  1. # Special-Forms, Kontrollstrukturen, Evaluator-Nahes fⁿr CLISP
  2. # Bruno Haible 6.12.1994
  3.  
  4. #include "lispbibl.c"
  5.  
  6.  
  7. LISPFUN(exit,0,1,norest,nokey,0,NIL)
  8. # (SYSTEM::%EXIT [errorp]) verlΣ▀t das System
  9.   { var reg1 object errorp = STACK_0;
  10.     final_exitcode = ((eq(errorp,unbound) || nullp(errorp)) ? 0 : 1);
  11.     quit();
  12.   }
  13.  
  14. LISPSPECFORM(eval_when, 1,0,body)
  15. # (EVAL-WHEN ({situation}) {form}), CLTL S. 69
  16.   { var reg1 object situations = STACK_1; # Liste der Situationen
  17.     # Symbol EVAL oder Liste (NOT COMPILE) darin suchen:
  18.     while (consp(situations))
  19.       { var reg2 object situation = Car(situations);
  20.         if (eq(situation,S(eval))) # Symbol EVAL gefunden?
  21.           goto found;
  22.         if (consp(situation) && eq(Car(situation),S(not)))
  23.           { situation = Cdr(situation);
  24.             if (consp(situation) && nullp(Cdr(situation))
  25.                 && eq(Car(situation),S(compile)) # Liste (NOT COMPILE) gefunden?
  26.                )
  27.               goto found;
  28.           }
  29.         situations = Cdr(situations);
  30.       }
  31.     # Symbol EVAL nicht gefunden
  32.     value1 = NIL; mv_count=1; # Wert NIL
  33.     skipSTACK(2);
  34.     return;
  35.     found: # Symbol EVAL gefunden
  36.    {var reg2 object body = popSTACK();
  37.     skipSTACK(1);
  38.     implicit_progn(body,NIL); # body auswerten
  39.     return;
  40.   }}
  41.  
  42. LISPSPECFORM(quote, 1,0,nobody)
  43. # (QUOTE object) == 'object, CLTL S. 86
  44.   { value1 = popSTACK(); mv_count=1; } # Argument als Wert
  45.  
  46. # Fehlermeldung bei FUNCTION/FLET/LABELS, wenn kein Funktionssymbol vorliegt.
  47. # > caller: Aufrufer, ein Symbol
  48. # > obj: fehlerhaftes Funktionssymbol
  49.   nonreturning_function(local, fehler_funsymbol, (object caller, object obj));
  50.   local void fehler_funsymbol(caller,obj)
  51.     var reg2 object caller;
  52.     var reg1 object obj;
  53.     { pushSTACK(obj);
  54.       pushSTACK(caller);
  55.       fehler(program_error,
  56.              DEUTSCH ? "~: Funktionsname ~ ist kein Symbol." :
  57.              ENGLISH ? "~: function name ~ should be a symbol" :
  58.              FRANCAIS ? "~: Le nom de fonction ~ n'est pas un symb⌠le." :
  59.              ""
  60.             );
  61.     }
  62.  
  63. LISPSPECFORM(function, 1,1,nobody)
  64. # (FUNCTION funname), CLTL. S. 87
  65. # entweder (FUNCTION symbol)
  66. #     oder (FUNCTION (LAMBDA . lambdabody))
  67. #     oder (FUNCTION name (LAMBDA . lambdabody))
  68.   { var reg1 object funname; # Funktionsname (Symbol oder Lambdabody)
  69.     var reg2 object name; # Name (Symbol)
  70.     if (eq(STACK_0,unbound))
  71.       # 1 Argument
  72.       { funname = STACK_1;
  73.         if (funnamep(funname))
  74.           # (FUNCTION symbol) - Syntax
  75.           { # Symbol im aktuellen Funktions-Environment suchen:
  76.             var reg3 object fun = sym_function(funname,aktenv.fun_env);
  77.             # SUBR oder Closure zurⁿckgeben, sonst Fehler:
  78.             if (!(subrp(fun) || closurep(fun)))
  79.               { pushSTACK(funname); # Wert fⁿr Slot NAME von CELL-ERROR
  80.                 pushSTACK(funname);
  81.                 pushSTACK(S(function));
  82.                 fehler(undefined_function,
  83.                        DEUTSCH ? "~: Die Funktion ~ ist nicht definiert." :
  84.                        ENGLISH ? "~: undefined function ~" :
  85.                        FRANCAIS ? "~: La fonction ~ n'est pas dΘfinie." :
  86.                        ""
  87.                       );
  88.               }
  89.             value1 = fun; mv_count=1; skipSTACK(2); return;
  90.           }
  91.         name = S(Klambda); # :LAMBDA als Default-Name
  92.       }
  93.       else
  94.       # 2 Argumente
  95.       { name = STACK_1; # 1. Argument
  96.         if (!funnamep(name)) { fehler_funsymbol(S(function),name); }
  97.         funname = STACK_0; # 2. Argument, hoffentlich Lambdaausdruck
  98.       }
  99.     if (!(consp(funname) && eq(Car(funname),S(lambda)))) # Cons (LAMBDA . ...) ?
  100.       { pushSTACK(funname);
  101.         pushSTACK(S(function));
  102.         fehler(program_error,
  103.                DEUTSCH ? "~: ~ ist keine Funktionsbezeichnung." :
  104.                ENGLISH ? "~: ~ is not a function name" :
  105.                FRANCAIS ? "~: ~ n'est pas un nom de fonction." :
  106.                ""
  107.               );
  108.       }
  109.     # Lambdaausdruck
  110.     # im aktuellen Environment in eine Closure umwandeln:
  111.     value1 = get_closure(Cdr(funname),name,&aktenv); mv_count=1;
  112.     skipSTACK(2); return;
  113.   }
  114.  
  115. LISPFUNN(symbol_value,1)
  116. # (SYMBOL-VALUE symbol), CLTL S. 90
  117.   { var reg1 object symbol = popSTACK();
  118.     if (!symbolp(symbol)) { fehler_symbol(symbol); }
  119.    {var reg2 object val = Symbol_value(symbol);
  120.     if (eq(val,unbound))
  121.       { pushSTACK(symbol); # Wert fⁿr Slot NAME von CELL-ERROR
  122.         pushSTACK(symbol);
  123.         pushSTACK(S(symbol_value));
  124.         fehler(unbound_variable,
  125.                DEUTSCH ? "~: ~ hat keinen dynamischen Wert." :
  126.                ENGLISH ? "~: ~ has no dynamic value" :
  127.                FRANCAIS ? "~: ~ n'a pas de valeur dynamique." :
  128.                ""
  129.               );
  130.       }
  131.     value1 = val; mv_count=1;
  132.   }}
  133.  
  134. # Fehlermeldung wegen undefinierter Funktion.
  135. # fehler_undef_function(caller,symbol);
  136. # > caller: Aufrufer (ein Symbol)
  137. # > symbol: Symbol oder (SETF symbol)
  138.   nonreturning_function(global, fehler_undef_function, (object caller, object symbol));
  139.   global void fehler_undef_function(caller,symbol)
  140.     var reg2 object caller;
  141.     var reg1 object symbol;
  142.     { pushSTACK(symbol); # Wert fⁿr Slot NAME von CELL-ERROR
  143.       pushSTACK(symbol);
  144.       pushSTACK(caller);
  145.       fehler(undefined_function,
  146.              DEUTSCH ? "~: ~ hat keine globale Funktionsdefinition." :
  147.              ENGLISH ? "~: ~ has no global function definition" :
  148.              FRANCAIS ? "~: ~ n'as pas de dΘfinition de fonction globale." :
  149.              ""
  150.             );
  151.     }
  152.  
  153. LISPFUNN(symbol_function,1)
  154. # (SYMBOL-FUNCTION symbol), CLTL S. 90
  155.   { var reg1 object symbol = popSTACK();
  156.     if (!symbolp(symbol)) { fehler_symbol(symbol); }
  157.    {var reg2 object val = Symbol_function(symbol);
  158.     if (eq(val,unbound)) { fehler_undef_function(S(symbol_value),symbol); }
  159.     value1 = val; mv_count=1;
  160.   }}
  161.  
  162. LISPFUNN(fdefinition,1)
  163. # (FDEFINITION funname), CLTL2 S. 120
  164.   { var reg3 object funname = popSTACK();
  165.     var reg1 object symbol = funname;
  166.     if (!funnamep(symbol)) { fehler_symbol(symbol); }
  167.     if (!symbolp(symbol))
  168.       { symbol = get(Car(Cdr(symbol)),S(setf_function)); # (get ... 'SYS::SETF-FUNCTION)
  169.         if (!symbolp(symbol)) # sollte (uninterniertes) Symbol sein
  170.           { fehler_undef_function(S(fdefinition),funname); } # sonst undefiniert
  171.       }
  172.    {var reg2 object val = Symbol_function(symbol);
  173.     if (eq(val,unbound))
  174.       { fehler_undef_function(S(fdefinition),funname); }
  175.     value1 = val; mv_count=1;
  176.   }}
  177.  
  178. LISPFUNN(boundp,1)
  179. # (BOUNDP symbol), CLTL S. 90
  180.   { var reg1 object symbol = popSTACK();
  181.     if (!symbolp(symbol)) { fehler_symbol(symbol); }
  182.     value1 = (eq(Symbol_value(symbol),unbound) ? NIL : T); mv_count=1;
  183.   }
  184.  
  185. LISPFUNN(fboundp,1)
  186. # (FBOUNDP symbol), CLTL S. 90, CLTL2 S. 120
  187.   { var reg1 object symbol = popSTACK();
  188.     if (!funnamep(symbol)) { fehler_symbol(symbol); }
  189.     if (!symbolp(symbol))
  190.       { symbol = get(Car(Cdr(symbol)),S(setf_function)); # (get ... 'SYS::SETF-FUNCTION)
  191.         if (!symbolp(symbol)) # sollte (uninterniertes) Symbol sein
  192.           goto undef; # sonst undefiniert
  193.       }
  194.     if (eq(Symbol_function(symbol),unbound))
  195.       { undef: value1 = NIL; }
  196.       else
  197.       { value1 = T; }
  198.     mv_count=1;
  199.   }
  200.  
  201. LISPFUNN(special_form_p,1)
  202. # (SPECIAL-FORM-P symbol), CLTL S. 91
  203.   { var reg1 object symbol = popSTACK();
  204.     if (!symbolp(symbol)) { fehler_symbol(symbol); }
  205.    {var reg2 object obj = Symbol_function(symbol);
  206.     value1 = (fsubrp(obj) ? T : NIL); mv_count=1;
  207.   }}
  208.  
  209. # Fehlermeldung bei Zuweisung, wenn ein Symbol eine Konstante ist.
  210. # (Einer Konstante kann nicht zugewiesen werden.)
  211. # fehler_symbol_constant(caller,symbol);
  212. # > caller: Aufrufer (ein Symbol)
  213. # > symbol: konstantes Symbol
  214.   nonreturning_function(local, fehler_symbol_constant, (object caller, object symbol));
  215.   local void fehler_symbol_constant(caller,symbol)
  216.     var reg2 object caller;
  217.     var reg1 object symbol;
  218.     { pushSTACK(symbol);
  219.       pushSTACK(caller);
  220.       fehler(error,
  221.              DEUTSCH ? "~: Der Konstanten ~ kann kein Wert zugewiesen werden." :
  222.              ENGLISH ? "~: the value of the constant ~ may not be altered" :
  223.              FRANCAIS ? "~: Aucune valeur ne peut Ωtre assignΘe α la constante ~." :
  224.              ""
  225.             );
  226.     }
  227.  
  228. # UP: ⁿberprⁿft den Body einer SETQ- oder PSETQ-Form.
  229. # > caller: Aufrufer (ein Symbol)
  230. # > STACK_0: Body
  231. # < ergebnis: TRUE falls Symbol-Macros zu expandieren sind.
  232.   local boolean check_setq_body (object caller);
  233.   local boolean check_setq_body(caller)
  234.     var reg3 object caller;
  235.     { var reg1 object body = STACK_0;
  236.       while (consp(body))
  237.         { var reg2 object symbol = Car(body); # Variable
  238.           if (!symbolp(symbol)) { fehler_kein_symbol(caller,symbol); }
  239.           if (constantp(TheSymbol(symbol)))
  240.             { fehler_symbol_constant(caller,symbol); }
  241.           if (sym_macrop(symbol))
  242.             { return TRUE; }
  243.           body = Cdr(body);
  244.           if (atomp(body))
  245.             { if (!nullp(body)) goto fehler_dotted;
  246.               # Der ganze Body noch in STACK_0.
  247.               pushSTACK(caller);
  248.               fehler(program_error,
  249.                      DEUTSCH ? "~ mit ungerader Anzahl von Argumenten: ~" :
  250.                      ENGLISH ? "~ called with odd number of arguments: ~" :
  251.                      FRANCAIS ? "~ appelΘ avec un nombre impair d'arguments : ~" :
  252.                      ""
  253.                     );
  254.             }
  255.           body = Cdr(body);
  256.         }
  257.       # body ist zu Ende.
  258.       if (!nullp(body))
  259.         { fehler_dotted: # Der ganze Body noch in STACK_0.
  260.           pushSTACK(caller);
  261.           fehler(program_error,
  262.                  DEUTSCH ? "Dotted List als Argumentliste an ~ : ~" :
  263.                  ENGLISH ? "dotted list given to ~ : ~" :
  264.                  FRANCAIS ? "Liste pointΘe d'arguments fournie α ~ : ~" :
  265.                  ""
  266.                 );
  267.         }
  268.       return FALSE;
  269.     }
  270.  
  271. LISPSPECFORM(setq, 0,0,body)
  272. # (SETQ {var form}), CLTL S. 91
  273.   { if (check_setq_body(S(setq)))
  274.       { var reg1 object form = allocate_cons();
  275.         Car(form) = S(setf); Cdr(form) = popSTACK(); # aus SETQ mache SETF
  276.         eval(form);
  277.       }
  278.       else
  279.       { var reg1 object body = popSTACK();
  280.         if (consp(body))
  281.           { do { var reg2 object symbol = Car(body); # Variable
  282.                  body = Cdr(body);
  283.                  pushSTACK(Cdr(body)); # Restliste retten
  284.                  pushSTACK(symbol); # Symbol retten
  285.                  eval(Car(body)); # nΣchste Form auswerten
  286.                  symbol = popSTACK();
  287.                  setq(symbol,value1); # Zuweisung durchfⁿhren
  288.                  body = popSTACK();
  289.                }
  290.                while (consp(body));
  291.             # value1 ist noch das letzte Auswertungs-Ergebnis.
  292.           }
  293.           else
  294.           { value1 = NIL; } # Defaultwert bei (SETQ)
  295.         mv_count=1;
  296.   }   }
  297.  
  298. LISPSPECFORM(psetq, 0,0,body)
  299. # (PSETQ {var form}), CLTL S. 92
  300.   { if (check_setq_body(S(psetq)))
  301.       { var reg1 object form = allocate_cons();
  302.         Car(form) = S(psetf); Cdr(form) = popSTACK(); # aus PSETQ mache PSETF
  303.         eval(form);
  304.       }
  305.       else
  306.       { var reg1 object body = popSTACK();
  307.         var reg4 uintL body_length = llength(body)/2; # Anzahl der Paare (var form)
  308.         get_space_on_STACK(body_length*2*sizeof(object)); # Platz im STACK belegen
  309.         { var reg2 uintL count;
  310.           dotimesL(count,body_length,
  311.             { pushSTACK(Car(body)); # Variable auf den Stack
  312.               body = Cdr(body);
  313.               pushSTACK(Cdr(body)); # Restliche Liste auf den Stack
  314.               eval(Car(body)); # nΣchste Form auswerten
  315.               body = STACK_0;
  316.               STACK_0 = value1; # ihr Ergebnis in den Stack
  317.             });
  318.         }
  319.         { var reg3 uintL count;
  320.           dotimesL(count,body_length,
  321.             { var reg2 object val = popSTACK(); # Wert
  322.               var reg1 object sym = popSTACK(); # Symbol
  323.               setq(sym,val); # Zuweisung durchfⁿhren
  324.             });
  325.         }
  326.         value1 = NIL; mv_count=1; # Wert NIL
  327.   }   }
  328.  
  329. LISPFUNN(set,2)
  330. # (SET symbol value), CLTL S. 92
  331.   { var reg1 object symbol = STACK_1;
  332.     if (!symbolp(symbol)) { fehler_symbol(symbol); }
  333.     if (constantp(TheSymbol(symbol)))
  334.       { fehler_symbol_constant(S(set),symbol); }
  335.     value1 = Symbol_value(symbol) = STACK_0; mv_count=1;
  336.     skipSTACK(2);
  337.   }
  338.  
  339. LISPFUNN(makunbound,1)
  340. # (MAKUNBOUND symbol), CLTL S. 92
  341.   { var reg1 object symbol = popSTACK();
  342.     if (!symbolp(symbol)) { fehler_symbol(symbol); }
  343.     if (constantp(TheSymbol(symbol)))
  344.       { pushSTACK(symbol);
  345.         pushSTACK(S(makunbound));
  346.         fehler(error,
  347.                DEUTSCH ? "~: Der Wert der Konstanten ~ mu▀ erhalten bleiben." :
  348.                ENGLISH ? "~: the value of the constant ~ must not be removed" :
  349.                FRANCAIS ? "~: La valeur de la constante ~ doit Ωtre conservΘe." :
  350.                ""
  351.               );
  352.       }
  353.     Symbol_value(symbol) = unbound;
  354.     value1 = symbol; mv_count=1;
  355.   }
  356.  
  357. LISPFUNN(fmakunbound,1)
  358. # (FMAKUNBOUND symbol), CLTL S. 92, CLTL2 S. 123
  359.   { var reg3 object funname = popSTACK();
  360.     var reg1 object symbol = funname;
  361.     if (!funnamep(symbol)) { fehler_symbol(symbol); }
  362.     if (!symbolp(symbol))
  363.       { symbol = get(Car(Cdr(symbol)),S(setf_function)); # (get ... 'SYS::SETF-FUNCTION)
  364.         if (!symbolp(symbol)) # sollte (uninterniertes) Symbol sein
  365.           goto undef; # sonst undefiniert
  366.       }
  367.     { var reg2 object obj = Symbol_function(symbol);
  368.       if (fsubrp(obj))
  369.         { pushSTACK(symbol);
  370.           pushSTACK(S(fmakunbound));
  371.           fehler(error,
  372.                  DEUTSCH ? "~: Definition der Spezialform ~ darf nicht gel÷scht werden." :
  373.                  ENGLISH ? "~: the special form definition of ~ must not be removed" :
  374.                  FRANCAIS ? "~: La dΘfinition de la forme spΘciale ~ doit Ωtre conservΘe." :
  375.                  ""
  376.                 );
  377.     }   }
  378.     Symbol_function(symbol) = unbound;
  379.     undef: value1 = funname; mv_count=1;
  380.   }
  381.  
  382. LISPFUN(apply,2,0,rest,nokey,0,NIL)
  383. # (APPLY function {arg} arglist), CLTL S. 107
  384.   { BEFORE(rest_args_pointer);
  385.     apply(Before(rest_args_pointer), # function
  386.           argcount, # Anzahl der {arg} auf dem Stack
  387.           popSTACK() # arglist
  388.          );
  389.     skipSTACK(1); # function aus dem Stack entfernen
  390.   }
  391.  
  392. LISPFUN(pfuncall,1,0,rest,nokey,0,NIL)
  393. # (SYS::%FUNCALL function {arg})
  394.   { funcall(Before(rest_args_pointer),argcount); skipSTACK(1); }
  395.  
  396. LISPFUN(funcall,1,0,rest,nokey,0,NIL)
  397. # (FUNCALL function {arg}), CLTL S. 108
  398.   { funcall(Before(rest_args_pointer),argcount); skipSTACK(1); }
  399.  
  400. LISPSPECFORM(progn, 0,0,body)
  401. # (PROGN {form}), CLTL S. 109
  402.   { implicit_progn(popSTACK(),NIL); }
  403.  
  404. # Macro: Wertet die Formen einer Formenliste aus.
  405. # implicit_prog();
  406. # > -(STACK): Formenliste
  407. # erh÷ht STACK um 1
  408. # kann GC ausl÷sen
  409.   #define implicit_prog()  \
  410.     { while (mconsp(STACK_0))                         \
  411.         { var reg1 object forms = STACK_0;            \
  412.           STACK_0 = Cdr(forms);                       \
  413.           eval(Car(forms)); # nΣchste Form evaluieren \
  414.         }                                             \
  415.       skipSTACK(1);                                   \
  416.     }
  417.  
  418. LISPSPECFORM(prog1, 1,0,body)
  419. # (PROG1 form1 {form}), CLTL S. 109
  420.   { STACK_1 = (eval(STACK_1),value1); # form1 evaluieren, Wert retten
  421.     implicit_prog();
  422.     value1 = popSTACK(); mv_count=1; # geretteten Wert zurⁿckgeben
  423.   }
  424.  
  425. LISPSPECFORM(prog2, 2,0,body)
  426. # (PROG2 form1 form2 {form}), CLTL S. 109
  427.   { eval(STACK_2); # form1 evaluieren
  428.     eval(STACK_1); STACK_2 = value1; # form2 evaluieren, Wert retten
  429.     STACK_1 = STACK_0; skipSTACK(1);
  430.     implicit_prog();
  431.     value1 = popSTACK(); mv_count=1; # geretteten Wert zurⁿckgeben
  432.   }
  433.  
  434. # Fehlermeldung wegen nicht erlaubter Docstrings
  435. # fehler_docstring(caller,body);
  436. # > caller: Aufrufer, ein Symbol
  437. # > body: gesamter Body
  438.   nonreturning_function(local, fehler_docstring, (object caller, object body));
  439.   local void fehler_docstring(caller,body)
  440.     var reg1 object caller;
  441.     var reg2 object body;
  442.     { pushSTACK(body);
  443.       pushSTACK(caller);
  444.       fehler(program_error,
  445.              DEUTSCH ? "~: Doc-Strings sind nicht hier erlaubt: ~" :
  446.              ENGLISH ? "~: doc-strings are not allowed here: ~" :
  447.              FRANCAIS ? "~: Une chaεne de documentation n'est pas permise ici : ~" :
  448.              ""
  449.             );
  450.     }
  451.  
  452. # UP fⁿr LET, LET*, LOCALLY, MULTIPLE-VALUE-BIND, SYMBOL-MACROLET:
  453. # Kompiliert die aktuelle Form und fⁿhrt sie in kompiliertem Zustand aus.
  454. # compile_form()
  455. # > im STACK: EVAL-Frame mit der Form
  456. # < mv_count/mv_space: Werte
  457. # kann GC ausl÷sen
  458.   local Values compile_eval_form (void);
  459.   local Values compile_eval_form()
  460.     { # (SYS::COMPILE-FORM form venv fenv benv genv denv) ausfⁿhren:
  461.       # Die ganze Form aus dem EVAL-Frame im Stack holen:
  462.       pushSTACK(STACK_(frame_form)); # als 1. Argument
  463.      {var reg1 environment* stack_env = nest_aktenv(); # aktuelles Environment nesten, auf den STACK legen
  464.       #if !defined(STACK_UP)
  465.       var environment my_env;
  466.       my_env = *stack_env; # und hierher ⁿbertragen
  467.       skipSTACK(5); # und wieder vom STACK nehmen
  468.       pushSTACK(my_env.var_env); # 2. Argument
  469.       pushSTACK(my_env.fun_env); # 3. Argument
  470.       pushSTACK(my_env.block_env); # 4. Argument
  471.       pushSTACK(my_env.go_env); # 5. Argument
  472.       pushSTACK(my_env.decl_env); # 6. Argument
  473.       #endif
  474.       funcall(S(compile_form),6);
  475.      }# Die sich ergebende compilierte Closure mit 0 Argumenten aufrufen:
  476.       funcall(value1,0);
  477.     }
  478.  
  479. # UP fⁿr LET, LET*, LOCALLY, MULTIPLE-VALUE-BIND, SYMBOL-MACROLET:
  480. # Analysiert die Variablen und Deklarationen, baut einen Variablenbindungs-
  481. # Frame auf und erweitert VENV und evtl. auch DENV durch einen Frame.
  482. # make_variable_frame(caller,varspecs,&bind_ptr,&bind_count)
  483. # > object caller: Aufrufer, ein Symbol
  484. # > object varspecs: Liste von Variablen-Specifiern
  485. # > object value2: Liste von Declaration-Specifiern
  486. # > object value1: Liste ({form}) von Formen
  487. # < Stackaufbau: Variablenbindungsframe, Env-Bindungs-Frame, ({form}).
  488. # < object* bind_ptr: Pointer ⁿber die erste "richtige" Bindung.
  489. # < uintC bind_count: Anzahl der "richtigen" Bindungen.
  490. # verΣndert STACK
  491. # kann GC ausl÷sen
  492.   local void make_variable_frame (object caller, object varspecs, object** bind_ptr_, uintC* bind_count_);
  493.   local void make_variable_frame(caller,varspecs,bind_ptr_,bind_count_)
  494.     var reg10 object caller;
  495.     var reg10 object varspecs;
  496.     var reg10 object** bind_ptr_;
  497.     var reg10 uintC* bind_count_;
  498.     { var reg10 object declarations = value2;
  499.       # Variablenbindungs-Frame aufbauen:
  500.       { var reg9 object* top_of_frame = STACK; # Pointer ⁿbern Frame
  501.         # zuerst die Special-deklarierten Variablen aus declarations
  502.         # im Stack ablegen:
  503.         var reg9 object* spec_pointer = args_end_pointer;
  504.         var reg8 uintL spec_anz = 0; # Anzahl der SPECIAL-Referenzen
  505.         { var reg3 object declspecs = declarations;
  506.           while (consp(declspecs))
  507.             { var reg1 object declspec = Car(declspecs); # nΣchste Deklaration
  508.               if (consp(declspec) && eq(Car(declspec),S(special))) # (SPECIAL ...) ?
  509.                 { while (consp( declspec = Cdr(declspec) ))
  510.                     { var reg2 object declsym = Car(declspec); # nΣchstes Special-deklariertes Item
  511.                       if (!symbolp(declsym)) # sollte ein Symbol sein
  512.                         { pushSTACK(declsym);
  513.                           pushSTACK(caller);
  514.                           fehler(program_error,
  515.                                  DEUTSCH ? "~: ~ ist kein Symbol, wurde aber als SPECIAL deklariert." :
  516.                                  ENGLISH ? "~: ~ is not a symbol, but was declared SPECIAL" :
  517.                                  FRANCAIS ? "~: ~ n'est pas un symb⌠le mais fut dΘclarΘ SPECIAL." :
  518.                                  ""
  519.                                 );
  520.                         }
  521.                       # Special-deklariertes Symbol im Stack ablegen:
  522.                       pushSTACK(specdecl); # SPECDECL als "Wert"
  523.                       pushSTACK_symbolwithflags(declsym,wbit(active_bit_o)); # Symbol aktiv
  524.                       check_STACK();
  525.                       spec_anz++;
  526.                 }   }
  527.               declspecs = Cdr(declspecs);
  528.         }   }
  529.         *bind_ptr_ = args_end_pointer; # Pointer ⁿber erste "richtige" Bindung
  530.         # Dann die "richtigen" Variablenbindungen (jeweils die Variable
  531.         # und ihren unausgewerteten Init) im Stack ablegen:
  532.        {var reg7 uintL var_anz = 0; # Anzahl der Variablenbindungen
  533.         { while (consp(varspecs))
  534.             { var reg4 object varspec = Car(varspecs); # nΣchstes varspec
  535.               # in Symbol und Init aufspalten:
  536.               var reg5 object symbol;
  537.               var reg6 object init;
  538.               if (symbolp(varspec) && !eq(caller,S(symbol_macrolet))) # Symbol ?
  539.                 { symbol = varspec; init = unbound; }
  540.               elif # zweielementige Liste, mit Symbol als CAR ?
  541.                    (consp(varspec)
  542.                     && (symbol = Car(varspec), varspec = Cdr(varspec),
  543.                         symbolp(symbol) && consp(varspec) && nullp(Cdr(varspec))
  544.                    )   )
  545.                 { init = Car(varspec); }
  546.               else
  547.                 { pushSTACK(Car(varspecs));
  548.                   pushSTACK(caller);
  549.                   fehler(program_error,
  550.                          DEUTSCH ? "~: ~ ist keine korrekte Variablenspezifikation." :
  551.                          ENGLISH ? "~: illegal variable specification ~" :
  552.                          FRANCAIS ? "~: ~ n'est pas une spΘcification de variable licite." :
  553.                          ""
  554.                         );
  555.                 }
  556.               pushSTACK(init); # Init und
  557.               pushSTACK_symbolwithflags(symbol,0); # Variable ablegen
  558.               check_STACK();
  559.               # feststellen, ob statische oder dynamische Bindung:
  560.               if (!special_var_p(TheSymbol(symbol)) || eq(caller,S(symbol_macrolet)))
  561.                 { # Variable unter den Special-deklarierten?
  562.                   #ifdef NO_symbolflags
  563.                   var reg1 object* ptr = spec_pointer;
  564.                   var reg2 uintL count;
  565.                   dotimesL(count,spec_anz,
  566.                     { NEXT(ptr);
  567.                       if (eq(NEXT(ptr),symbol))
  568.                         { if (eq(NEXT(ptr),fixnum(bit(active_bit)))) goto dynamic; }
  569.                         else
  570.                         { NEXT(ptr); }
  571.                     });
  572.                   #else
  573.                   var reg3 object to_compare = as_object(as_oint(symbol) | wbit(active_bit_o));
  574.                   var reg1 object* ptr = spec_pointer;
  575.                   var reg2 uintL count;
  576.                   dotimesL(count,spec_anz,
  577.                     { NEXT(ptr);
  578.                       if (eq(NEXT(ptr),to_compare))
  579.                         goto dynamic;
  580.                     });
  581.                   #endif
  582.                   # Nein -> statische Bindung
  583.                 }
  584.                 else
  585.                 { # dynamisch binden
  586.                   if (FALSE)
  587.                     { dynamic:
  588.                       if (eq(caller,S(symbol_macrolet)))
  589.                         { pushSTACK(symbol);
  590.                           pushSTACK(caller);
  591.                           fehler(program_error,
  592.                                  DEUTSCH ? "~: Symbol ~ darf nicht gleichzeitig SPECIAL und Makro deklariert werden." :
  593.                                  ENGLISH ? "~: symbol ~ must not be declared SPECIAL and a macro at the same time" :
  594.                                  FRANCAIS ? "~ : Le symbole ~ ne peut Ωtre dΘclarΘ SPECIAL et macro en mΩme temps." :
  595.                                  ""
  596.                                 );
  597.                     }   }
  598.                   *(oint*)(&STACK_0) |= wbit(dynam_bit_o);
  599.                 }
  600.               varspecs = Cdr(varspecs);
  601.               var_anz++;
  602.         }   }
  603.         *bind_count_ = var_anz;
  604.         var_anz += spec_anz; # Gesamtzahl Symbol/Wert-Paare
  605.         #ifndef UNIX_DEC_ULTRIX_GCCBUG
  606.         if (var_anz > (uintC)(~(uintC)0)) # pa▀t es in ein uintC ?
  607.           { pushSTACK(caller);
  608.             fehler(program_error,
  609.                    DEUTSCH ? "~: Zuviele Variablen und/oder Deklarationen." :
  610.                    ENGLISH ? "~: too many variables and/or declarations" :
  611.                    FRANCAIS ? "~: Trop de dΘclarations et/ou de variables." :
  612.                    ""
  613.                   );
  614.           }
  615.         #endif
  616.         pushSTACK(aktenv.var_env); # aktuelles VAR_ENV als NEXT_ENV
  617.         pushSTACK(as_object(var_anz)); # Anzahl Bindungen
  618.         finish_frame(VAR);
  619.       }}
  620.       # Der Variablenbindungsframe ist jetzt fertig.
  621.      {var reg5 object* var_frame_ptr = STACK; # Pointer auf Variablenbindungs-Frame
  622.       # VENV-Bindungsframe aufbauen:
  623.       { var reg4 object* top_of_frame = STACK; # Pointer ⁿbern Frame
  624.         # Zuerst DENV um die n÷tigen declspecs erweitern:
  625.         var reg3 object denv = aktenv.decl_env;
  626.         pushSTACK(value1); # ({form}) retten
  627.         pushSTACK(declarations);
  628.         while (mconsp(STACK_0))
  629.           { var reg2 object declspecs = STACK_0;
  630.             STACK_0 = Cdr(declspecs);
  631.            {var reg1 object declspec = Car(declspecs); # nΣchstes Declspec
  632.             if (consp(declspec)) # sollte ein Cons sein
  633.               { if (!eq(Car(declspec),S(special))) # (SPECIAL ...) haben wir schon behandelt
  634.                   { denv = augment_decl_env(declspec,denv); } # alles andere behandeln
  635.           }}  }
  636.         skipSTACK(1);
  637.        {var reg1 object forms = popSTACK();
  638.         # Nun den Frame bauen:
  639.         if (eq(denv,aktenv.decl_env))
  640.           { pushSTACK(aktenv.var_env);
  641.             finish_frame(ENV1V);
  642.           }
  643.           else
  644.           { pushSTACK(aktenv.decl_env);
  645.             pushSTACK(aktenv.var_env);
  646.             finish_frame(ENV2VD);
  647.             aktenv.decl_env = denv;
  648.           }
  649.         # VENV-Bindungsframe ist fertig.
  650.         aktenv.var_env = make_framepointer(var_frame_ptr); # Pointer auf Variablenbindungsframe
  651.         pushSTACK(forms);
  652.     }}}}
  653.  
  654. LISPSPECFORM(let, 1,0,body)
  655. # (LET ({varspec}) {decl} {form}), CLTL S. 110
  656.   { # {decl} {form} trennen:
  657.     var reg6 boolean to_compile = parse_dd(STACK_0,aktenv.var_env,aktenv.fun_env); # unvollstΣndiges var_env??
  658.     # bitte kein Docstring:
  659.     if (!nullp(value3)) { fehler_docstring(S(let),STACK_0); }
  660.     if (to_compile) # Deklaration (COMPILE) ?
  661.       # ja -> Form kompilieren:
  662.       { skipSTACK(2); return_Values compile_eval_form(); }
  663.       else
  664.       { skipSTACK(1);
  665.         # Variablenbindungsframe aufbauen, VAR_ENV erweitern:
  666.        {var object* bind_ptr;
  667.         var uintC bind_count;
  668.         make_variable_frame(S(let),popSTACK(),&bind_ptr,&bind_count);
  669.         # Dann die Initialisierungsformen auswerten:
  670.         { var reg3 object* frame_pointer = bind_ptr;
  671.           var reg4 uintC count;
  672.           dotimesC(count,bind_count,
  673.             { var reg1 object* initptr = &NEXT(frame_pointer);
  674.               var reg2 object init = *initptr; # nΣchstes Init
  675.               *initptr = (eq(init,unbound) ? NIL : (eval(init),value1)); # auswerten, NIL als Default
  676.               frame_pointer skipSTACKop -(varframe_binding_size-1);
  677.             });
  678.         }
  679.         # Dann die Bindungen aktivieren:
  680.         { var reg4 object* frame_pointer = bind_ptr;
  681.           var reg5 uintC count;
  682.           dotimesC(count,bind_count,
  683.             { frame_pointer skipSTACKop -varframe_binding_size;
  684.              {var reg1 object* markptr = &Before(frame_pointer);
  685.               if (*(oint*)(markptr) & wbit(dynam_bit_o)) # Bindung dynamisch?
  686.                 { var reg2 object symbol = *(markptr STACKop varframe_binding_sym); # Variable
  687.                   var reg3 object newval = *(markptr STACKop varframe_binding_value); # neuer Wert
  688.                   *(markptr STACKop varframe_binding_value) = TheSymbolflagged(symbol)->symvalue; # alten Wert im Frame sichern
  689.                   *(oint*)(markptr) |= wbit(active_bit_o); # Bindung aktivieren
  690.                   TheSymbolflagged(symbol)->symvalue = newval; # neuer Wert
  691.                 }
  692.                 else
  693.                 { *(oint*)(markptr) |= wbit(active_bit_o); } # Bindung aktivieren
  694.             }});
  695.         }
  696.         # Body abinterpretieren:
  697.         implicit_progn(popSTACK(),NIL);
  698.         # Frames aufl÷sen:
  699.         unwind(); # VENV-Bindungsframe aufl÷sen
  700.         unwind(); # Variablenbindungs-Frame aufl÷sen
  701.   }   }}
  702.  
  703. LISPSPECFORM(letstern, 1,0,body)
  704. # (LET* ({varspec}) {decl} {form}), CLTL S. 111
  705.   { # {decl} {form} trennen:
  706.     var reg7 boolean to_compile = parse_dd(STACK_0,aktenv.var_env,aktenv.fun_env); # unvollstΣndiges var_env??
  707.     # bitte kein Docstring:
  708.     if (!nullp(value3)) { fehler_docstring(S(letstern),STACK_0); }
  709.     if (to_compile) # Deklaration (COMPILE) ?
  710.       # ja -> Form kompilieren:
  711.       { skipSTACK(2); return_Values compile_eval_form(); }
  712.       else
  713.       { skipSTACK(1);
  714.         # Variablenbindungsframe aufbauen, VAR_ENV erweitern:
  715.        {var object* bind_ptr;
  716.         var uintC bind_count;
  717.         make_variable_frame(S(letstern),popSTACK(),&bind_ptr,&bind_count);
  718.         # Dann die Initialisierungsformen auswerten und die Bindungen aktivieren:
  719.         { var reg5 object* frame_pointer = bind_ptr;
  720.           var reg6 uintC count;
  721.           dotimesC(count,bind_count,
  722.             { var reg2 object* initptr = &Next(frame_pointer);
  723.               frame_pointer skipSTACKop -varframe_binding_size;
  724.              {var reg1 object* markptr = &Before(frame_pointer);
  725.               var reg4 object init = *initptr; # nΣchstes Init
  726.               var reg4 object newval = (eq(init,unbound) ? NIL : (eval(init),value1)); # auswerten, NIL als Default
  727.               if (*(oint*)(markptr) & wbit(dynam_bit_o)) # Bindung dynamisch?
  728.                 { var reg3 object symbol = *(markptr STACKop varframe_binding_sym); # Variable
  729.                   *initptr = TheSymbolflagged(symbol)->symvalue; # alten Wert im Frame sichern
  730.                   *(oint*)(markptr) |= wbit(active_bit_o); # Bindung aktivieren
  731.                   TheSymbolflagged(symbol)->symvalue = newval; # neuer Wert
  732.                 }
  733.                 else
  734.                 { *initptr = newval; # neuen Wert in den Frame
  735.                   *(oint*)(markptr) |= wbit(active_bit_o); # Bindung aktivieren
  736.                 }
  737.             }});
  738.         }
  739.         # Body abinterpretieren:
  740.         implicit_progn(popSTACK(),NIL);
  741.         # Frames aufl÷sen:
  742.         unwind(); # VENV-Bindungsframe aufl÷sen
  743.         unwind(); # Variablenbindungs-Frame aufl÷sen
  744.   }   }}
  745.  
  746. LISPSPECFORM(locally, 0,0,body)
  747. # (LOCALLY {decl} {form}), CLTL2 S. 221
  748.   { # {decl} {form} trennen:
  749.     var reg1 boolean to_compile = parse_dd(STACK_0,aktenv.var_env,aktenv.fun_env); # unvollstΣndiges var_env??
  750.     # bitte kein Docstring:
  751.     if (!nullp(value3)) { fehler_docstring(S(locally),STACK_0); }
  752.     skipSTACK(1);
  753.     if (to_compile) # Deklaration (COMPILE) ?
  754.       # ja -> Form kompilieren:
  755.       { return_Values compile_eval_form(); }
  756.       else
  757.       { # Variablenbindungsframe aufbauen, VAR_ENV erweitern:
  758.         var object* bind_ptr;
  759.         var uintC bind_count;
  760.         make_variable_frame(S(locally),NIL,&bind_ptr,&bind_count);
  761.         # Body abinterpretieren:
  762.         implicit_progn(popSTACK(),NIL);
  763.         # Frames aufl÷sen:
  764.         unwind(); # VENV-Bindungsframe aufl÷sen
  765.         unwind(); # Variablenbindungs-Frame aufl÷sen
  766.   }   }
  767.  
  768. LISPSPECFORM(compiler_let, 1,0,body)
  769. # (COMPILER-LET ({varspec}) {form}), CLTL S. 112
  770.   { var reg5 object* varspecs_ = &STACK_1;
  771.     var reg3 object varspecs = *varspecs_; # Liste der Variablen
  772.     var reg7 uintL varcount = llength(varspecs); # Anzahl der Variablen
  773.     get_space_on_STACK(varcount*3*sizeof(object)); # Platz auf dem STACK verlangen
  774.     # varspecs evaluieren:
  775.    {var reg6 object* val_pointer = args_end_pointer; # Pointer ⁿber die Werte
  776.     while (consp(varspecs))
  777.       { var reg1 object varspec = Car(varspecs);
  778.         var reg2 object symbol;
  779.         if (consp(varspec))
  780.           # varspec ist ein Cons
  781.           { symbol = Car(varspec);
  782.             varspec = Cdr(varspec);
  783.             if (!(consp(varspec) && nullp(Cdr(varspec))))
  784.               { pushSTACK(Car(varspecs));
  785.                 pushSTACK(S(compiler_let));
  786.                 fehler(program_error,
  787.                        DEUTSCH ? "~: ~ ist keine korrekte Variablenspezifikation." :
  788.                        ENGLISH ? "~: illegal variable specification ~" :
  789.                        FRANCAIS ? "~: ~ n'est pas une spΘcification de variable licite." :
  790.                        ""
  791.                       );
  792.               }
  793.             # symbol sollte ein nichtkonstantes Symbol sein:
  794.             if (!symbolp(symbol))
  795.               { fehler_symbol:
  796.                 fehler_kein_symbol(S(compiler_let),symbol);
  797.               }
  798.             if (constantp(TheSymbol(symbol)))
  799.               { fehler_constant:
  800.                 pushSTACK(symbol);
  801.                 pushSTACK(S(compiler_let));
  802.                 fehler(error,
  803.                        DEUTSCH ? "~: ~ ist eine Konstante und kann nicht dynamisch gebunden werden." :
  804.                        ENGLISH ? "~: ~ is a constant, cannot be bound" :
  805.                        FRANCAIS ? "~: ~ est une constante et ne peut pas Ωtre liΘe." :
  806.                        ""
  807.                       );
  808.               }
  809.             pushSTACK(Cdr(varspecs));
  810.             eval_noenv(Car(varspec)); # zweites Listenelement auswerten
  811.             varspecs = STACK_0;
  812.             STACK_0 = value1; # und in den Stack
  813.           }
  814.           else
  815.           { symbol = varspec;
  816.             if (!symbolp(symbol)) goto fehler_symbol;
  817.             if (constantp(TheSymbol(symbol))) goto fehler_constant;
  818.             pushSTACK(NIL); # NIL als Wert in den Stack
  819.             varspecs = Cdr(varspecs);
  820.       }   }
  821.     varspecs = *varspecs_;
  822.     # Frame aufbauen:
  823.     { var reg4 object* top_of_frame = STACK; # Pointer ⁿbern Frame
  824.       while (consp(varspecs))
  825.         { var reg1 object varspec = Car(varspecs);
  826.           if (consp(varspec)) { varspec = Car(varspec); }
  827.           pushSTACK(Symbol_value(varspec)); # alter Wert der Variablen
  828.           pushSTACK(varspec); # Variable
  829.           varspecs = Cdr(varspecs);
  830.         }
  831.       finish_frame(DYNBIND);
  832.     }
  833.     # Frame fertig aufgebaut, nun die Werte der Variablen verΣndern:
  834.     varspecs = *varspecs_;
  835.     { var reg2 object* valptr = val_pointer;
  836.       while (consp(varspecs))
  837.         { var reg1 object varspec = Car(varspecs);
  838.           if (consp(varspec)) { varspec = Car(varspec); }
  839.           Symbol_value(varspec) = NEXT(valptr); # neuen Wert der Variablen zuweisen
  840.           varspecs = Cdr(varspecs);
  841.     }   }
  842.     # Nun die Formen evaluieren:
  843.     implicit_progn(*(varspecs_ STACKop -1),NIL);
  844.     # Bindungsframe aufl÷sen:
  845.     unwind();
  846.     # Stack aufrΣumen:
  847.     set_args_end_pointer(val_pointer);
  848.     skipSTACK(2);
  849.   }}
  850.  
  851. LISPSPECFORM(progv, 2,0,body)
  852. # (PROGV symbollist valuelist {form}), CLTL S. 112
  853.   { STACK_2 = (eval(STACK_2),value1); # Symbolliste auswerten
  854.    {var reg2 object valuelist = (eval(STACK_1),value1); # Wertliste auswerten
  855.     var reg1 object body = popSTACK();
  856.     skipSTACK(1);
  857.     progv(popSTACK(),valuelist); # Frame aufbauen
  858.     implicit_progn(body,NIL); # body auswerten
  859.     unwind(); # Frame aufl÷sen
  860.   }}
  861.  
  862. # Fehlermeldung bei FLET/LABELS, wenn keine Funktionsspezifikation vorliegt.
  863. # > caller: Aufrufer, ein Symbol
  864. # > obj: fehlerhafte Funktionsspezifikation
  865.   nonreturning_function(local, fehler_funspec, (object caller, object obj));
  866.   local void fehler_funspec(caller,obj)
  867.     var reg2 object caller;
  868.     var reg1 object obj;
  869.     { pushSTACK(obj);
  870.       pushSTACK(caller);
  871.       fehler(program_error,
  872.              DEUTSCH ? "~: ~ ist keine Funktionsspezifikation." :
  873.              ENGLISH ? "~: ~ is not a function specification" :
  874.              FRANCAIS ? "~: ~ n'est pas une spΘcification de fonction." :
  875.              ""
  876.             );
  877.     }
  878.  
  879. # UP: Beendet ein FLET/MACROLET.
  880. # finish_flet(top_of_frame,body);
  881. # > Stackaufbau: [top_of_frame] def1 name1 ... defn namen [STACK]
  882. # > top_of_frame: Pointer ⁿbern Frame
  883. # > body: Formenliste
  884. # < mv_count/mv_space: Werte
  885. # kann GC ausl÷sen
  886.   local Values finish_flet (object* top_of_frame, object body);
  887.   local Values finish_flet(top_of_frame,body)
  888.     var reg2 object* top_of_frame;
  889.     var reg3 object body;
  890.     {{var reg1 uintL bindcount = # Anzahl der Bindungen
  891.         STACK_item_count(STACK,top_of_frame) / 2;
  892.       pushSTACK(aktenv.fun_env); # aktuelles FUN_ENV als NEXT_ENV
  893.       pushSTACK(as_object(bindcount));
  894.       finish_frame(FUN);
  895.      }# Funktionsbindungsframe ist fertig.
  896.       # FENV-Bindungsframe bauen:
  897.      {var reg1 object* top_of_frame = STACK; # Pointer ⁿbern Frame
  898.       pushSTACK(aktenv.fun_env);
  899.       finish_frame(ENV1F);
  900.       # FENV-Bindungsframe ist fertig.
  901.       # FUN_ENV erweitern:
  902.       # top_of_frame = Pointer auf den Funktionsbindungsframe
  903.       aktenv.fun_env = make_framepointer(top_of_frame);
  904.      }# Formen ausfⁿhren:
  905.       implicit_progn(body,NIL);
  906.       unwind(); # FENV-Bindungsframe aufl÷sen
  907.       unwind(); # Funktionsbindungsframe aufl÷sen
  908.     }
  909.  
  910. LISPSPECFORM(flet, 1,0,body)
  911. # (FLET ({funspec}) {form}), CLTL S. 113
  912.   { var reg5 object body = popSTACK(); # ({form})
  913.     var reg1 object funspecs = popSTACK(); # ({funspec})
  914.     # Funktionsbindungs-Frame aufbauen:
  915.     var reg6 object* top_of_frame = STACK; # Pointer ⁿbern Frame
  916.     while (consp(funspecs))
  917.       { pushSTACK(body); # Formenliste retten
  918.         pushSTACK(Cdr(funspecs)); # restliche funspecs
  919.         funspecs = Car(funspecs); # nΣchstes funspec = (name . lambdabody)
  920.         # sollte ein Cons sein, dessen CAR ein Symbol und dessen CDR ein Cons ist:
  921.         if (!consp(funspecs)) { fehler_spec: fehler_funspec(S(flet),funspecs); }
  922.        {var reg2 object name = Car(funspecs);
  923.         var reg3 object lambdabody = Cdr(funspecs);
  924.         if (!funnamep(name)) { fehler_funsymbol(S(flet),name); }
  925.         if (!consp(lambdabody)) { goto fehler_spec; }
  926.         pushSTACK(name); # name retten
  927.         # lambdabody zu einer Closure machen:
  928.         {var reg4 object fun = get_closure(lambdabody,name,&aktenv);
  929.          name = popSTACK();
  930.          funspecs = popSTACK(); # restliche funspecs
  931.          body = popSTACK();
  932.          # in den Frame:
  933.          pushSTACK(fun); # als "Wert" die Closure
  934.          pushSTACK(name); # Name, Bindung ist automatisch aktiv
  935.       }}}
  936.     return_Values finish_flet(top_of_frame,body);
  937.   }
  938.  
  939. LISPSPECFORM(labels, 1,0,body)
  940. # (LABELS ({funspec}) {form}), CLTL S. 113
  941.   { # Auf den Aufbau eines Funktionsbindungs-Frames kann hier verzichtet werden,
  942.     # weil bei der Bildung der ersten Closure sowieso das Environment genestet
  943.     # und dabei dieser Funktionsbindungs-Frame in einen Vektor geschrieben wⁿrde.
  944.     # aktuelles FUN_ENV nesten:
  945.     pushSTACK(nest_fun(aktenv.fun_env));
  946.     # Anzahl der funspecs bestimmen und Syntax abtesten:
  947.    {var reg6 uintL veclength = 1; # = 2 * (Anzahl der funspecs) + 1
  948.     { var reg2 object funspecs = STACK_(1+1);
  949.       while (consp(funspecs))
  950.         { var reg1 object funspec = Car(funspecs);
  951.           # sollte ein Cons sein, dessen CAR ein Symbol und dessen CDR ein Cons ist:
  952.           if (!consp(funspec)) { fehler_spec: fehler_funspec(S(labels),funspec); }
  953.           {var reg3 object name = Car(funspec);
  954.            var reg4 object lambdabody = Cdr(funspec);
  955.            if (!funnamep(name)) { fehler_funsymbol(S(labels),name); }
  956.            if (!consp(lambdabody)) { goto fehler_spec; }
  957.           }
  958.           funspecs = Cdr(funspecs);
  959.           veclength += 2;
  960.     }   }
  961.     # Vektor passender LΣnge allozieren und darin die Namen eintragen:
  962.     {var reg7 object vec = allocate_vector(veclength);
  963.      {var reg2 object* ptr = &TheSvector(vec)->data[0];
  964.       var reg1 object funspecs = STACK_(1+1);
  965.       while (consp(funspecs))
  966.         { *ptr++ = Car(Car(funspecs)); # nΣchster name
  967.           ptr++; # Funktion bleibt vorerst NIL
  968.           funspecs = Cdr(funspecs);
  969.         }
  970.       *ptr++ = popSTACK(); # genestetes FUN_ENV als letztes Vektor-Element
  971.      }
  972.      {var reg5 object body = popSTACK(); # Formenliste
  973.       var reg2 object funspecs = popSTACK();
  974.       # FENV-Bindungsframe aufbauen:
  975.       { var reg1 object* top_of_frame = STACK; # Pointer ⁿbern Frame
  976.         pushSTACK(aktenv.fun_env);
  977.         finish_frame(ENV1F);
  978.       }
  979.       # FUN_ENV erweitern:
  980.       aktenv.fun_env = vec;
  981.       # Closures erzeugen und in den Vektor stecken:
  982.       pushSTACK(body);
  983.       pushSTACK(vec);
  984.       {var reg4 uintL index = 1; # Index in den Vektor
  985.        while (consp(funspecs))
  986.          { pushSTACK(Cdr(funspecs)); # restliche funspecs
  987.           {var reg1 object funspec = Car(funspecs);
  988.            # Closure erzeugen:
  989.            var reg3 object fun = get_closure(Cdr(funspec),Car(funspec),&aktenv);
  990.            funspecs = popSTACK();
  991.            TheSvector(STACK_0)->data[index] = fun; # in den Vektor stecken
  992.            index += 2;
  993.       }  }}
  994.       skipSTACK(1); # Vektor vergessen
  995.       body = popSTACK();
  996.       # Formen ausfⁿhren:
  997.       implicit_progn(body,NIL);
  998.       unwind(); # FENV-Bindungsframe aufl÷sen
  999.   }}}}
  1000.  
  1001. LISPSPECFORM(macrolet, 1,0,body)
  1002. # (MACROLET ({macrodef}) {form}), CLTL S. 113
  1003.   { var reg2 object body = popSTACK(); # ({form})
  1004.     var reg1 object macrodefs = popSTACK(); # ({macrodef})
  1005.     # Macrobindungs-Frame aufbauen:
  1006.     var reg4 object* top_of_frame = STACK; # Pointer ⁿbern Frame
  1007.     while (consp(macrodefs))
  1008.       { pushSTACK(body); # Formenliste retten
  1009.         pushSTACK(Cdr(macrodefs)); # restliche macrodefs
  1010.         macrodefs = Car(macrodefs); # nΣchstes macrodef = (name . lambdabody)
  1011.         # sollte ein Cons sein, dessen CAR ein Symbol und dessen CDR ein Cons ist:
  1012.         if (!consp(macrodefs))
  1013.           { fehler_spec:
  1014.             pushSTACK(macrodefs);
  1015.             pushSTACK(S(macrolet));
  1016.             fehler(program_error,
  1017.                    DEUTSCH ? "~: ~ ist keine Macro-Spezifikation." :
  1018.                    ENGLISH ? "~: ~ is not a macro specification" :
  1019.                    FRANCAIS ? "~: ~ n'est pas une spΘcification de macro." :
  1020.                    ""
  1021.                   );
  1022.           }
  1023.        {var reg3 object name = Car(macrodefs);
  1024.         if (!symbolp(name))
  1025.           { pushSTACK(name);
  1026.             pushSTACK(S(macrolet));
  1027.             fehler(program_error,
  1028.                    DEUTSCH ? "~: Macro-Name ~ ist kein Symbol." :
  1029.                    ENGLISH ? "~: macro name ~ should be a symbol" :
  1030.                    FRANCAIS ? "~: Le nom de macro ~ n'est pas un symb⌠le." :
  1031.                    ""
  1032.                   );
  1033.           }
  1034.         if (!mconsp(Cdr(macrodefs))) { goto fehler_spec; }
  1035.         pushSTACK(name); # name retten
  1036.         # Macro-Expander bauen: (SYSTEM::MAKE-MACRO-EXPANDERCONS macrodef)
  1037.         pushSTACK(macrodefs); funcall(S(make_macro_expandercons),1);
  1038.         name = popSTACK();
  1039.         macrodefs = popSTACK(); # restliche macrodefs
  1040.         body = popSTACK();
  1041.         # in den Frame:
  1042.         pushSTACK(value1); # als "Wert" das Cons mit dem Expander
  1043.         pushSTACK(name); # Name, Bindung ist automatisch aktiv
  1044.       }}
  1045.     return_Values finish_flet(top_of_frame,body);
  1046.   }
  1047.  
  1048. LISPSPECFORM(symbol_macrolet, 1,0,body)
  1049. # (SYMBOL-MACROLET ({(var expansion)}) {decl} {form}), CLTL2 S. 155
  1050.   { # {decl} {form} trennen:
  1051.     var reg5 boolean to_compile = parse_dd(STACK_0,aktenv.var_env,aktenv.fun_env); # unvollstΣndiges var_env??
  1052.     # bitte kein Docstring:
  1053.     if (!nullp(value3)) { fehler_docstring(S(symbol_macrolet),STACK_0); }
  1054.     if (to_compile) # Deklaration (COMPILE) ?
  1055.       # ja -> Form kompilieren:
  1056.       { skipSTACK(2); return_Values compile_eval_form(); }
  1057.       else
  1058.       { skipSTACK(1);
  1059.         # Variablenbindungsframe aufbauen, VAR_ENV erweitern:
  1060.        {var object* bind_ptr;
  1061.         var uintC bind_count;
  1062.         make_variable_frame(S(symbol_macrolet),popSTACK(),&bind_ptr,&bind_count);
  1063.         # Dann die Symbol-Macros bilden und die Bindungen aktivieren:
  1064.         { var reg3 object* frame_pointer = bind_ptr;
  1065.           var reg4 uintC count;
  1066.           dotimesC(count,bind_count,
  1067.             { var reg1 object* initptr = &NEXT(frame_pointer);
  1068.               var reg2 object sm = allocate_symbolmacro();
  1069.               TheSymbolmacro(sm)->symbolmacro_expansion = *initptr;
  1070.               *initptr = sm;
  1071.               frame_pointer skipSTACKop -(varframe_binding_size-1);
  1072.               *(oint*)(&Before(frame_pointer)) |= wbit(active_bit_o);
  1073.             });
  1074.         }
  1075.         # Body abinterpretieren:
  1076.         implicit_progn(popSTACK(),NIL);
  1077.         # Frames aufl÷sen:
  1078.         unwind(); # VENV-Bindungsframe aufl÷sen
  1079.         unwind(); # Variablenbindungs-Frame aufl÷sen
  1080.   }   }}
  1081.  
  1082. LISPSPECFORM(if, 2,1,nobody)
  1083. # (IF test form1 [form2]), CLTL S. 115
  1084.   { eval(STACK_2); # Bedingung auswerten
  1085.    {var reg1 object form;
  1086.     if (!nullp(value1))
  1087.       { form = STACK_1; skipSTACK(3); } # form1 auswerten
  1088.       else
  1089.       { form = STACK_0; skipSTACK(3); # form2 auswerten
  1090.         if (eq(form,unbound))
  1091.           { value1 = NIL; mv_count=1; return; } # keine angegeben -> NIL
  1092.       }
  1093.     eval(form);
  1094.   }}
  1095.  
  1096. LISPSPECFORM(when, 1,0,body)
  1097. # (WHEN test {form}), CLTL S. 115
  1098.   { eval(STACK_1); # Bedingung auswerten
  1099.     if (!nullp(value1))
  1100.       { var reg1 object body = STACK_0;
  1101.         skipSTACK(2);
  1102.         implicit_progn(body,NIL);
  1103.       }
  1104.       else
  1105.       { skipSTACK(2);
  1106.         value1 = NIL; mv_count=1;
  1107.       }
  1108.   }
  1109.  
  1110. LISPSPECFORM(unless, 1,0,body)
  1111. # (UNLESS test {form}), CLTL S. 115
  1112.   { eval(STACK_1); # Bedingung auswerten
  1113.     if (nullp(value1))
  1114.       { var reg1 object body = STACK_0;
  1115.         skipSTACK(2);
  1116.         implicit_progn(body,NIL);
  1117.       }
  1118.       else
  1119.       { skipSTACK(2);
  1120.         value1 = NIL; mv_count=1;
  1121.       }
  1122.   }
  1123.  
  1124. LISPSPECFORM(cond, 0,0,body)
  1125. # (COND {(bed {form})}), CLTL S. 116
  1126.   { while (mconsp(STACK_0))
  1127.       { var reg1 object clause = STACK_0; # Klausel-Liste
  1128.         STACK_0 = Cdr(clause); # restliche Klauseln retten
  1129.         clause = Car(clause); # nΣchste Klausel
  1130.         if (!consp(clause)) # sollte ein Cons sein
  1131.           { pushSTACK(clause);
  1132.             pushSTACK(S(cond));
  1133.             fehler(program_error,
  1134.                    DEUTSCH ? "~: Klausel ~ mu▀ Liste sein." :
  1135.                    ENGLISH ? "~: clause ~ should be a list" :
  1136.                    FRANCAIS ? "~: La clause ~ doit Ωtre une liste." :
  1137.                    ""
  1138.                   );
  1139.           }
  1140.         pushSTACK(Cdr(clause)); # Klausel-Rest retten
  1141.         eval(Car(clause)); # Bedingung auswerten
  1142.         if (!nullp(value1)) goto eval_clause;
  1143.         skipSTACK(1); # nΣchste probieren
  1144.       }
  1145.     # keine Bedingung war erfⁿllt.
  1146.     skipSTACK(1); value1 = NIL; mv_count=1; return;
  1147.     # erfⁿllte Bedingung gefunden:
  1148.     eval_clause:
  1149.    {var reg1 object clause_rest = popSTACK(); # Klausel-Rest
  1150.     skipSTACK(1);
  1151.     implicit_progn(clause_rest,value1); # auswerten
  1152.   }}
  1153.  
  1154. LISPSPECFORM(block, 1,0,body)
  1155. # (BLOCK name {form}), CLTL S. 119
  1156.   { var reg9 object body = popSTACK();
  1157.     var reg9 object name = popSTACK();
  1158.     if (!symbolp(name)) { fehler_symbol(name); }
  1159.    {var jmp_buf returner; # Rⁿcksprungpunkt
  1160.     # Block-Frame aufbauen:
  1161.     { var reg1 object* top_of_frame = STACK; # Pointer ⁿbern Frame
  1162.       pushSTACK(name); # Block-Name
  1163.       pushSTACK(aktenv.block_env); # aktuelles BLOCK_ENV als NEXT_ENV
  1164.       finish_entry_frame(IBLOCK,&!returner,, goto block_return; );
  1165.     }
  1166.     # BENV-Frame aufbauen:
  1167.     {var reg1 object* top_of_frame = STACK;
  1168.      pushSTACK(aktenv.block_env);
  1169.      finish_frame(ENV1B);
  1170.     # BLOCK_ENV erweitern (top_of_frame = Pointer auf den Block-Frame)
  1171.      aktenv.block_env = make_framepointer(top_of_frame);
  1172.     }
  1173.     # Body ausfⁿhren:
  1174.     implicit_progn(body,NIL);
  1175.     unwind(); # BENV-Bindungsframe aufl÷sen
  1176.     block_return: # Hierher wird gesprungen, wenn der BLOCK-Frame einen
  1177.                   # RETURN-FROM gefangen hat.
  1178.     unwind(); # BLOCK-Frame aufl÷sen
  1179.   }}
  1180.  
  1181. # Fehler, wenn ein Block bereits verlassen wurde.
  1182. # fehler_block_left(name);
  1183. # > name: Block-Name
  1184.   nonreturning_function(global, fehler_block_left, (object name));
  1185.   global void fehler_block_left(name)
  1186.     var reg1 object name;
  1187.     { pushSTACK(name);
  1188.       pushSTACK(S(return_from));
  1189.       fehler(control_error,
  1190.              DEUTSCH ? "~: Der Block mit Namen ~ wurde bereits verlassen." :
  1191.              ENGLISH ? "~: the block named ~ has already been left" :
  1192.              FRANCAIS ? "~: Le bloc de nom ~ a dΘjα ΘtΘ quittΘ." :
  1193.              ""
  1194.             );
  1195.     }
  1196.  
  1197. LISPSPECFORM(return_from, 1,1,nobody)
  1198. # (RETURN-FROM name [result]), CLTL S. 120
  1199.   { var reg4 object name = STACK_1;
  1200.     if (!symbolp(name)) { fehler_symbol(name); } # sollte ein Symbol sein
  1201.     # BLOCK_ENV durchgehen:
  1202.    {var reg1 object env = aktenv.block_env; # aktuelles BLOCK_ENV
  1203.     var reg2 object* FRAME;
  1204.     while (stack_env_p(env))
  1205.       { # env ist ein Frame-Pointer auf einen IBLOCK-Frame im Stack.
  1206.         FRAME = TheFramepointer(env);
  1207.         if (mtypecode(FRAME_(0)) & bit(nested_bit_t))
  1208.           # Frame schon genestet
  1209.           { env = FRAME_(frame_next_env); break; }
  1210.         if (eq(FRAME_(frame_name),name)) goto found;
  1211.         env = FRAME_(frame_next_env);
  1212.       }
  1213.     # env ist eine Aliste.
  1214.     while (consp(env))
  1215.       { var reg3 object block_cons = Car(env);
  1216.         if (eq(Car(block_cons),name))
  1217.           { env = Cdr(block_cons);
  1218.             if (eq(env,disabled)) # Block noch aktiv?
  1219.               { fehler_block_left(name); }
  1220.             goto found;
  1221.           }
  1222.         env = Cdr(env);
  1223.       }
  1224.     # env ist zu Ende.
  1225.     pushSTACK(name);
  1226.     pushSTACK(S(return_from));
  1227.     fehler(program_error,
  1228.            DEUTSCH ? "~: Es ist kein Block namens ~ sichtbar." :
  1229.            ENGLISH ? "~: no block named ~ is currently visible" :
  1230.            FRANCAIS ? "~: Aucun bloc de nom ~ n'est visible." :
  1231.            ""
  1232.           );
  1233.     # Block-Frame gefunden: env
  1234.     found:
  1235.     FRAME = uTheFramepointer(env); # Pointer auf ihn
  1236.     # Werte produzieren, mit denen der Block verlassen werden soll:
  1237.     {var reg5 object result = popSTACK();
  1238.      skipSTACK(1);
  1239.      if (!eq(result,unbound)) # result angegeben?
  1240.        { eval(result); }
  1241.        else
  1242.        { value1 = NIL; mv_count=1; }
  1243.      # Zum gefundenen Block-Frame springen und ihn aufl÷sen:
  1244.      unwind_upto(FRAME);
  1245.   }}}
  1246.  
  1247. # Die Funktionen MAPCAR, MAPLIST, MAPCAN, MAPCON bauen wir in zwei Versionen:
  1248. # Die erste baut die Liste im umgekehrter Reihenfolge, mu▀ sie dann umdrehen.
  1249. # Die zweite arbeitet vorwΣrtsherum, braucht dafⁿr aber ein Cons zuviel.
  1250.   #define MAP_REVERSES
  1251.  
  1252. #ifdef MAP_REVERSES
  1253.  
  1254. # Macro fⁿr MAPCAR und MAPLIST
  1255.   #define MAPCAR_MAPLIST_BODY(listaccess)  \
  1256.     { var reg7 object* args_pointer = rest_args_pointer STACKop 2;              \
  1257.       argcount++; # argcount := Anzahl der Listen auf dem Stack                 \
  1258.       # Platz fⁿr die Funktionsaufruf-Argumente reservieren:                    \
  1259.       get_space_on_STACK(sizeof(object)*(uintL)argcount);                       \
  1260.       pushSTACK(NIL); # Anfang der Ergebnisliste                                \
  1261.      {var reg6 object* ergptr = &STACK_0; # Pointer darauf                      \
  1262.       # alle Listen parallel durchlaufen:                                       \
  1263.       loop                                                                      \
  1264.         { var reg3 object* argptr = args_pointer;                               \
  1265.           var reg5 object fun = NEXT(argptr);                                   \
  1266.           var reg4 uintC count;                                                 \
  1267.           dotimespC(count,argcount,                                             \
  1268.             { var reg2 object* next_list_ = &NEXT(argptr);                      \
  1269.               var reg1 object next_list = *next_list_;                          \
  1270.               if (atomp(next_list)) goto fertig; # eine Liste zu Ende -> fertig \
  1271.               pushSTACK(listaccess(next_list)); # als Argument auf den Stack    \
  1272.               *next_list_ = Cdr(next_list); # Liste verkⁿrzen                   \
  1273.             });                                                                 \
  1274.           funcall(fun,argcount); # Funktion aufrufen                            \
  1275.           pushSTACK(value1);                                                    \
  1276.          {var reg1 object new_cons = allocate_cons(); # neues Cons              \
  1277.           Car(new_cons) = popSTACK(); Cdr(new_cons) = STACK_0;                  \
  1278.           STACK_0 = new_cons; # verlΣngert die Ergebnisliste                    \
  1279.         }}                                                                      \
  1280.       fertig:                                                                   \
  1281.       value1 = nreverse(*ergptr); mv_count=1; # Ergebnisliste umdrehen          \
  1282.       set_args_end_pointer(args_pointer); # STACK aufrΣumen                     \
  1283.     }}
  1284.  
  1285. #else
  1286.  
  1287. # Macro fⁿr MAPCAR und MAPLIST
  1288.   #define MAPCAR_MAPLIST_BODY(listaccess)  \
  1289.     { var reg7 object* args_pointer = rest_args_pointer STACKop 2;              \
  1290.       argcount++; # argcount := Anzahl der Listen auf dem Stack                 \
  1291.       # Platz fⁿr die Funktionsaufruf-Argumente reservieren:                    \
  1292.       get_space_on_STACK(sizeof(object)*(uintL)argcount);                       \
  1293.       # Gesamtliste anfangen:                                                   \
  1294.       {var reg1 object new_cons = allocate_cons(); # (CONS NIL NIL)             \
  1295.        pushSTACK(new_cons); # Gesamtliste                                       \
  1296.        pushSTACK(new_cons); # (last Gesamtliste)                                \
  1297.       }                                                                         \
  1298.      {var reg6 object* ergptr = &STACK_1; # Pointer darauf                      \
  1299.       # alle Listen parallel durchlaufen:                                       \
  1300.       loop                                                                      \
  1301.         { var reg3 object* argptr = args_pointer;                               \
  1302.           var reg5 object fun = NEXT(argptr);                                   \
  1303.           var reg4 uintC count;                                                 \
  1304.           dotimespC(count,argcount,                                             \
  1305.             { var reg2 object* next_list_ = &NEXT(argptr);                      \
  1306.               var reg1 object next_list = *next_list_;                          \
  1307.               if (atomp(next_list)) goto fertig; # eine Liste zu Ende -> fertig \
  1308.               pushSTACK(listaccess(next_list)); # als Argument auf den Stack    \
  1309.               *next_list_ = Cdr(next_list); # Liste verkⁿrzen                   \
  1310.             });                                                                 \
  1311.           funcall(fun,argcount); # Funktion aufrufen                            \
  1312.           pushSTACK(value1);                                                    \
  1313.          {var reg1 object new_cons = allocate_cons(); # neues Cons              \
  1314.           Car(new_cons) = popSTACK(); # new_cons = (LIST (FUNCALL ...))         \
  1315.           Cdr(STACK_0) = new_cons; STACK_0 = new_cons; # verlΣngert Gesamtliste \
  1316.         }}                                                                      \
  1317.       fertig:                                                                   \
  1318.       value1 = Cdr(*ergptr); mv_count=1; # Ergebnisliste ohne Header-Cons       \
  1319.       set_args_end_pointer(args_pointer); # STACK aufrΣumen                     \
  1320.     }}
  1321.  
  1322. #endif
  1323.  
  1324. # Macro fⁿr MAPC und MAPL
  1325.   #define MAPC_MAPL_BODY(listaccess)  \
  1326.     { var reg7 object* args_pointer = rest_args_pointer STACKop 2;              \
  1327.       argcount++; # argcount := Anzahl der Listen auf dem Stack                 \
  1328.       # Platz fⁿr die Funktionsaufruf-Argumente reservieren:                    \
  1329.       get_space_on_STACK(sizeof(object)*(uintL)argcount);                       \
  1330.       pushSTACK(BEFORE(rest_args_pointer)); # erstes Listenargument retten      \
  1331.      {var reg6 object* ergptr = &STACK_0; # Pointer darauf                      \
  1332.       # alle Listen parallel durchlaufen:                                       \
  1333.       loop                                                                      \
  1334.         { var reg3 object* argptr = args_pointer;                               \
  1335.           var reg5 object fun = NEXT(argptr);                                   \
  1336.           var reg4 uintC count;                                                 \
  1337.           dotimespC(count,argcount,                                             \
  1338.             { var reg2 object* next_list_ = &NEXT(argptr);                      \
  1339.               var reg1 object next_list = *next_list_;                          \
  1340.               if (atomp(next_list)) goto fertig; # eine Liste zu Ende -> fertig \
  1341.               pushSTACK(listaccess(next_list)); # als Argument auf den Stack    \
  1342.               *next_list_ = Cdr(next_list); # Liste verkⁿrzen                   \
  1343.             });                                                                 \
  1344.           funcall(fun,argcount); # Funktion aufrufen                            \
  1345.         }                                                                       \
  1346.       fertig:                                                                   \
  1347.       value1 = *ergptr; mv_count=1; # 1. Liste als Wert                         \
  1348.       set_args_end_pointer(args_pointer); # STACK aufrΣumen                     \
  1349.     }}
  1350.  
  1351. #ifdef MAP_REVERSES
  1352.  
  1353. # Macro fⁿr MAPCAN und MAPCON
  1354.   #define MAPCAN_MAPCON_BODY(listaccess)  \
  1355.     { var reg7 object* args_pointer = rest_args_pointer STACKop 2;              \
  1356.       argcount++; # argcount := Anzahl der Listen auf dem Stack                 \
  1357.       # Platz fⁿr die Funktionsaufruf-Argumente reservieren:                    \
  1358.       get_space_on_STACK(sizeof(object)*(uintL)argcount);                       \
  1359.       pushSTACK(NIL); # Anfang der Ergebnisliste                                \
  1360.      {var reg6 object* ergptr = &STACK_0; # Pointer darauf                      \
  1361.       # alle Listen parallel durchlaufen:                                       \
  1362.       loop                                                                      \
  1363.         { var reg3 object* argptr = args_pointer;                               \
  1364.           var reg5 object fun = NEXT(argptr);                                   \
  1365.           var reg4 uintC count;                                                 \
  1366.           dotimespC(count,argcount,                                             \
  1367.             { var reg2 object* next_list_ = &NEXT(argptr);                      \
  1368.               var reg1 object next_list = *next_list_;                          \
  1369.               if (atomp(next_list)) goto fertig; # eine Liste zu Ende -> fertig \
  1370.               pushSTACK(listaccess(next_list)); # als Argument auf den Stack    \
  1371.               *next_list_ = Cdr(next_list); # Liste verkⁿrzen                   \
  1372.             });                                                                 \
  1373.           funcall(fun,argcount); # Funktion aufrufen                            \
  1374.           STACK_0 = nreconc(value1,STACK_0); # Ergebnis anhΣngen                \
  1375.         }                                                                       \
  1376.       fertig:                                                                   \
  1377.       value1 = nreconc(*ergptr,NIL); mv_count=1; # Ergebnisliste umdrehen       \
  1378.       set_args_end_pointer(args_pointer); # STACK aufrΣumen                     \
  1379.     }}
  1380.  
  1381. #else
  1382.  
  1383. # Macro fⁿr MAPCAN und MAPCON
  1384.   #define MAPCAN_MAPCON_BODY(listaccess)  \
  1385.     { var reg7 object* args_pointer = rest_args_pointer STACKop 2;              \
  1386.       argcount++; # argcount := Anzahl der Listen auf dem Stack                 \
  1387.       # Platz fⁿr die Funktionsaufruf-Argumente reservieren:                    \
  1388.       get_space_on_STACK(sizeof(object)*(uintL)argcount);                       \
  1389.       # Gesamtliste anfangen:                                                   \
  1390.       {var reg1 object new_cons = allocate_cons(); # (CONS NIL NIL)             \
  1391.        pushSTACK(new_cons); # Gesamtliste                                       \
  1392.        pushSTACK(new_cons); # (last Gesamtliste)                                \
  1393.       }                                                                         \
  1394.      {var reg6 object* ergptr = &STACK_1; # Pointer darauf                      \
  1395.       # alle Listen parallel durchlaufen:                                       \
  1396.       loop                                                                      \
  1397.         { var reg3 object* argptr = args_pointer;                               \
  1398.           var reg5 object fun = NEXT(argptr);                                   \
  1399.           var reg4 uintC count;                                                 \
  1400.           dotimespC(count,argcount,                                             \
  1401.             { var reg2 object* next_list_ = &NEXT(argptr);                      \
  1402.               var reg1 object next_list = *next_list_;                          \
  1403.               if (atomp(next_list)) goto fertig; # eine Liste zu Ende -> fertig \
  1404.               pushSTACK(listaccess(next_list)); # als Argument auf den Stack    \
  1405.               *next_list_ = Cdr(next_list); # Liste verkⁿrzen                   \
  1406.             });                                                                 \
  1407.           funcall(fun,argcount); # Funktion aufrufen                            \
  1408.          {var reg1 object list = value1; # anzuhΣngende Liste                   \
  1409.           if (consp(list))                                                      \
  1410.             { Cdr(STACK_0) = list; # als (cdr (last Gesamtliste)) einhΣngen     \
  1411.               while (mconsp(Cdr(list))) { list = Cdr(list); }                   \
  1412.               STACK_0 = list; # und (last Gesamtliste) := (last list)           \
  1413.         }}  }                                                                   \
  1414.       fertig:                                                                   \
  1415.       value1 = Cdr(*ergptr); mv_count=1; # Ergebnisliste ohne Header-Cons       \
  1416.       set_args_end_pointer(args_pointer); # STACK aufrΣumen                     \
  1417.     }}
  1418.  
  1419. #endif
  1420.  
  1421. #define Identity
  1422.  
  1423. LISPFUN(mapcar,2,0,rest,nokey,0,NIL)
  1424. # (MAPCAR fun list {list}), CLTL S. 128
  1425.   MAPCAR_MAPLIST_BODY(Car)
  1426.  
  1427. LISPFUN(maplist,2,0,rest,nokey,0,NIL)
  1428. # (MAPLIST fun list {list}), CLTL S. 128
  1429.   MAPCAR_MAPLIST_BODY(Identity)
  1430.  
  1431. LISPFUN(mapc,2,0,rest,nokey,0,NIL)
  1432. # (MAPC fun list {list}), CLTL S. 128
  1433.   MAPC_MAPL_BODY(Car)
  1434.  
  1435. LISPFUN(mapl,2,0,rest,nokey,0,NIL)
  1436. # (MAPL fun list {list}), CLTL S. 128
  1437.   MAPC_MAPL_BODY(Identity)
  1438.  
  1439. LISPFUN(mapcan,2,0,rest,nokey,0,NIL)
  1440. # (MAPCAN fun list {list}), CLTL S. 128
  1441.   MAPCAN_MAPCON_BODY(Car)
  1442.  
  1443. LISPFUN(mapcon,2,0,rest,nokey,0,NIL)
  1444. # (MAPCON fun list {list}), CLTL S. 128
  1445.   MAPCAN_MAPCON_BODY(Identity)
  1446.  
  1447. LISPSPECFORM(tagbody, 0,0,body)
  1448. # (TAGBODY {tag | statement}), CLTL S. 130
  1449.   { var reg5 object body = popSTACK();
  1450.     # GENV-Frame aufbauen:
  1451.     { var reg1 object* top_of_frame = STACK; # Pointer ⁿbern Frame
  1452.       pushSTACK(aktenv.go_env);
  1453.       finish_frame(ENV1G);
  1454.     }
  1455.     # TAGBODY-Frame aufbauen:
  1456.    {var reg6 object* top_of_frame = STACK; # Pointer ⁿbern Frame
  1457.     # Body durchparsen und Tags im Stack ablegen:
  1458.     var reg4 uintL tagcount = 0;
  1459.     { var reg3 object body_rest = body;
  1460.       while (consp(body_rest))
  1461.         { var reg2 object item = Car(body_rest);
  1462.           body_rest = Cdr(body_rest);
  1463.           # Als Tags werden Symbole /=NIL sowie Zahlen angesehen
  1464.           # (wie im Compiler), Conses sind Statements.
  1465.           if (atomp(item))
  1466.             { if (numberp(item) || (symbolp(item) && (!nullp(item))))
  1467.                 # Marke im Stack ablegen:
  1468.                 { check_STACK();
  1469.                   pushSTACK(body_rest); # Body-Rest nach der Marke
  1470.                   pushSTACK(item);
  1471.                   tagcount++;
  1472.                 }
  1473.                 else
  1474.                 { pushSTACK(item);
  1475.                   pushSTACK(S(tagbody));
  1476.                   fehler(program_error,
  1477.                          DEUTSCH ? "~: ~ ist weder Marke noch Statement." :
  1478.                          ENGLISH ? "~: ~ is neither tag nor form" :
  1479.                          FRANCAIS ?"~: ~ n'est ni un marqueur ni une forme α evaluer." :
  1480.                          ""
  1481.                         );
  1482.                 }
  1483.     }   }   }
  1484.     if (tagcount>0)
  1485.       { var jmp_buf returner; # Rⁿcksprungpunkt
  1486.         pushSTACK(aktenv.go_env); # aktuelles GO_ENV als NEXT_ENV
  1487.         finish_entry_frame(ITAGBODY,&!returner,, goto go_entry; );
  1488.         # GO_ENV erweitern:
  1489.         aktenv.go_env = make_framepointer(STACK);
  1490.         if (FALSE)
  1491.           { go_entry: # Hierher wird gesprungen, wenn dieser Frame ein GO
  1492.                       # gefangen hat.
  1493.             body = value1; # Die Formenliste wird als value1 ⁿbergeben.
  1494.           }
  1495.         # Statements abarbeiten:
  1496.         pushSTACK(body);
  1497.         while (mconsp(STACK_0))
  1498.           { var reg1 object body_rest = STACK_0;
  1499.             STACK_0 = Cdr(body_rest); # restlicher Body
  1500.             body_rest = Car(body_rest); # nΣchstes Item
  1501.             if (consp(body_rest)) { eval(body_rest); } # Form -> auswerten
  1502.           }
  1503.         skipSTACK(1); # Body vergessen
  1504.         unwind(); # TAGBODY-Frame aufl÷sen
  1505.         unwind(); # GENV-Frame aufl÷sen
  1506.       }
  1507.       else
  1508.       # Body ohne Tags -> nur PROGN mit Wert NIL
  1509.       { skipSTACK(2); # GENV-Frame wieder aufl÷sen, GENV ist unverΣndert
  1510.         pushSTACK(body); implicit_prog();
  1511.       }
  1512.     value1 = NIL; mv_count=1; # Wert NIL
  1513.   }}
  1514.  
  1515. LISPSPECFORM(go, 1,0,nobody)
  1516. # (GO tag), CLTL S. 133
  1517.   { var reg3 object tag = popSTACK();
  1518.     if (!(numberp(tag) || (symbolp(tag) && (!nullp(tag)))))
  1519.       { pushSTACK(tag);
  1520.         pushSTACK(S(go));
  1521.         fehler(program_error,
  1522.                DEUTSCH ? "~: ~ ist keine zulΣssige Marke." :
  1523.                ENGLISH ? "~: illegal tag ~" :
  1524.                FRANCAIS ? "~: ~ n'est pas un marqueur permis." :
  1525.                ""
  1526.               );
  1527.       }
  1528.     # GO_ENV durchgehen:
  1529.    {var reg7 object env = aktenv.go_env; # aktuelles GO_ENV
  1530.     var reg8 object* FRAME;
  1531.     while (stack_env_p(env))
  1532.       { # env ist ein Frame-Pointer auf einen ITAGBODY-Frame im Stack.
  1533.         FRAME = uTheFramepointer(env);
  1534.         if (mtypecode(FRAME_(0)) & bit(nested_bit_t))
  1535.           # Frame schon genestet
  1536.           { env = FRAME_(frame_next_env); break; }
  1537.         # Tags im ungenesteten ITAGBODY-Frame absuchen:
  1538.         { var reg1 object* bind_ptr = &FRAME_(frame_bindings); # Pointer unter die Tagbindungen
  1539.           var reg2 object* bindend_ptr = STACKpointable(topofframe(FRAME_(0))); # Pointer ⁿber die Tagbindungen
  1540.           do { if (eql(*bind_ptr,tag)) # Tag gefunden?
  1541.                  { value1 = *(bind_ptr STACKop 1); # Formenliste aus dem Frame holen
  1542.                    goto found;
  1543.                  }
  1544.                bind_ptr skipSTACKop 2;
  1545.              }
  1546.              until (bind_ptr==bindend_ptr);
  1547.         }
  1548.         env = FRAME_(frame_next_env);
  1549.       }
  1550.     # env ist eine Aliste.
  1551.     while (consp(env))
  1552.       { var reg6 object tagbody_cons = Car(env);
  1553.         var reg5 object tagbody_vec = Car(tagbody_cons); # Tag-Vektor
  1554.         var reg1 object* tagptr = &TheSvector(tagbody_vec)->data[0];
  1555.         var reg4 uintL index = 0;
  1556.         var reg2 uintL count;
  1557.         dotimespL(count,TheSvector(tagbody_vec)->length,
  1558.           { if (eql(*tagptr++,tag)) # Tag gefunden?
  1559.               { env = Cdr(tagbody_cons);
  1560.                 if (eq(env,disabled)) # Tagbody noch aktiv?
  1561.                   { pushSTACK(tag);
  1562.                     pushSTACK(S(go));
  1563.                     fehler(control_error,
  1564.                            DEUTSCH ? "~: Tagbody zur Marke ~ wurde bereits verlassen." :
  1565.                            ENGLISH ? "~: tagbody for tag ~ has already been left" :
  1566.                            FRANCAIS ? "~: Le TAGBODY du marqueur ~ a dΘjα ΘtΘ quittΘ." :
  1567.                            ""
  1568.                           );
  1569.                   }
  1570.                 FRAME = uTheFramepointer(env); # Pointer auf den (noch aktiven!) Frame
  1571.                 value1 = FRAME_(frame_bindings+2*index+1); # Formenliste
  1572.                 goto found;
  1573.               }
  1574.             index++;
  1575.           });
  1576.         env = Cdr(env);
  1577.       }
  1578.     # env ist zu Ende.
  1579.     pushSTACK(tag);
  1580.     pushSTACK(S(go));
  1581.     fehler(program_error,
  1582.            DEUTSCH ? "~: Es ist keine Marke namens ~ sichtbar." :
  1583.            ENGLISH ? "~: no tag named ~ is currently visible" :
  1584.            FRANCAIS ? "~: Aucun marqueur de nom ~ n'est visible." :
  1585.            ""
  1586.           );
  1587.     # Tagbody-Frame gefunden. FRAME ist ein Pointer auf ihn (ohne Typinfo),
  1588.     # value1 die Liste der auszufⁿhrenden Formen.
  1589.     found:
  1590.     mv_count=1; # Formenliste value1 wird ⁿbergeben
  1591.     # Zum gefundenen Tagbody-Frame springen und dort weitermachen:
  1592.     unwind_upto(FRAME);
  1593.   }}
  1594.  
  1595. # Fehlermeldung bei zu vielen Werten
  1596. # fehler_mv_zuviel(caller);
  1597. # > caller: Aufrufer, ein Symbol
  1598.   nonreturning_function(global, fehler_mv_zuviel, (object caller));
  1599.   global void fehler_mv_zuviel(caller)
  1600.     var reg1 object caller;
  1601.     { pushSTACK(caller);
  1602.       fehler(error,
  1603.              DEUTSCH ? "~: Zu viele Werte." :
  1604.              ENGLISH ? "~: too many values" :
  1605.              FRANCAIS ? "~: Trop de valeurs." :
  1606.              ""
  1607.             );
  1608.     }
  1609.  
  1610. LISPFUN(values,0,0,rest,nokey,0,NIL)
  1611. # (VALUES {arg}), CLTL S. 134
  1612.   { if (argcount >= mv_limit) { fehler_mv_zuviel(S(values)); }
  1613.     STACK_to_mv(argcount);
  1614.   }
  1615.  
  1616. LISPFUNN(values_list,1)
  1617. # (VALUES-LIST list), CLTL S. 135
  1618.   { list_to_mv(popSTACK(), fehler_mv_zuviel(S(values_list)); ); }
  1619.  
  1620. LISPSPECFORM(multiple_value_list, 1,0,nobody)
  1621. # (MULTIPLE-VALUE-LIST form), CLTL S. 135
  1622.   { eval(popSTACK()); # form auswerten
  1623.     mv_to_list(); # Werte in Liste packen
  1624.     value1 = popSTACK(); mv_count=1; # Liste als Wert
  1625.   }
  1626.  
  1627. LISPSPECFORM(multiple_value_call, 1,0,body)
  1628. # (MULTIPLE-VALUE-CALL fun {form}), CLTL S. 135
  1629.   { var reg3 object* fun_ = &STACK_1;
  1630.     *fun_ = (eval(*fun_),value1); # Funktion auswerten
  1631.    {var reg1 object forms = popSTACK(); # Formenliste
  1632.     var reg2 uintL argcount = 0; # Anzahl der bisherigen Argumente
  1633.     while (consp(forms))
  1634.       { pushSTACK(Cdr(forms)); # restliche Formen
  1635.         eval(Car(forms)); # nΣchste Form auswerten
  1636.         forms = popSTACK();
  1637.         # Deren Werte in den Stack:
  1638.         argcount += (uintL)mv_count;
  1639.         mv_to_STACK();
  1640.       }
  1641.     if (((uintL)~(uintL)0 > ca_limit_1) && (argcount > ca_limit_1))
  1642.       { pushSTACK(*fun_);
  1643.         pushSTACK(S(multiple_value_call));
  1644.         fehler(error,
  1645.                DEUTSCH ? "~: Zu viele Argumente fⁿr ~" :
  1646.                ENGLISH ? "~: too many arguments to ~" :
  1647.                FRANCAIS ? "~: Trop d'arguments pour ~." :
  1648.                ""
  1649.               );
  1650.       }
  1651.     funcall(*fun_,argcount); # Funktion aufrufen
  1652.     skipSTACK(1);
  1653.   }}
  1654.  
  1655. LISPSPECFORM(multiple_value_prog1, 1,0,body)
  1656. # (MULTIPLE-VALUE-PROG1 form {form}), CLTL S. 136
  1657.   {  eval(STACK_1); # erste Form auswerten
  1658.    { var reg3 object body = popSTACK();
  1659.      skipSTACK(1);
  1660.     {var reg2 uintC mvcount = mv_count; # Wertezahl
  1661.      mv_to_STACK(); # alle Werte in den Stack
  1662.      pushSTACK(body); implicit_prog();
  1663.      STACK_to_mv(mvcount); # alle Werte wieder aus dem Stack zurⁿckholen
  1664.   }}}
  1665.  
  1666. LISPSPECFORM(multiple_value_bind, 2,0,body)
  1667. # (MULTIPLE-VALUE-BIND ({var}) values-form {decl} {form}), CLTL S. 136
  1668.   { # {decl} {form} trennen:
  1669.     var reg10 boolean to_compile = parse_dd(STACK_0,aktenv.var_env,aktenv.fun_env); # unvollstΣndiges var_env??
  1670.     # bitte kein Docstring:
  1671.     if (!nullp(value3)) { fehler_docstring(S(multiple_value_bind),STACK_0); }
  1672.     if (to_compile) # Deklaration (COMPILE) ?
  1673.       # ja -> Form kompilieren:
  1674.       { skipSTACK(3); return_Values compile_eval_form(); }
  1675.       else
  1676.       { var reg10 object varlist = STACK_2;
  1677.         STACK_2 = STACK_1;
  1678.         skipSTACK(2);
  1679.         # Variablenbindungsframe aufbauen, VAR_ENV erweitern:
  1680.        {var reg9 object* form_ = &STACK_0;
  1681.         var object* bind_ptr;
  1682.         var uintC bind_count;
  1683.         make_variable_frame(S(multiple_value_bind),varlist,&bind_ptr,&bind_count);
  1684.         # Stackaufbau: values-form, Variablenbindungsframe, Env-Bindungs-Frame, ({form}).
  1685.         # Dann values-form auswerten:
  1686.         eval(*form_);
  1687.         # Macro zum Binden von Variablen im Variablenframe:
  1688.         # Bindet die nΣchste Variable an value, erniedrigt frame_pointer um 2 bzw. 3.
  1689.         #define bind_next_var(value)  \
  1690.           { var reg3 object* valptr = &Next(frame_pointer);                   \
  1691.             frame_pointer skipSTACKop -varframe_binding_size;                 \
  1692.            {var reg2 object* markptr = &Before(frame_pointer);                \
  1693.             if (*(oint*)(markptr) & wbit(dynam_bit_o))                        \
  1694.               # dynamische Bindung aktivieren:                                \
  1695.               { var reg4 object sym = *(markptr STACKop varframe_binding_sym); # Variable \
  1696.                 *valptr = TheSymbolflagged(sym)->symvalue; # alten Wert in den Frame      \
  1697.                 *(oint*)(markptr) |= wbit(active_bit_o); # Bindung aktivieren             \
  1698.                 TheSymbolflagged(sym)->symvalue = (value); # neuen Wert in die Wertzelle  \
  1699.               }                                                               \
  1700.               else                                                            \
  1701.               # statische Bindung aktivieren:                                 \
  1702.               { *valptr = (value); # neuen Wert in den Frame                  \
  1703.                 *(oint*)(markptr) |= wbit(active_bit_o); # Bindung aktivieren \
  1704.               }                                                               \
  1705.           }}
  1706.         # Die r:=bind_count Variablen an die s:=mv_count Werte binden:
  1707.         # (Falls die Variablen ausgehen: restliche Werte wegwerfen;
  1708.         #  falls die Werte ausgehen: mit NIL auffⁿllen.)
  1709.         # Hier r>=0 und s>=0.
  1710.         { var reg5 object* frame_pointer = bind_ptr;
  1711.           var reg7 uintC r = bind_count;
  1712.           var reg6 object* mv_pointer;
  1713.           var reg8 uintC s = mv_count;
  1714.           if (r==0) goto ok; # keine Variablen?
  1715.           if (s==0) goto fill; # keine Werte?
  1716.           # noch min(r,s)>0 Werte binden:
  1717.           #if !defined(VALUE1_EXTRA)
  1718.           mv_pointer = &mv_space[0];
  1719.           #else
  1720.           bind_next_var(value1);
  1721.           if (--r == 0) goto ok; # keine Variablen mehr?
  1722.           if (--s == 0) goto fill; # keine Werte mehr?
  1723.           mv_pointer = &mv_space[1];
  1724.           #endif
  1725.           # noch min(r,s)>0 Werte binden:
  1726.           loop
  1727.             { bind_next_var(*mv_pointer++);
  1728.               if (--r == 0) goto ok; # keine Variablen mehr?
  1729.               if (--s == 0) goto fill; # keine Werte mehr?
  1730.             }
  1731.           fill: # Noch r>0 Variablen an NIL binden
  1732.           dotimespC(r,r, { bind_next_var(NIL); } );
  1733.           ok: ;
  1734.         }
  1735.         # Body abinterpretieren:
  1736.         implicit_progn(popSTACK(),NIL);
  1737.         # Frames aufl÷sen:
  1738.         unwind(); # VENV-Bindungsframe aufl÷sen
  1739.         unwind(); # Variablenbindungs-Frame aufl÷sen
  1740.         skipSTACK(1);
  1741.   }   }}
  1742.  
  1743. LISPSPECFORM(multiple_value_setq, 2,0,nobody)
  1744. # (MULTIPLE-VALUE-SETQ ({var}) form), CLTL S. 136
  1745.   { {var reg2 object varlist = STACK_1;
  1746.      # Variablenliste durchgehen:
  1747.      while (consp(varlist))
  1748.        { var reg1 object symbol = Car(varlist); # nΣchste Variable
  1749.          if (!symbolp(symbol)) # sollte ein Symbol
  1750.            { fehler_kein_symbol(S(multiple_value_setq),symbol); }
  1751.          if (constantp(TheSymbol(symbol))) # und keine Konstante sein
  1752.            { fehler_symbol_constant(S(multiple_value_setq),symbol); }
  1753.          if (sym_macrop(symbol)) # und kein Symbol-Macro
  1754.            goto expand;
  1755.          varlist = Cdr(varlist);
  1756.     }  }
  1757.     if (FALSE)
  1758.       { expand:
  1759.         pushSTACK(STACK_0); STACK_1 = STACK_2; STACK_2 = S(multiple_value_setf);
  1760.        {var reg1 object newform = listof(3); # aus MULTIPLE-VALUE-SETQ mache MULTIPLE-VALUE-SETF
  1761.         eval(newform);
  1762.       }}
  1763.       else
  1764.       {  eval(popSTACK()); # form auswerten
  1765.        { var reg4 object varlist = popSTACK();
  1766.          var reg5 object* args_end = args_end_pointer;
  1767.          mv_to_STACK(); # Werte in den Stack schreiben (erleichtert den Zugriff)
  1768.          # Variablenliste durchgehen:
  1769.         {var reg1 object* mvptr = args_end;
  1770.          var reg3 uintC count = mv_count; # Anzahl noch verfⁿgbarer Werte
  1771.          while (consp(varlist))
  1772.            { var reg2 object value;
  1773.              if (count>0)
  1774.                { value = NEXT(mvptr); count--; } # nΣchster Wert
  1775.                else
  1776.                { value = NIL; } # NIL, wenn alle Werte verbraucht
  1777.              setq(Car(varlist),value); # der nΣchsten Variablen zuweisen
  1778.              varlist = Cdr(varlist);
  1779.            }
  1780.          set_args_end_pointer(args_end); # STACK aufrΣumen
  1781.          mv_count=1; # letzter value1 als einziger Wert
  1782.   }   }}}
  1783.  
  1784. LISPSPECFORM(catch, 1,0,body)
  1785. # (CATCH tag {form}), CLTL S. 139
  1786.   { STACK_1 = (eval(STACK_1),value1); # tag auswerten
  1787.     # CATCH-Frame zu Ende aufbauen:
  1788.    {var reg1 object body = popSTACK(); # ({form})
  1789.     var reg2 object* top_of_frame = STACK STACKop 1; # Pointer ⁿbern Frame
  1790.     var jmp_buf returner; # Rⁿcksprungpunkt merken
  1791.     finish_entry_frame(CATCH,&!returner,, goto catch_return; );
  1792.     # Body ausfⁿhren:
  1793.     implicit_progn(body,NIL);
  1794.     catch_return: # Hierher wird gesprungen, wenn der oben aufgebaute
  1795.                   # Catch-Frame einen Throw gefangen hat.
  1796.     skipSTACK(3); # CATCH-Frame aufl÷sen
  1797.   }}
  1798.  
  1799. LISPSPECFORM(unwind_protect, 1,0,body)
  1800. # (UNWIND-PROTECT form {cleanup}), CLTL S. 140
  1801.   { var reg2 object cleanup = popSTACK();
  1802.     var reg3 object form = popSTACK();
  1803.     # UNWIND-PROTECT-Frame aufbauen:
  1804.     pushSTACK(cleanup);
  1805.    {var reg4 object* top_of_frame = STACK;
  1806.     var jmp_buf returner; # Rⁿcksprungpunkt
  1807.     finish_entry_frame(UNWIND_PROTECT,&!returner,, goto throw_save; );
  1808.     # Protected form auswerten:
  1809.     eval(form);
  1810.     # Cleanup nach normaler Beendigung der Protected form:
  1811.       # UNWIND-PROTECT-Frame aufl÷sen:
  1812.       skipSTACK(2);
  1813.       cleanup = popSTACK();
  1814.       # Werte retten:
  1815.      {var reg1 uintC mvcount = mv_count;
  1816.       mv_to_STACK();
  1817.       # Cleanup-Formen abarbeiten:
  1818.       pushSTACK(cleanup); implicit_prog();
  1819.       # Werte zurⁿckschreiben:
  1820.       STACK_to_mv(mvcount);
  1821.      }
  1822.     return;
  1823.     throw_save: # Hierher wird gesprungen, wenn der oben aufgebaute
  1824.                 # Unwind-Protect-Frame einen Throw aufgehalten hat.
  1825.                 # unwind_protect_to_save ist zu retten und am Schlu▀ anzuspringen.
  1826.     { var reg5 restart fun = unwind_protect_to_save.fun;
  1827.       var reg6 object* arg = unwind_protect_to_save.upto_frame;
  1828.     # Cleanup:
  1829.       # UNWIND-PROTECT-Frame aufl÷sen:
  1830.       skipSTACK(2);
  1831.       cleanup = popSTACK();
  1832.       # Werte retten:
  1833.      {var reg1 uintC mvcount = mv_count;
  1834.       mv_to_STACK();
  1835.       # Cleanup-Formen abarbeiten:
  1836.       pushSTACK(cleanup); implicit_prog();
  1837.       # Werte zurⁿckschreiben:
  1838.       STACK_to_mv(mvcount);
  1839.      }# und weiterspringen:
  1840.       fun(arg);
  1841.     }
  1842.   }}
  1843.  
  1844. LISPSPECFORM(throw, 2,0,nobody)
  1845. # (THROW tag result), CLTL S. 142
  1846.   { STACK_1 = (eval(STACK_1),value1); # tag auswerten
  1847.     eval(popSTACK()); # result auswerten
  1848.    {var reg1 object tag = popSTACK(); # ausgewertetes Tag
  1849.     throw(tag); # versuche auf dieses zu THROWen
  1850.     # Nicht gelungen.
  1851.     pushSTACK(tag);
  1852.     pushSTACK(S(throw));
  1853.     fehler(control_error,
  1854.            DEUTSCH ? "~: Es gibt kein CATCH zur Marke ~." :
  1855.            ENGLISH ? "~: there is no CATCHer for tag ~" :
  1856.            FRANCAIS ? "~: Il n'y a pas de CATCH correspondant au marqueur ~." :
  1857.            ""
  1858.           );
  1859.   }}
  1860.  
  1861. LISPFUNN(driver,1)
  1862. # (SYS::DRIVER fun) baut einen Driver-Frame auf, der jedesmal die Funktion
  1863. # fun (mit 0 Argumenten) aufruft. fun wird in einer Endlosschleife ausgefⁿhrt,
  1864. # die mit GO oder THROW abgebrochen werden kann.
  1865.   { var reg1 object* top_of_frame = STACK; # Pointer ⁿbern Frame
  1866.     var DRIVER_frame_data returner_and_data; # Einsprungpunkt merken
  1867.     #ifdef HAVE_NUM_STACK
  1868.     returner_and_data.old_NUM_STACK_normal = NUM_STACK_normal;
  1869.     #endif
  1870.     finish_entry_frame(DRIVER,&!returner_and_data.returner,,;);
  1871.     # Hier ist der Einsprungpunkt.
  1872.     loop { funcall(STACK_(0+2),0); } # fun aufrufen, Endlosschleife
  1873.   }
  1874.  
  1875. LISPFUNN(unwind_to_driver,0)
  1876. # (SYS::UNWIND-TO-DRIVER) macht ein UNWIND bis zum nΣchsth÷heren Driver-Frame.
  1877.   { reset(); }
  1878.  
  1879. # ▄berprⁿft ein optionales Macroexpansions-Environment in STACK_0.
  1880. # > STACK_0: Argument
  1881. # < STACK_0: Macroexpansions-Environment #(venv fenv)
  1882. # kann GC ausl÷sen
  1883.   local void test_env (void);
  1884.   local void test_env()
  1885.     { var reg1 object arg = STACK_0;
  1886.       if (eq(arg,unbound))
  1887.         { STACK_0 = allocate_vector(2); } # Vektor #(nil nil) als Default
  1888.       elif (!(simple_vector_p(arg) && (TheSvector(arg)->length == 2)))
  1889.         { pushSTACK(arg); # Wert fⁿr Slot DATUM von TYPE-ERROR
  1890.           pushSTACK(O(type_svector2)); # Wert fⁿr Slot EXPECTED-TYPE von TYPE-ERROR
  1891.           pushSTACK(arg);
  1892.           fehler(type_error,
  1893.                  DEUTSCH ? "Argument ~ ist kein Macroexpansions-Environment." :
  1894.                  ENGLISH ? "Argument ~ is not a macroexpansion environment" :
  1895.                  FRANCAIS ? "L'argument ~ n'est pas un environnement pour macros" :
  1896.                  ""
  1897.                 );
  1898.     }   }
  1899.  
  1900. LISPFUNN(macro_function,1)
  1901. # (MACRO-FUNCTION symbol), CLTL S. 144
  1902.   { var reg3 object symbol = popSTACK();
  1903.     if (!symbolp(symbol)) { fehler_symbol(symbol); }
  1904.    {var reg2 object fundef = Symbol_function(symbol); # globale Funktionsdefinition
  1905.     if (fsubrp(fundef))
  1906.       # ein FSUBR -> Propertyliste absuchen: (GET symbol 'SYS::MACRO)
  1907.       { var reg1 object got = get(symbol,S(macro)); # suchen
  1908.         if (eq(got,unbound)) goto nil; # nichts gefunden?
  1909.         value1 = got;
  1910.       }
  1911.     elif (consp(fundef) && eq(Car(fundef),S(macro))) # (SYS::MACRO . expander) ?
  1912.       { value1 = Cdr(fundef); }
  1913.     else # SUBR/Closure/#<UNBOUND> -> keine Macrodefinition
  1914.       { nil: value1 = NIL; }
  1915.     mv_count=1;
  1916.   }}
  1917.  
  1918. LISPFUN(macroexpand,1,1,norest,nokey,0,NIL)
  1919. # (MACROEXPAND form [env]), CLTL S. 151
  1920.   { test_env();
  1921.    {var reg1 object env = popSTACK();
  1922.     var reg2 object form = STACK_0;
  1923.     STACK_0 = env; # env retten
  1924.     macroexp0(form,env); # expandieren
  1925.     if (!nullp(value2)) # was getan?
  1926.       # ja -> zu Tode expandieren:
  1927.       { do { macroexp0(value1,STACK_0); } until (nullp(value2));
  1928.         value2 = T;
  1929.       }
  1930.     mv_count=2; skipSTACK(1);
  1931.   }}
  1932.  
  1933. LISPFUN(macroexpand_1,1,1,norest,nokey,0,NIL)
  1934. # (MACROEXPAND-1 form [env]), CLTL S. 151
  1935.   { test_env();
  1936.    {var reg1 object env = popSTACK();
  1937.     var reg2 object form = popSTACK();
  1938.     macroexp0(form,env); # 1 mal expandieren
  1939.     mv_count=2;
  1940.   }}
  1941.  
  1942. LISPSPECFORM(declare, 0,0,body)
  1943. # (DECLARE {decl-spec}), CLTL S. 153
  1944.   { # ({decl-spec}) bereits in STACK_0
  1945.     fehler(program_error,
  1946.            DEUTSCH ? "Deklarationen ~ an dieser Stelle nicht erlaubt." :
  1947.            ENGLISH ? "declarations ~ are not allowed here" :
  1948.            FRANCAIS ? "Les dΘclarations ~ ne sont pas permises α cet endroit." :
  1949.            ""
  1950.           );
  1951.   }
  1952.  
  1953. LISPSPECFORM(the, 2,0,nobody)
  1954. # (THE value-type form), CLTL S. 161
  1955.   { eval(STACK_0); # form auswerten
  1956.     mv_to_list(); # Werteliste bilden und retten
  1957.     # Stackaufbau: value-type, form, values.
  1958.     # zum Typ-Check (SYS::%THE values value-type) aufrufen:
  1959.     pushSTACK(STACK_0); pushSTACK(STACK_(2+1)); funcall(S(pthe),2);
  1960.     if (nullp(value1))
  1961.       # Typ-Check mi▀lang
  1962.       { pushSTACK(STACK_(2+0)); # value-type
  1963.         pushSTACK(STACK_(0+1)); # values
  1964.         pushSTACK(STACK_(1+2)); # form
  1965.         pushSTACK(S(the));
  1966.         fehler(error, # type_error ??
  1967.                DEUTSCH ? "~: Die Form ~ produzierte die Werte ~, nicht vom Typ ~" :
  1968.                ENGLISH ? "~: ~ evaluated to the values ~, not of type ~" :
  1969.                FRANCAIS ? "~: La forme ~ a produit les valeurs ~ qui ne sont pas de type ~." :
  1970.                ""
  1971.               );
  1972.       }
  1973.     # Typ-Check OK -> Werte zurⁿckgeben:
  1974.     list_to_mv(popSTACK(), { fehler_mv_zuviel(S(the)); } );
  1975.     skipSTACK(2);
  1976.   }
  1977.  
  1978. LISPFUNN(proclaim,1)
  1979. # (PROCLAIM decl-spec)
  1980.   { var reg3 object declspec = popSTACK();
  1981.     if (!consp(declspec))
  1982.       { pushSTACK(declspec);
  1983.         pushSTACK(S(proclaim));
  1984.         fehler(error,
  1985.                DEUTSCH ? "~: Falsche Deklaration: ~" :
  1986.                ENGLISH ? "~: bad declaration ~" :
  1987.                FRANCAIS ? "~: Mauvaise dΘclaration : ~" :
  1988.                ""
  1989.               );
  1990.       }
  1991.    {var reg4 object decltype = Car(declspec); # Deklarationstyp
  1992.     if (eq(decltype,S(special))) # SPECIAL
  1993.       { while (consp( declspec = Cdr(declspec) ))
  1994.           { var reg1 object symbol = Car(declspec);
  1995.             if (!symbolp(symbol)) { fehler_symbol(symbol); }
  1996.             if (!keywordp(symbol)) { clear_const_flag(TheSymbol(symbol)); }
  1997.             set_special_flag(TheSymbol(symbol));
  1998.       }   }
  1999.     elif (eq(decltype,S(declaration))) # DECLARATION
  2000.       { while (consp( declspec = Cdr(declspec) ))
  2001.           { var reg2 object symbol = Car(declspec);
  2002.             if (!symbolp(symbol)) { fehler_symbol(symbol); }
  2003.             # (PUSHNEW symbol (cdr declaration-types)) :
  2004.             { var reg1 object list = Cdr(O(declaration_types));
  2005.               while (consp(list))
  2006.                 { if (eq(Car(list),symbol)) goto not_adjoin;
  2007.                   list = Cdr(list);
  2008.             }   }
  2009.             pushSTACK(declspec); pushSTACK(symbol);
  2010.            {var reg1 object new_cons = allocate_cons();
  2011.             var reg2 object list = O(declaration_types);
  2012.             Car(new_cons) = popSTACK(); Cdr(new_cons) = Cdr(list);
  2013.             Cdr(list) = new_cons;
  2014.             declspec = popSTACK();
  2015.            }
  2016.             not_adjoin: ;
  2017.       }   }
  2018.     elif (eq(decltype,S(inline)) || eq(decltype,S(notinline))) # INLINE, NOTINLINE
  2019.       { pushSTACK(decltype);
  2020.         while (consp( declspec = Cdr(declspec) ))
  2021.           { var reg2 object symbol = Car(declspec);
  2022.             if (!funnamep(symbol)) { fehler_kein_symbol(S(proclaim),symbol); }
  2023.             # (SYS::%PUT (SYS::GET-FUNNAME-SYMBOL symbol) 'SYS::INLINABLE decltype) :
  2024.             pushSTACK(declspec);
  2025.             pushSTACK(symbol); funcall(S(get_funname_symbol),1); pushSTACK(value1);
  2026.             pushSTACK(S(inlinable));
  2027.             pushSTACK(STACK_(1+2));
  2028.             funcall(L(put),3);
  2029.             declspec = popSTACK();
  2030.           }
  2031.         skipSTACK(1);
  2032.       }
  2033.     # Alles restliche wird ignoriert.
  2034.     value1 = NIL; mv_count=1;
  2035.   }}
  2036.  
  2037. LISPFUNN(eval,1)
  2038. # (EVAL form), CLTL S. 321
  2039.   { eval_noenv(popSTACK()); } # form im leeren Environment auswerten
  2040.  
  2041. LISPSPECFORM(load_time_value, 1,1,nobody)
  2042. # (LOAD-TIME-VALUE form [read-only-p]), CLTL2 S. 680
  2043.   { var reg1 object form = STACK_1;
  2044.     skipSTACK(2); # read-only-p ignorieren
  2045.     eval_noenv(form); # form im leeren Environment auswerten
  2046.     mv_count=1;
  2047.   }
  2048.  
  2049. # UP: ▄berprⁿft ein optionales Environment-Argument fⁿr EVALHOOK und APPLYHOOK.
  2050. # test_optional_env_arg(&env5);
  2051. # > subr_self: Aufrufer (ein SUBR)
  2052. # < env5: 5 Komponenten des Environments
  2053. # erh÷ht STACK um 1
  2054.   local void test_optional_env_arg (environment* env5);
  2055.   local void test_optional_env_arg(env5)
  2056.     var reg2 environment* env5;
  2057.     { var reg1 object env = popSTACK(); # env-Argument
  2058.       if (eq(env,unbound)) # nicht angegeben -> leeres Environment
  2059.         { env5->var_env   = NIL;
  2060.           env5->fun_env   = NIL;
  2061.           env5->block_env = NIL;
  2062.           env5->go_env    = NIL;
  2063.           env5->decl_env  = O(top_decl_env);
  2064.         }
  2065.       elif (simple_vector_p(env) && (TheSvector(env)->length == 5))
  2066.         # ein Simple-Vector der LΣnge 5
  2067.         { env5->var_env   = TheSvector(env)->data[0];
  2068.           env5->fun_env   = TheSvector(env)->data[1];
  2069.           env5->block_env = TheSvector(env)->data[2];
  2070.           env5->go_env    = TheSvector(env)->data[3];
  2071.           env5->decl_env  = TheSvector(env)->data[4];
  2072.         }
  2073.       else
  2074.         { pushSTACK(env); # Wert fⁿr Slot DATUM von TYPE-ERROR
  2075.           pushSTACK(O(type_svector5)); # Wert fⁿr Slot EXPECTED-TYPE von TYPE-ERROR
  2076.           pushSTACK(env);
  2077.           pushSTACK(TheSubr(subr_self)->name);
  2078.           fehler(type_error,
  2079.                  DEUTSCH ? "~: ~ ist nicht als Environment geeignet." :
  2080.                  ENGLISH ? "~: ~ may not be used as an environment" :
  2081.                  FRANCAIS ? "~: ~ ne peut pas Ωtre utilisΘ comme environnement." :
  2082.                  ""
  2083.                 );
  2084.     }   }
  2085.  
  2086. LISPFUN(evalhook,3,1,norest,nokey,0,NIL)
  2087. # (EVALHOOK form evalhookfn applyhookfn [env]), CLTL S. 323
  2088.   { var environment env5;
  2089.     test_optional_env_arg(&env5); # env-Argument nach env5
  2090.    {var reg4 object applyhookfn = popSTACK();
  2091.     var reg3 object evalhookfn = popSTACK();
  2092.     var reg2 object form = popSTACK();
  2093.     bindhooks(evalhookfn,applyhookfn); # *EVALHOOK* und *APPLYHOOK* binden
  2094.     # Environment-Frame aufbauen:
  2095.     make_ENV5_frame();
  2096.     # aktuelle Environments setzen:
  2097.     aktenv = env5;
  2098.     # form unter Umgehung von *EVALHOOK* und *APPLYHOOK* auswerten:
  2099.     eval_no_hooks(form);
  2100.     unwind(); # Environment-Frame aufl÷sen
  2101.     unwind(); # Bindungsframe fⁿr *EVALHOOK* / *APPLYHOOK* aufl÷sen
  2102.   }}
  2103.  
  2104. LISPFUN(applyhook,4,1,norest,nokey,0,NIL)
  2105. # (APPLYHOOK function args evalhookfn applyhookfn [env]), CLTL S. 323
  2106.   { var environment env5;
  2107.     test_optional_env_arg(&env5); # env-Argument nach env5
  2108.    {var reg6 object applyhookfn = popSTACK();
  2109.     var reg5 object evalhookfn = popSTACK();
  2110.     var reg1 object args = popSTACK();
  2111.     var reg7 object fun = popSTACK();
  2112.     bindhooks(evalhookfn,applyhookfn); # *EVALHOOK* und *APPLYHOOK* binden
  2113.     # Environment-Frame aufbauen:
  2114.     make_ENV5_frame();
  2115.     # aktuelle Environments setzen:
  2116.     aktenv = env5;
  2117.     # fun retten:
  2118.     { pushSTACK(fun);
  2119.      {var reg3 object* fun_ = &STACK_0;
  2120.       # Argumente einzeln auswerten und auf dem Stack ablegen:
  2121.       var reg2 uintC argcount = 0;
  2122.       while (consp(args))
  2123.         { pushSTACK(Cdr(args)); # restliche Argumentliste
  2124.           eval_no_hooks(Car(args)); # nΣchstes arg auswerten
  2125.           args = STACK_0; STACK_0 = value1; # Wert im Stack ablegen
  2126.           argcount++;
  2127.           if (argcount==0) # ▄berlauf?
  2128.             { pushSTACK(*fun_);
  2129.               pushSTACK(S(applyhook));
  2130.               fehler(error,
  2131.                      DEUTSCH ? "~: Zu viele Argumente fⁿr ~" :
  2132.                      ENGLISH ? "~: too many arguments given to ~" :
  2133.                      FRANCAIS ? "~: Trop d'arguments fournis α ~." :
  2134.                      ""
  2135.                     );
  2136.         }   }
  2137.       funcall(*fun_,argcount); # Funktion anwenden
  2138.       skipSTACK(1);
  2139.     }}
  2140.     unwind(); # Environment-Frame aufl÷sen
  2141.     unwind(); # Bindungsframe fⁿr *EVALHOOK* / *APPLYHOOK* aufl÷sen
  2142.   }}
  2143.  
  2144. LISPFUNN(constantp,1)
  2145. # (CONSTANTP expr), CLTL S. 324
  2146.   { var reg1 object arg = popSTACK();
  2147.     switch (typecode(arg))
  2148.       { case_cons: # Cons
  2149.           if (eq(Car(arg),S(quote))) goto ja; else goto nein;
  2150.         case_symbol: # Symbol
  2151.           if (constantp(TheSymbol(arg))) goto ja; else goto nein;
  2152.         case_number: # Zahl
  2153.         case_char: # Character
  2154.         case_string: # String
  2155.         case_bvector: # Bit-Vektor
  2156.           goto ja;
  2157.         default:
  2158.           goto nein;
  2159.       }
  2160.     ja: value1 = T; mv_count=1; return;
  2161.     nein: value1 = NIL; mv_count=1; return;
  2162.   }
  2163.  
  2164. LISPFUNN(function_name_p,1)
  2165. # (SYS::FUNCTION-NAME-P expr) erkennt Funktionsnamen
  2166.   { var reg1 object arg = popSTACK();
  2167.     value1 = (funnamep(arg) ? T : NIL); mv_count=1;
  2168.   }
  2169.  
  2170. LISPFUN(parse_body,1,2,norest,nokey,0,NIL)
  2171. # (SYS::PARSE-BODY body [docstring-allowed [env]])
  2172. # parst body, erkennt Deklarationen, liefert 3 Werte:
  2173. # 1. body-rest, alle Formen nach den Deklarationen,
  2174. # 2. Liste der aufgetretenen declspecs
  2175. # 3. docstring (nur falls docstring-allowed=T war) oder NIL.
  2176. # (docstring-allowed sollte = NIL oder T sein,
  2177. #  env sollte ein Function-Environment sein.)
  2178.   { test_env();
  2179.    {var reg5 boolean docstring_allowed = (!eq(STACK_1,unbound) && !nullp(STACK_1)); # Docstrings erlaubt?
  2180.     var reg2 object body = STACK_2; # body = ({decl|doc} {form})
  2181.     STACK_1 = NIL; # Noch war kein Doc-String da
  2182.     pushSTACK(NIL); # Anfang decl-spec-Liste
  2183.     # Stackaufbau: body, docstring, env, declspecs.
  2184.     while (consp(body))
  2185.       {  pushSTACK(body); # body retten
  2186.        { var reg1 object form = Car(body); # nΣchste Form
  2187.          # evtl. macroexpandieren (ohne FSUBRs, Symbole zu expandieren):
  2188.          do { var reg1 object env = STACK_(1+1);
  2189.               macroexp(form,TheSvector(env)->data[0],TheSvector(env)->data[1]);
  2190.               form = value1;
  2191.             }
  2192.             until (nullp(value2));
  2193.          body = popSTACK();
  2194.         {var reg4 object body_rest = Cdr(body); # body verkⁿrzen
  2195.          if (stringp(form)) # Doc-String gefunden?
  2196.            { if (atomp(body_rest)) # an letzter Stelle der Formenliste?
  2197.                goto fertig; # ja -> letzte Form kann kein Doc-String sein!
  2198.              if (!docstring_allowed) # kein Doc-String erlaubt?
  2199.                { pushSTACK(STACK_3); # ganzer body
  2200.                  fehler(program_error,
  2201.                         DEUTSCH ? "Hier sind keine Doc-Strings erlaubt: ~" :
  2202.                         ENGLISH ? "no doc-strings allowed here: ~" :
  2203.                         FRANCAIS ? "Les chaεnes de documentation ne sont pas permises ici : ~" :
  2204.                         ""
  2205.                        );
  2206.                }
  2207.              if (!nullp(STACK_2)) # schon ein Doc-String dagewesen?
  2208.                # ja -> mehr als ein Doc-String ist zuviel:
  2209.                { pushSTACK(STACK_3); # ganzer body
  2210.                  fehler(program_error,
  2211.                         DEUTSCH ? "In ~ kommen zu viele Doc-Strings vor." :
  2212.                         ENGLISH ? "Too many documentation strings in ~" :
  2213.                         FRANCAIS ? "Trop de chaεnes de documentation apparaεssent dans ~." :
  2214.                         ""
  2215.                        );
  2216.                }
  2217.              STACK_2 = form; # neuer Doc-String
  2218.              body = body_rest;
  2219.            }
  2220.          elif (consp(form) && eq(Car(form),S(declare))) # Deklaration (DECLARE ...) ?
  2221.            { # neue decl-specs einzeln auf STACK_0 consen:
  2222.              pushSTACK(body_rest); # body_rest retten
  2223.              pushSTACK(Cdr(form)); # Liste der neuen decl-specs
  2224.              while (mconsp(STACK_0))
  2225.                { # Diese Deklaration auf STACK_(0+2) consen:
  2226.                  var reg3 object new_cons = allocate_cons();
  2227.                  Car(new_cons) = Car(STACK_0);
  2228.                  Cdr(new_cons) = STACK_(0+2);
  2229.                  STACK_(0+2) = new_cons;
  2230.                  # zum nΣchsten decl-spec:
  2231.                  STACK_0 = Cdr(STACK_0);
  2232.                }
  2233.              skipSTACK(1);
  2234.              body = popSTACK(); # body := alter body_rest
  2235.            }
  2236.          else
  2237.            { fertig: # fertig mit Durchlaufen der Formenliste
  2238.              #if 0 # Im Interpreter zwar eine gute Idee, aber der Compiler
  2239.                    # wird dadurch behindert, weil er dann CASE und HANDLER-BIND
  2240.                    # nicht so gut compilieren kann.
  2241.              if (!eq(form,Car(body))) # Sofern die Form expandiert wurde,
  2242.                # ersetze body durch (cons form (cdr body)) :
  2243.                { pushSTACK(body_rest); pushSTACK(form);
  2244.                  body = allocate_cons();
  2245.                  Car(body) = popSTACK(); # form
  2246.                  Cdr(body) = popSTACK(); # body_rest
  2247.                }
  2248.              #endif
  2249.              break;
  2250.            }
  2251.       }}}
  2252.     value1 = body;
  2253.     value2 = nreverse(popSTACK()); # decl-spec-Liste
  2254.     skipSTACK(1);
  2255.     value3 = popSTACK(); # Doc-String
  2256.     skipSTACK(1);
  2257.     mv_count=3; # 3 Werte: ({form}), declspecs, doc
  2258.   }}
  2259.  
  2260. LISPFUNN(keyword_test,2)
  2261. # (SYSTEM::KEYWORD-TEST arglist kwlist)
  2262. # stellt fest, ob in der Argumentliste arglist (eine paarige Keyword/Value -
  2263. # Liste) alle Keywords in der Liste kwlist  vorkommen oder aber
  2264. # ein Keyword/Value-Paar :ALLOW-OTHER-KEYS mit value /= NIL vorkommt.
  2265. # Wenn nein, Error.
  2266.   { var reg4 object arglist = STACK_1;
  2267.     # Argumente-Zahl ⁿberprⁿfen:
  2268.     { var reg1 uintL argcount = llength(arglist);
  2269.       if (!((argcount%2) == 0))
  2270.         { pushSTACK(arglist);
  2271.           fehler(error,
  2272.                  DEUTSCH ? "Keyword-Argumentliste ~ hat ungerade LΣnge." :
  2273.                  ENGLISH ? "keyword argument list ~ has an odd length" :
  2274.                  FRANCAIS ? "La liste de mots clΘ ~ est de longueur impaire." :
  2275.                  ""
  2276.                 );
  2277.     }   }
  2278.     # Suche, ob :ALLOW-OTHER-KEYS kommt:
  2279.     { var reg1 object arglistr = arglist;
  2280.       while (consp(arglistr))
  2281.         { if (eq(Car(arglistr),S(Kallow_other_keys)) && !nullp(Car(Cdr(arglistr))))
  2282.             goto fertig;
  2283.           arglistr = Cdr(Cdr(arglistr));
  2284.     }   }
  2285.     # Suche, ob alle angegebenen Keywords in kwlist vorkommen:
  2286.     { var reg3 object arglistr = arglist;
  2287.       while (consp(arglistr))
  2288.         { var reg2 object key = Car(arglistr);
  2289.           var reg1 object kwlistr = STACK_0;
  2290.           while (consp(kwlistr))
  2291.             { if (eq(Car(kwlistr),key)) goto found;
  2292.               kwlistr = Cdr(kwlistr);
  2293.             }
  2294.           # nicht gefunden
  2295.           pushSTACK(Car(Cdr(arglistr)));
  2296.           pushSTACK(key);
  2297.           fehler(error,
  2298.                  DEUTSCH ? "UnzulΣssiges Keyword/Wert-Paar ~, ~ in einer Argumentliste. Die erlaubten Keywords sind ~" :
  2299.                  ENGLISH ? "illegal keyword/value pair ~, ~ in argument list. The allowed keywords are ~" :
  2300.                  FRANCAIS ? "Paire mot-clΘ - valeur ~, ~ illicite dans une liste d'arguments. Les mots-clΘ permis sont ~" :
  2301.                  ""
  2302.                 );
  2303.           found: # gefunden. Weiter:
  2304.           arglistr = Cdr(Cdr(arglistr));
  2305.     }   }
  2306.     fertig:
  2307.     skipSTACK(2);
  2308.     value1 = NIL; mv_count=0; # keine Werte
  2309.   }
  2310.  
  2311. LISPSPECFORM(and, 0,0,body)
  2312. # (AND {form}), CLTL S. 82
  2313.   { var reg1 object body = popSTACK();
  2314.     if (atomp(body))
  2315.       { value1 = T; mv_count=1; } # (AND) -> T
  2316.       else
  2317.       loop
  2318.         { pushSTACK(Cdr(body));
  2319.           eval(Car(body)); # form auswerten
  2320.           body = popSTACK();
  2321.           if (atomp(body)) break; # am Schlu▀: Werte der letzten Form zurⁿck
  2322.           if (nullp(value1)) { mv_count=1; break; } # vorzeitig: 1 Wert NIL
  2323.         }
  2324.   }
  2325.  
  2326. LISPSPECFORM(or, 0,0,body)
  2327. # (OR {form}), CLTL S. 83
  2328.   { var reg1 object body = popSTACK();
  2329.     if (atomp(body))
  2330.       { value1 = NIL; mv_count=1; } # (OR) -> NIL
  2331.       else
  2332.       loop
  2333.         { pushSTACK(Cdr(body));
  2334.           eval(Car(body)); # form auswerten
  2335.           body = popSTACK();
  2336.           if (atomp(body)) break; # am Schlu▀: Werte der letzten Form zurⁿck
  2337.           if (!nullp(value1)) { mv_count=1; break; } # vorzeitig: 1 Wert /=NIL
  2338.         }
  2339.   }
  2340.  
  2341. # Ab jetzt hat der Tabellenmacro eine andere Verwendung:
  2342.   #undef LISPSPECFORM
  2343.  
  2344. # Tabelle aller Fsubr-Funktionen:
  2345.   global struct fsubr_tab_ fsubr_tab =
  2346.     {
  2347.       #define LISPSPECFORM LISPSPECFORM_D
  2348.       #include "fsubr.c"
  2349.       #undef LISPSPECFORM
  2350.     };
  2351.  
  2352.