📄 eval.c
字号:
Lisp_Object funcar; int numargs = nargs - 1; Lisp_Object lisp_numargs; Lisp_Object val; struct backtrace backtrace; struct gcpro gcpro1; register Lisp_Object *internal_args; register int i; QUIT; if (consing_since_gc > gc_cons_threshold) { GCPRO1 (*args); gcpro1.nvars = nargs; Fgarbage_collect (); UNGCPRO; } if (++lisp_eval_depth > max_lisp_eval_depth) { if (max_lisp_eval_depth < 100) max_lisp_eval_depth = 100; if (lisp_eval_depth > max_lisp_eval_depth) error ("Lisp nesting exceeds max-lisp-eval-depth"); } backtrace.next = backtrace_list; backtrace_list = &backtrace; backtrace.function = &args[0]; backtrace.args = &args[1]; backtrace.nargs = nargs - 1; backtrace.evalargs = 0; backtrace.debug_on_exit = 0; if (debug_on_next_call) do_debug_on_call (Qlambda); retry: fun = args[0]; while (XTYPE (fun) == Lisp_Symbol) { QUIT; val = XSYMBOL (fun)->function; if (EQ (val, Qunbound)) Fsymbol_function (fun); /* Get the right kind of error! */ fun = val; } if (XTYPE (fun) == Lisp_Subr) { if (numargs < XSUBR (fun)->min_args || (XSUBR (fun)->max_args >= 0 && XSUBR (fun)->max_args < numargs)) { XFASTINT (lisp_numargs) = numargs; return Fsignal (Qwrong_number_of_arguments, Fcons (fun, Fcons (lisp_numargs, Qnil))); } if (XSUBR (fun)->max_args == UNEVALLED) return Fsignal (Qinvalid_function, Fcons (fun, Qnil)); if (XSUBR (fun)->max_args == MANY) { val = (*XSUBR (fun)->function) (numargs, args + 1); goto done; } if (XSUBR (fun)->max_args > numargs) { internal_args = (Lisp_Object *) alloca (XSUBR (fun)->max_args * sizeof (Lisp_Object)); bcopy (args + 1, internal_args, numargs * sizeof (Lisp_Object)); for (i = numargs; i < XSUBR (fun)->max_args; i++) internal_args[i] = Qnil; } else internal_args = args + 1; switch (XSUBR (fun)->max_args) { case 0: val = (*XSUBR (fun)->function) (); goto done; case 1: val = (*XSUBR (fun)->function) (internal_args[0]); goto done; case 2: val = (*XSUBR (fun)->function) (internal_args[0], internal_args[1]); goto done; case 3: val = (*XSUBR (fun)->function) (internal_args[0], internal_args[1], internal_args[2]); goto done; case 4: val = (*XSUBR (fun)->function) (internal_args[0], internal_args[1], internal_args[2], internal_args[3]); goto done; case 5: val = (*XSUBR (fun)->function) (internal_args[0], internal_args[1], internal_args[2], internal_args[3], internal_args[4]); goto done; } } if (!CONSP (fun)) return Fsignal (Qinvalid_function, Fcons (fun, Qnil)); funcar = Fcar (fun); if (XTYPE (funcar) != Lisp_Symbol) return Fsignal (Qinvalid_function, Fcons (fun, Qnil)); if (EQ (funcar, Qlambda)) val = funcall_lambda (fun, numargs, args + 1); else if (EQ (funcar, Qmocklisp)) val = ml_apply (fun, Flist (numargs, args + 1)); else if (EQ (funcar, Qautoload)) { do_autoload (fun, args[0]); goto retry; } else return Fsignal (Qinvalid_function, Fcons (fun, Qnil)); done: lisp_eval_depth--; if (backtrace.debug_on_exit) val = call_debugger (Fcons (Qexit, Fcons (val, Qnil))); backtrace_list = backtrace.next; return val;}Lisp_Objectapply_lambda (fun, args, eval_flag) Lisp_Object fun, args; int eval_flag;{ Lisp_Object args_left; Lisp_Object numargs; register Lisp_Object *arg_vector; struct gcpro gcpro1, gcpro2, gcpro3; register int i; register Lisp_Object tem; numargs = Flength (args); arg_vector = (Lisp_Object *) alloca (XINT (numargs) * sizeof (Lisp_Object)); args_left = args; GCPRO3 (*arg_vector, args_left, fun); gcpro1.nvars = 0; for (i = 0; i < XINT (numargs);) { tem = Fcar (args_left), args_left = Fcdr (args_left); if (eval_flag) tem = Feval (tem); arg_vector[i++] = tem; gcpro1.nvars = i; } UNGCPRO; if (eval_flag) { backtrace_list->args = arg_vector; backtrace_list->nargs = i; } backtrace_list->evalargs = 0; tem = funcall_lambda (fun, XINT (numargs), arg_vector); /* Do the debug-on-exit now, while arg_vector still exists. */ if (backtrace_list->debug_on_exit) tem = call_debugger (Fcons (Qexit, Fcons (tem, Qnil))); /* Don't do it again when we return to eval. */ backtrace_list->debug_on_exit = 0; return tem;}Lisp_Objectfuncall_lambda (fun, nargs, arg_vector) Lisp_Object fun; int nargs; register Lisp_Object *arg_vector;{ Lisp_Object val, tem; register Lisp_Object syms_left; Lisp_Object numargs; register Lisp_Object next; int count = specpdl_ptr - specpdl; register int i; int optional = 0, rest = 0; specbind (Qmocklisp_arguments, Qt); /* t means NOT mocklisp! */ XFASTINT (numargs) = nargs; i = 0; for (syms_left = Fcar (Fcdr (fun)); !NULL (syms_left); syms_left = Fcdr (syms_left)) { QUIT; next = Fcar (syms_left); if (EQ (next, Qand_rest)) rest = 1; else if (EQ (next, Qand_optional)) optional = 1; else if (rest) { specbind (Fcar (syms_left), Flist (nargs - i, &arg_vector[i])); i = nargs; } else if (i < nargs) { tem = arg_vector[i++]; specbind (next, tem); } else if (!optional) return Fsignal (Qwrong_number_of_arguments, Fcons (fun, Fcons (numargs, Qnil))); else specbind (next, Qnil); } if (i < nargs) return Fsignal (Qwrong_number_of_arguments, Fcons (fun, Fcons (numargs, Qnil))); val = Fprogn (Fcdr (Fcdr (fun))); unbind_to (count); return val;}voidgrow_specpdl (){ register int count = specpdl_ptr - specpdl; if (specpdl_size >= max_specpdl_size) { if (max_specpdl_size < 400) max_specpdl_size = 400; if (specpdl_size >= max_specpdl_size) { Fsignal (Qerror, Fcons (build_string ("Variable binding depth exceeds max-specpdl-size"), Qnil)); max_specpdl_size *= 2; } } specpdl_size *= 2; if (specpdl_size > max_specpdl_size) specpdl_size = max_specpdl_size; specpdl = (struct specbinding *) xrealloc (specpdl, specpdl_size * sizeof (struct specbinding)); specpdl_ptr = specpdl + count;}voidspecbind (symbol, value) Lisp_Object symbol, value;{ extern void store_symval_forwarding (); /* in eval.c */ Lisp_Object ovalue; if (specpdl_ptr == specpdl + specpdl_size) grow_specpdl (); specpdl_ptr->symbol = symbol; specpdl_ptr->func = 0; ovalue = XSYMBOL (symbol)->value; specpdl_ptr->old_value = EQ (ovalue, Qunbound) ? Qunbound : Fsymbol_value (symbol); specpdl_ptr++; if (XTYPE (ovalue) == Lisp_Buffer_Objfwd) store_symval_forwarding (symbol, ovalue, value); else Fset (symbol, value);}voidrecord_unwind_protect (function, arg) Lisp_Object (*function)(); Lisp_Object arg;{ if (specpdl_ptr == specpdl + specpdl_size) grow_specpdl (); specpdl_ptr->func = function; specpdl_ptr->symbol = Qnil; specpdl_ptr->old_value = arg; specpdl_ptr++;}voidunbind_to (count) int count;{ int quitf = !NULL (Vquit_flag); Vquit_flag = Qnil; while (specpdl_ptr != specpdl + count) { --specpdl_ptr; if (specpdl_ptr->func != 0) (*specpdl_ptr->func) (specpdl_ptr->old_value); /* Note that a "binding" of nil is really an unwind protect, so in that case the "old value" is a list of forms to evaluate. */ else if (NULL (specpdl_ptr->symbol)) Fprogn (specpdl_ptr->old_value); else Fset (specpdl_ptr->symbol, specpdl_ptr->old_value); } if (NULL (Vquit_flag) && quitf) Vquit_flag = Qt;}#if 0/* Get the value of symbol's global binding, even if that binding is not now dynamically visible. */Lisp_Objecttop_level_value (symbol) Lisp_Object symbol;{ register struct specbinding *ptr = specpdl; CHECK_SYMBOL (symbol, 0); for (; ptr != specpdl_ptr; ptr++) { if (EQ (ptr->symbol, symbol)) return ptr->old_value; } return Fsymbol_value (symbol);}Lisp_Objecttop_level_set (symbol, newval) Lisp_Object symbol, newval;{ register struct specbinding *ptr = specpdl; CHECK_SYMBOL (symbol, 0); for (; ptr != specpdl_ptr; ptr++) { if (EQ (ptr->symbol, symbol)) { ptr->old_value = newval; return newval; } } return Fset (symbol, newval);} #endif /* 0 */DEFUN ("backtrace-debug", Fbacktrace_debug, Sbacktrace_debug, 2, 2, 0, "Set the debug-on-exit flag of eval frame LEVEL levels down to FLAG.\n\The debugger is entered when that frame exits, if the flag is non-nil.") (level, flag) Lisp_Object level, flag;{ register struct backtrace *backlist = backtrace_list; register int i; CHECK_NUMBER (level, 0); for (i = 0; backlist && i < XINT (level); i++) { backlist = backlist->next; } if (backlist) backlist->debug_on_exit = !NULL (flag); return flag;}DEFUN ("backtrace", Fbacktrace, Sbacktrace, 0, 0, "", "Print a trace of Lisp function calls currently active.\n\Output stream used is value of standard-output.") (){ register struct backtrace *backlist = backtrace_list; register int i; Lisp_Object tail; Lisp_Object tem; struct gcpro gcpro1; tail = Qnil; GCPRO1 (tail); while (backlist) { write_string (backlist->debug_on_exit ? "* " : " ", 2); if (backlist->nargs == UNEVALLED) write_string ("(", -1); tem = *backlist->function; Fprin1 (tem, Qnil); /* This can QUIT */ if (backlist->nargs == UNEVALLED) { if (backlist->evalargs) write_string (" ...computing arguments...", -1); else write_string (" ...", -1); } else if (backlist->nargs == MANY) { write_string ("(", -1); for (tail = *backlist->args, i = 0; !NULL (tail); tail = Fcdr (tail), i++) { if (i) write_string (" ", -1); Fprin1 (Fcar (tail), Qnil); } } else { write_string ("(", -1); for (i = 0; i < backlist->nargs; i++) { if (i) write_string (" ", -1); Fprin1 (backlist->args[i], Qnil); } } write_string (")\n", -1); backlist = backlist->next; } UNGCPRO; return Qnil;}syms_of_eval (){ DEFVAR_INT ("max-specpdl-size", &max_specpdl_size, "Limit on number of Lisp variable bindings & unwind-protects before error."); DEFVAR_INT ("max-lisp-eval-depth", &max_lisp_eval_depth, "Limit on depth in eval, apply and funcall before error."); DEFVAR_LISP ("quit-flag", &Vquit_flag, "Non-nil causes eval to abort, unless inhibit-quit is non-nil.\n\Typing C-G sets quit-flag non-nil, regardless of inhibit-quit."); Vquit_flag = Qnil; Qinhibit_quit = intern ("inhibit-quit"); staticpro (&Qinhibit_quit); DEFVAR_LISP ("inhibit-quit", &Vinhibit_quit, "Non-nil inhibits C-g quitting from happening immediately.\n\Note that quit-flag will still be set by typing C-g,\n\so a quit will be signalled as soon as inhibit-quit is nil.\n\To prevent this happening, set quit-flag to nil\n\before making inhibit-quit nil."); Vinhibit_quit = Qnil; Qautoload = intern ("autoload"); staticpro (&Qautoload); Qmacro = intern ("macro"); staticpro (&Qmacro); Qexit = intern ("exit"); staticpro (&Qexit); Qinteractive = intern ("interactive"); staticpro (&Qinteractive); Qcommandp = intern ("commandp"); staticpro (&Qcommandp); Qdefun = intern ("defun"); staticpro (&Qdefun); Qand_rest = intern ("&rest"); staticpro (&Qand_rest); Qand_optional = intern ("&optional"); staticpro (&Qand_optional); DEFVAR_BOOL ("stack-trace-on-error", &stack_trace_on_error, "*Non-nil means automatically display a backtrace buffer\n\after any error that is handled by the editor command loop."); stack_trace_on_error = 0; DEFVAR_BOOL ("debug-on-error", &debug_on_error, "*Non-nil means enter debugger if an error is signaled.\n\Does not apply to errors handled by condition-case.\n\See also variable debug-on-quit."); debug_on_error = 0; DEFVAR_BOOL ("debug-on-quit", &debug_on_quit, "*Non-nil means enter debugger if quit is signaled (C-G, for example).\n\Does not apply if quit is handled by a condition-case."); debug_on_quit = 0; DEFVAR_BOOL ("debug-on-next-call", &debug_on_next_call, "Non-nil means enter debugger before next eval, apply or funcall."); DEFVAR_LISP ("debugger", &Vdebugger, "Function to call to invoke debugger.\n\If due to frame exit, args are 'exit and value being returned;\n\ this function's value will be returned instead of that.\n\If due to error, args are 'error and list of signal's args.\n\If due to apply or funcall entry, one arg, 'lambda.\n\If due to eval entry, one arg, 't."); Vdebugger = Qnil; Qmocklisp_arguments = intern ("mocklisp-arguments"); staticpro (&Qmocklisp_arguments); DEFVAR_LISP ("mocklisp-arguments", &Vmocklisp_arguments, "While in a mocklisp function, the list of its unevaluated args."); Vmocklisp_arguments = Qt; staticpro (&Vautoload_queue); Vautoload_queue = Qnil; defsubr (&Sor); defsubr (&Sand); defsubr (&Sif); defsubr (&Scond); defsubr (&Sprogn); defsubr (&Sprog1); defsubr (&Sprog2); defsubr (&Ssetq); defsubr (&Squote); defsubr (&Sfunction); defsubr (&Sdefun); defsubr (&Sdefmacro); defsubr (&Sdefvar); defsubr (&Sdefconst); defsubr (&Suser_variable_p); defsubr (&Slet); defsubr (&SletX); defsubr (&Swhile); defsubr (&Smacroexpand); defsubr (&Scatch); defsubr (&Sthrow); defsubr (&Sunwind_protect); defsubr (&Scondition_case); defsubr (&Ssignal); defsubr (&Sinteractive_p); defsubr (&Scommandp); defsubr (&Sautoload); defsubr (&Seval); defsubr (&Sapply); defsubr (&Sfuncall); defsubr (&Sbacktrace_debug); defsubr (&Sbacktrace);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -