⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ceval.c

📁 python s60 1.4.5版本的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Portions Copyright (c) 2005 Nokia Corporation */

/* Execute compiled code */

/* XXX TO DO:
   XXX speed up searching for keywords by using a dictionary
   XXX document it!
   */

#include "Python.h"

#include "compile.h"
#include "frameobject.h"
#include "eval.h"
#include "opcode.h"
#include "structmember.h"

#ifdef macintosh
#include "macglue.h"
#endif

#include <ctype.h>

/* Turn this on if your compiler chokes on the big switch: */
/* #define CASE_TOO_BIG 1 */

#ifdef Py_DEBUG
/* For debugging the interpreter: */
#define LLTRACE  1	/* Low-level trace feature */
#define CHECKEXC 1	/* Double-check exception checking */
#endif

typedef PyObject *(*callproc)(PyObject *, PyObject *, PyObject *);

/* Forward declarations */
static PyObject *eval_frame(PyFrameObject *);
static PyObject *fast_function(PyObject *, PyObject ***, int, int, int);
static PyObject *fast_cfunction(PyObject *, PyObject ***, int);
static PyObject *do_call(PyObject *, PyObject ***, int, int);
static PyObject *ext_do_call(PyObject *, PyObject ***, int, int, int);
static PyObject *update_keyword_args(PyObject *, int, PyObject ***,PyObject *);
static PyObject *update_star_args(int, int, PyObject *, PyObject ***);
static PyObject *load_args(PyObject ***, int);
#define CALL_FLAG_VAR 1
#define CALL_FLAG_KW 2

#ifdef LLTRACE
static int prtrace(PyObject *, char *);
#endif
static int call_trace(Py_tracefunc, PyObject *, PyFrameObject *,
		      int, PyObject *);
static void call_trace_protected(Py_tracefunc, PyObject *,
				 PyFrameObject *, int);
static void call_exc_trace(Py_tracefunc, PyObject *, PyFrameObject *);
static PyObject *loop_subscript(PyObject *, PyObject *);
static PyObject *apply_slice(PyObject *, PyObject *, PyObject *);
static int assign_slice(PyObject *, PyObject *,
			PyObject *, PyObject *);
static PyObject *cmp_outcome(int, PyObject *, PyObject *);
static PyObject *import_from(PyObject *, PyObject *);
static int import_all_from(PyObject *, PyObject *);
static PyObject *build_class(PyObject *, PyObject *, PyObject *);
static int exec_statement(PyFrameObject *,
			  PyObject *, PyObject *, PyObject *);
static void set_exc_info(PyThreadState *, PyObject *, PyObject *, PyObject *);
static void reset_exc_info(PyThreadState *);
static void format_exc_check_arg(PyObject *, char *, PyObject *);

#define NAME_ERROR_MSG \
	"name '%.200s' is not defined"
#define GLOBAL_NAME_ERROR_MSG \
	"global name '%.200s' is not defined"
#define UNBOUNDLOCAL_ERROR_MSG \
	"local variable '%.200s' referenced before assignment"
#define UNBOUNDFREE_ERROR_MSG \
	"free variable '%.200s' referenced before assignment" \
        " in enclosing scope"

/* Dynamic execution profile */
#ifdef DYNAMIC_EXECUTION_PROFILE
#ifdef DXPAIRS
const static long dxpairs[257][256];
#define dxp dxpairs[256]
#else
const static long dxp[256];
#endif
#endif

#ifndef SYMBIAN
staticforward PyTypeObject gentype;
#else
#define gentype ((PYTHON_GLOBALS->tobj).t_gentype)
#endif

typedef struct {
	PyObject_HEAD
	/* The gi_ prefix is intended to remind of generator-iterator. */

	PyFrameObject *gi_frame;

	/* True if generator is being executed. */
	int gi_running;
} genobject;

static PyObject *
gen_new(PyFrameObject *f)
{
	genobject *gen = PyObject_New(genobject, &gentype);
	if (gen == NULL) {
		Py_DECREF(f);
		return NULL;
	}
	gen->gi_frame = f;
	gen->gi_running = 0;
	return (PyObject *)gen;
}

static int
gen_traverse(genobject *gen, visitproc visit, void *arg)
{
	return visit((PyObject *)gen->gi_frame, arg);
}

static void
gen_dealloc(genobject *gen)
{
	Py_DECREF(gen->gi_frame);
	PyObject_Del(gen);
}

static PyObject *
gen_iternext(genobject *gen)
{
	PyThreadState *tstate = PyThreadState_GET();
	PyFrameObject *f = gen->gi_frame;
	PyObject *result;

	if (gen->gi_running) {
		PyErr_SetString(PyExc_ValueError,
				"generator already executing");
		return NULL;
	}
	if (f->f_stacktop == NULL)
		return NULL;

	/* Generators always return to their most recent caller, not
	 * necessarily their creator. */
	Py_XINCREF(tstate->frame);
	assert(f->f_back == NULL);
	f->f_back = tstate->frame;

	gen->gi_running = 1;
	result = eval_frame(f);
	gen->gi_running = 0;

	/* Don't keep the reference to f_back any longer than necessary.  It
	 * may keep a chain of frames alive or it could create a reference
	 * cycle. */
	Py_XDECREF(f->f_back);
	f->f_back = NULL;

	/* If the generator just returned (as opposed to yielding), signal
	 * that the generator is exhausted. */
	if (result == Py_None && f->f_stacktop == NULL) {
		Py_DECREF(result);
		result = NULL;
	}

	return result;
}

static PyObject *
gen_next(genobject *gen)
{
	PyObject *result;

	result = gen_iternext(gen);

	if (result == NULL && !PyErr_Occurred()) {
		PyErr_SetObject(PyExc_StopIteration, Py_None);
		return NULL;
	}

	return result;
}

static PyObject *
gen_getiter(PyObject *gen)
{
	Py_INCREF(gen);
	return gen;
}

const static struct PyMethodDef gen_methods[] = {
	{"next",     (PyCFunction)gen_next, METH_NOARGS,
	 	"next() -- get the next value, or raise StopIteration"},
	{NULL,          NULL}   /* Sentinel */
};

const static PyMemberDef gen_memberlist[] = {
	{"gi_frame",	T_OBJECT, offsetof(genobject, gi_frame),	RO},
	{"gi_running",	T_INT,    offsetof(genobject, gi_running),	RO},
	{NULL}	/* Sentinel */
};

const PyTypeObject c_gentype = {
	PyObject_HEAD_INIT(NULL)
	0,					/* ob_size */
	"generator",				/* tp_name */
	sizeof(genobject),			/* tp_basicsize */
	0,					/* tp_itemsize */
	/* methods */
	(destructor)gen_dealloc, 		/* tp_dealloc */
	0,					/* tp_print */
	0, 					/* tp_getattr */
	0,					/* tp_setattr */
	0,					/* tp_compare */
	0,					/* tp_repr */
	0,					/* tp_as_number */
	0,					/* tp_as_sequence */
	0,					/* tp_as_mapping */
	0,					/* tp_hash */
	0,					/* tp_call */
	0,					/* tp_str */
	PyObject_GenericGetAttr,		/* tp_getattro */
	0,					/* tp_setattro */
	0,					/* tp_as_buffer */
	Py_TPFLAGS_DEFAULT,			/* tp_flags */
 	0,					/* tp_doc */
 	(traverseproc)gen_traverse,		/* tp_traverse */
 	0,					/* tp_clear */
	0,					/* tp_richcompare */
	0,					/* tp_weaklistoffset */
	(getiterfunc)gen_getiter,		/* tp_iter */
	(iternextfunc)gen_iternext,		/* tp_iternext */
	gen_methods,				/* tp_methods */
	gen_memberlist,				/* tp_members */
	0,					/* tp_getset */
	0,					/* tp_base */
	0,					/* tp_dict */
};


#ifdef WITH_THREAD

#ifndef DONT_HAVE_ERRNO_H
#include <errno.h>
#endif
#include "pythread.h"

#ifndef SYMBIAN
extern int _PyThread_Started; /* Flag for Py_Exit */
#else
#define _PyThread_Started (PYTHON_GLOBALS->_PyThread_Started)
#endif

#ifndef SYMBIAN
static PyThread_type_lock interpreter_lock = 0;
static long main_thread = 0;
#else
#define interpreter_lock (PYTHON_GLOBALS->interpreter_lock)
#define main_thread (PYTHON_GLOBALS->main_thread)
#endif

DL_EXPORT(void)
PyEval_InitThreads(void)
{
	if (interpreter_lock)
		return;
	_PyThread_Started = 1;
#ifndef SYMBIAN
	interpreter_lock = PyThread_allocate_lock();
	PyThread_acquire_lock(interpreter_lock, 1);
#else
	interpreter_lock = (void*)PyThread_allocate_lock();
	PyThread_acquire_lock(((PyThread_type_lock)interpreter_lock), 1);
#endif
	main_thread = PyThread_get_thread_ident();
}

DL_EXPORT(void)
PyEval_AcquireLock(void)
{
#ifndef SYMBIAN
	PyThread_acquire_lock(interpreter_lock, 1);
#else
	PyThread_acquire_lock((PyThread_type_lock)interpreter_lock, 1);
#endif
}

DL_EXPORT(void)
PyEval_ReleaseLock(void)
{
#ifndef SYMBIAN
	PyThread_release_lock(interpreter_lock);
#else
	PyThread_release_lock((PyThread_type_lock)interpreter_lock);
#endif
}

DL_EXPORT(void)
PyEval_AcquireThread(PyThreadState *tstate)
{
	if (tstate == NULL)
		Py_FatalError("PyEval_AcquireThread: NULL new thread state");
	PyThread_acquire_lock((PyThread_type_lock)interpreter_lock, 1);
	if (PyThreadState_Swap(tstate) != NULL)
		Py_FatalError(
			"PyEval_AcquireThread: non-NULL old thread state");
}

DL_EXPORT(void)
PyEval_ReleaseThread(PyThreadState *tstate)
{
	if (tstate == NULL)
		Py_FatalError("PyEval_ReleaseThread: NULL thread state");
	if (PyThreadState_Swap(NULL) != tstate)
		Py_FatalError("PyEval_ReleaseThread: wrong thread state");
	PyThread_release_lock((PyThread_type_lock)interpreter_lock);
}

/* This function is called from PyOS_AfterFork to ensure that newly
   created child processes don't hold locks referring to threads which
   are not running in the child process.  (This could also be done using
   pthread_atfork mechanism, at least for the pthreads implementation.) */

DL_EXPORT(void)
PyEval_ReInitThreads(void)
{
	if (!(interpreter_lock))
		return;
	/*XXX Can't use PyThread_free_lock here because it does too
	  much error-checking.  Doing this cleanly would require
	  adding a new function to each thread_*.h.  Instead, just
	  create a new lock and waste a little bit of memory */
	interpreter_lock = PyThread_allocate_lock();
	PyThread_acquire_lock(interpreter_lock, 1);
	main_thread = PyThread_get_thread_ident();
}
#endif

/* Functions save_thread and restore_thread are always defined so
   dynamically loaded modules needn't be compiled separately for use
   with and without threads: */

DL_EXPORT(PyThreadState *)
PyEval_SaveThread(void)
{
	PyThreadState *tstate = PyThreadState_Swap(NULL);
	if (tstate == NULL)
		Py_FatalError("PyEval_SaveThread: NULL tstate");
#ifdef WITH_THREAD
	if (interpreter_lock)
		PyThread_release_lock(interpreter_lock);
#endif
	return tstate;
}

DL_EXPORT(void)
PyEval_RestoreThread(PyThreadState *tstate)
{
	if (tstate == NULL)
		Py_FatalError("PyEval_RestoreThread: NULL tstate");
#ifdef WITH_THREAD
	if (interpreter_lock) {
		int err = errno;
		PyThread_acquire_lock(interpreter_lock, 1);
		errno = err;
	}
#endif
	PyThreadState_Swap(tstate);
}


/* Mechanism whereby asynchronously executing callbacks (e.g. UNIX
   signal handlers or Mac I/O completion routines) can schedule calls
   to a function to be called synchronously.
   The synchronous function is called with one void* argument.
   It should return 0 for success or -1 for failure -- failure should
   be accompanied by an exception.

   If registry succeeds, the registry function returns 0; if it fails
   (e.g. due to too many pending calls) it returns -1 (without setting
   an exception condition).

   Note that because registry may occur from within signal handlers,
   or other asynchronous events, calling malloc() is unsafe!

#ifdef WITH_THREAD
   Any thread can schedule pending calls, but only the main thread
   will execute them.
#endif

   XXX WARNING!  ASYNCHRONOUSLY EXECUTING CODE!
   There are two possible race conditions:
   (1) nested asynchronous registry calls;
   (2) registry calls made while pending calls are being processed.
   While (1) is very unlikely, (2) is a real possibility.
   The current code is safe against (2), but not against (1).
   The safety against (2) is derived from the fact that only one
   thread (the main thread) ever takes things out of the queue.

   XXX Darn!  With the advent of thread state, we should have an array
   of pending calls per thread in the thread state!  Later...
*/

#define NPENDINGCALLS 32
#ifndef SYMBIAN
const static struct {
	int (*func)(void *);
	void *arg;
} pendingcalls[NPENDINGCALLS];
static volatile int pendingfirst = 0;
static volatile int pendinglast = 0;
static volatile int things_to_do = 0;
#else
#define pendingcalls (PYTHON_GLOBALS->pendingcalls)
#define pendingfirst (PYTHON_GLOBALS->pendingfirst)
#define pendinglast (PYTHON_GLOBALS->pendinglast)
#define things_to_do (PYTHON_GLOBALS->things_to_do)
#endif

DL_EXPORT(int)
Py_AddPendingCall(int (*func)(void *), void *arg)
{
#ifndef SYMBIAN
  	static int busy = 0;
#endif
	int i, j;

#ifdef SYMBIAN
	int* pbusy = &(PYTHON_GLOBALS->add_pending_call_busy);
#define busy (*pbusy)
#endif
	/* XXX Begin critical section */
	/* XXX If you want this to be safe against nested
	   XXX asynchronous calls, you'll have to work harder! */
	if (busy)
		return -1;
	busy = 1;
	i = pendinglast;
	j = (i + 1) % NPENDINGCALLS;
	if (j == pendingfirst)
		return -1; /* Queue full */
	pendingcalls[i].func = func;
	pendingcalls[i].arg = arg;
	pendinglast = j;
	things_to_do = 1; /* Signal main loop */
	busy = 0;
	/* XXX End critical section */
	return 0;
#ifdef SYMBIAN
#undef busy
#endif
}

DL_EXPORT(int)
Py_MakePendingCalls(void)
{
#ifndef SYMBIAN
  	static int busy = 0;
#else
        int* pbusy = &(PYTHON_GLOBALS->make_pending_calls_busy);
#define busy (*pbusy)
#endif
#ifdef WITH_THREAD
	if (main_thread && PyThread_get_thread_ident() != main_thread)
		return 0;
#endif
	if (busy)
		return 0;
	busy = 1;
	things_to_do = 0;
	for (;;) {
		int i;
		int (*func)(void *);
		void *arg;
		i = pendingfirst;
		if (i == pendinglast)
			break; /* Queue empty */
		func = pendingcalls[i].func;
		arg = pendingcalls[i].arg;
		pendingfirst = (i + 1) % NPENDINGCALLS;
		if (func(arg) < 0) {
			busy = 0;
			things_to_do = 1; /* We're not done yet */
			return -1;
		}
	}
	busy = 0;
	return 0;
#ifdef SYMBIAN
#undef busy
#endif
}


/* The interpreter's recursion limit */

#ifndef SYMBIAN
static int recursion_limit = 1000;
#else
#define recursion_limit (PYTHON_GLOBALS->recursion_limit)
#endif

DL_EXPORT(int)
Py_GetRecursionLimit(void)
{
#ifdef SYMBIAN
	if (!recursion_limit)
		recursion_limit = 1000;
#endif
	return recursion_limit;
}

DL_EXPORT(void)
Py_SetRecursionLimit(int new_limit)
{
	recursion_limit = new_limit;
}

/* Status code for main loop (reason for stack unwind) */

enum why_code {
		WHY_NOT,	/* No error */
		WHY_EXCEPTION,	/* Exception occurred */
		WHY_RERAISE,	/* Exception re-raised by 'finally' */
		WHY_RETURN,	/* 'return' statement */
		WHY_BREAK,	/* 'break' statement */
		WHY_CONTINUE,	/* 'continue' statement */
		WHY_YIELD	/* 'yield' operator */
};

static enum why_code do_raise(PyObject *, PyObject *, PyObject *);
static int unpack_iterable(PyObject *, int, PyObject **);


DL_EXPORT(PyObject *)
PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals)
{
	return PyEval_EvalCodeEx(co,
			  globals, locals,
			  (PyObject **)NULL, 0,
			  (PyObject **)NULL, 0,
			  (PyObject **)NULL, 0,
			  NULL);
}


/* Interpreter main loop */

static PyObject *
eval_frame(PyFrameObject *f)
{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -