diff options
72 files changed, 3302 insertions, 2000 deletions
diff --git a/Include/allobjects.h b/Include/allobjects.h new file mode 100644 index 0000000..ed37609 --- /dev/null +++ b/Include/allobjects.h @@ -0,0 +1,26 @@ +/* "allobjects.c" -- Source for precompiled header "allobjects.h" */ + +#include <stdio.h> +#include "string.h" + +#include "PROTO.h" + +#include "object.h" +#include "objimpl.h" + +#include "intobject.h" +#include "floatobject.h" +#include "stringobject.h" +#include "tupleobject.h" +#include "listobject.h" +#include "dictobject.h" +#include "methodobject.h" +#include "moduleobject.h" +#include "funcobject.h" +#include "classobject.h" +#include "fileobject.h" + +#include "errors.h" +#include "malloc.h" + +extern char *strdup PROTO((const char *)); diff --git a/Include/bltinmodule.h b/Include/bltinmodule.h new file mode 100644 index 0000000..1f7f67b --- /dev/null +++ b/Include/bltinmodule.h @@ -0,0 +1,3 @@ +/* Built-in module interface */ + +extern object *getbuiltin PROTO((char *)); diff --git a/Include/ceval.h b/Include/ceval.h new file mode 100644 index 0000000..1495bb7 --- /dev/null +++ b/Include/ceval.h @@ -0,0 +1,9 @@ +/* Interface to execute compiled code */ +/* This header depends on "compile.h" */ + +object *eval_code PROTO((codeobject *, object *, object *, object *)); + +object *getglobals PROTO((void)); +object *getlocals PROTO((void)); + +void printtraceback PROTO((FILE *)); diff --git a/Include/classobject.h b/Include/classobject.h index 0514634..4b947b5 100644 --- a/Include/classobject.h +++ b/Include/classobject.h @@ -12,7 +12,7 @@ extern typeobject Classtype, Classmembertype, Classmethodtype; #define is_classmemberobject(op) ((op)->ob_type == &Classmembertype) #define is_classmethodobject(op) ((op)->ob_type == &Classmethodtype) -extern object *newclassobject PROTO((node *, object *, object *)); +extern object *newclassobject PROTO((object *, object *)); extern object *newclassmemberobject PROTO((object *)); extern object *newclassmethodobject PROTO((object *, object *)); diff --git a/Include/compile.h b/Include/compile.h new file mode 100644 index 0000000..3306930 --- /dev/null +++ b/Include/compile.h @@ -0,0 +1,23 @@ +/* Definitions for compiled intermediate code */ + + +/* An intermediate code fragment contains: + - a string that encodes the instructions, + - a list of the constants, + - and a list of the names used. */ + +typedef struct { + OB_HEAD + stringobject *co_code; /* instruction opcodes */ + object *co_consts; /* list of immutable constant objects */ + object *co_names; /* list of stringobjects */ + object *co_filename; /* string */ +} codeobject; + +extern typeobject Codetype; + +#define is_codeobject(op) ((op)->ob_type == &Codetype) + + +/* Public interface */ +codeobject *compile PROTO((struct _node *, char *)); diff --git a/Include/errors.h b/Include/errors.h index f0e3762..21c57d1 100755 --- a/Include/errors.h +++ b/Include/errors.h @@ -7,7 +7,7 @@ int err_occurred PROTO((void)); void err_get PROTO((object **, object **)); void err_clear PROTO((void)); -/* Predefined exceptions (in run.c) */ +/* Predefined exceptions */ extern object *RuntimeError; extern object *EOFError; @@ -29,5 +29,6 @@ extern object *KeyboardInterrupt; extern int err_badarg PROTO((void)); extern object *err_nomem PROTO((void)); extern object *err_errno PROTO((object *)); +extern void err_input PROTO((int)); extern void err_badcall PROTO((void)); diff --git a/Include/frameobject.h b/Include/frameobject.h new file mode 100644 index 0000000..92d18d7 --- /dev/null +++ b/Include/frameobject.h @@ -0,0 +1,56 @@ +/* Frame object interface */ + +typedef struct { + int b_type; /* what kind of block this is */ + int b_handler; /* where to jump to find handler */ + int b_level; /* value stack level to pop to */ +} block; + +typedef struct _frame { + OB_HEAD + struct _frame *f_back; /* previous frame, or NULL */ + codeobject *f_code; /* code segment */ + object *f_globals; /* global symbol table (dictobject) */ + object *f_locals; /* local symbol table (dictobject) */ + object **f_valuestack; /* malloc'ed array */ + block *f_blockstack; /* malloc'ed array */ + int f_nvalues; /* size of f_valuestack */ + int f_nblocks; /* size of f_blockstack */ + int f_iblock; /* index in f_blockstack */ +} frameobject; + + +/* Standard object interface */ + +extern typeobject Frametype; + +#define is_frameobject(op) ((op)->ob_type == &Frametype) + +frameobject * newframeobject PROTO( + (frameobject *, codeobject *, object *, object *, int, int)); + + +/* The rest of the interface is specific for frame objects */ + +/* List access macros */ + +#ifdef NDEBUG +#define GETITEM(v, i) GETLISTITEM((listobject *)(v), (i)) +#define GETITEMNAME(v, i) GETSTRINGVALUE((stringobject *)GETITEM((v), (i))) +#else +#define GETITEM(v, i) getlistitem((v), (i)) +#define GETITEMNAME(v, i) getstringvalue(getlistitem((v), (i))) +#endif + +#define GETUSTRINGVALUE(s) ((unsigned char *)GETSTRINGVALUE(s)) + +/* Code access macros */ + +#define Getconst(f, i) (GETITEM((f)->f_code->co_consts, (i))) +#define Getname(f, i) (GETITEMNAME((f)->f_code->co_names, (i))) + + +/* Block management functions */ + +void setup_block PROTO((frameobject *, int, int, int)); +block *pop_block PROTO((frameobject *)); diff --git a/Include/grammar.h b/Include/grammar.h index 423d862..07ce2b9 100644 --- a/Include/grammar.h +++ b/Include/grammar.h @@ -76,3 +76,6 @@ void translatelabels PROTO((grammar *g)); void addfirstsets PROTO((grammar *g)); void addaccellerators PROTO((grammar *g)); + +void printgrammar PROTO((grammar *g, FILE *fp)); +void printnonterminals PROTO((grammar *g, FILE *fp)); diff --git a/Include/import.h b/Include/import.h index cdeb3d1..4cdb6eb 100644 --- a/Include/import.h +++ b/Include/import.h @@ -1,5 +1,7 @@ /* Module definition and import interface */ -object *new_module PROTO((char *name)); -object *import_module PROTO((struct _context *ctx, char *name)); -object *reload_module PROTO((struct _context *ctx, object *m)); +object *get_modules PROTO((void)); +object *add_module PROTO((char *name)); +object *import_module PROTO((char *name)); +object *reload_module PROTO((object *m)); +void doneimport PROTO((void)); diff --git a/Include/listobject.h b/Include/listobject.h index 5ff057e..4a2bd72 100644 --- a/Include/listobject.h +++ b/Include/listobject.h @@ -14,6 +14,11 @@ inserted in the list. Similarly, getlistitem does not increment the returned item's reference count. */ +typedef struct { + OB_VARHEAD + object **ob_item; +} listobject; + extern typeobject Listtype; #define is_listobject(op) ((op)->ob_type == &Listtype) @@ -25,3 +30,6 @@ extern int setlistitem PROTO((object *, int, object *)); extern int inslistitem PROTO((object *, int, object *)); extern int addlistitem PROTO((object *, object *)); extern int sortlist PROTO((object *)); + +/* Macro, trading safety for speed */ +#define GETLISTITEM(op, i) ((op)->ob_item[i]) diff --git a/Include/methodobject.h b/Include/methodobject.h index b11ccd7..9dd05b4 100644 --- a/Include/methodobject.h +++ b/Include/methodobject.h @@ -9,3 +9,10 @@ typedef object *(*method) FPROTO((object *, object *)); extern object *newmethodobject PROTO((char *, method, object *)); extern method getmethod PROTO((object *)); extern object *getself PROTO((object *)); + +struct methodlist { + char *ml_name; + method ml_meth; +}; + +extern object *findmethod PROTO((struct methodlist *, object *, char *)); diff --git a/Include/modsupport.h b/Include/modsupport.h index d406bf6..db63eb5 100644 --- a/Include/modsupport.h +++ b/Include/modsupport.h @@ -1,9 +1,3 @@ /* Module support interface */ -struct methodlist { - char *ml_name; - method ml_meth; -}; - -extern object *findmethod PROTO((struct methodlist *, object *, char *)); extern object *initmodule PROTO((char *, struct methodlist *)); diff --git a/Include/moduleobject.h b/Include/moduleobject.h index 99d3d52..c9ce6ad 100644 --- a/Include/moduleobject.h +++ b/Include/moduleobject.h @@ -6,5 +6,4 @@ extern typeobject Moduletype; extern object *newmoduleobject PROTO((char *)); extern object *getmoduledict PROTO((object *)); -extern int setmoduledict PROTO((object *, object *)); extern char *getmodulename PROTO((object *)); diff --git a/Include/node.h b/Include/node.h index 9730e57..ff2ca7c 100644 --- a/Include/node.h +++ b/Include/node.h @@ -3,13 +3,14 @@ typedef struct _node { int n_type; char *n_str; + int n_lineno; int n_nchildren; struct _node *n_child; } node; -extern node *newnode PROTO((int type)); -extern node *addchild PROTO((node *n, int type, char *str)); -extern void freenode PROTO((node *n)); +extern node *newtree PROTO((int type)); +extern node *addchild PROTO((node *n, int type, char *str, int lineno)); +extern void freetree PROTO((node *n)); /* Node access functions */ #define NCH(n) ((n)->n_nchildren) @@ -28,3 +29,6 @@ extern void freenode PROTO((node *n)); abort(); \ } } #endif + +extern void listtree PROTO((node *)); +extern void listnode PROTO((FILE *, node *)); diff --git a/Include/object.h b/Include/object.h index dcfdfb4..c0deb7d 100644 --- a/Include/object.h +++ b/Include/object.h @@ -1,3 +1,4 @@ +#define NDEBUG /* Object and type object interface */ /* @@ -47,11 +48,15 @@ whose size is determined when the object is allocated. 123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 */ -#ifdef THINK_C -/* Debugging options for THINK_C (which has no -D compiler option): */ -/*#define TRACE_REFS*/ -/*#define REF_DEBUG*/ -#endif +#ifndef NDEBUG + +/* Turn on heavy reference debugging */ +#define TRACE_REFS + +/* Turn on reference counting */ +#define REF_DEBUG + +#endif /* NDEBUG */ #ifdef TRACE_REFS #define OB_HEAD \ @@ -147,9 +152,12 @@ extern typeobject Typetype; /* The type of type objects */ #define is_typeobject(op) ((op)->ob_type == &Typetype) +/* Generic operations on objects */ extern void printobject PROTO((object *, FILE *, int)); extern object * reprobject PROTO((object *)); extern int cmpobject PROTO((object *, object *)); +extern object *getattr PROTO((object *, char *)); +extern int setattr PROTO((object *, char *, object *)); /* Flag bits for printing: */ #define PRINT_RAW 1 /* No string quotes etc. */ @@ -215,6 +223,10 @@ extern long ref_total; DELREF(op) #endif +/* Macros to use in case the object pointer may be NULL: */ + +#define XINCREF(op) if ((op) == NULL) ; else INCREF(op) +#define XDECREF(op) if ((op) == NULL) ; else DECREF(op) /* Definition of NULL, so you don't have to include <stdio.h> */ @@ -252,22 +264,12 @@ Failure Modes ------------- Functions may fail for a variety of reasons, including running out of -memory. This is communicated to the caller in two ways: 'errno' is set -to indicate the error, and the function result differs: functions that -normally return a pointer return nil for failure, functions returning -an integer return -1 (which can be a legal return value too!), and -other functions return 0 for success and the error number for failure. -Callers should always check for errors before using the result. The -following error codes are used: - - EBADF bad object type (first argument only) - EINVAL bad argument type (second and further arguments) - ENOMEM no memory (malloc failed) - ENOENT key not found in dictionary - EDOM index out of range or division by zero - ERANGE result not representable - - XXX any others? +memory. This is communicated to the caller in two ways: an error string +is set (see errors.h), and the function result differs: functions that +normally return a pointer return NULL for failure, functions returning +an integer return -1 (which could be a legal return value too!), and +other functions return 0 for success and -1 for failure. +Callers should always check for errors before using the result. Reference Counts ---------------- @@ -296,16 +298,3 @@ times. 123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 */ - -/* Error number interface */ -#include <errno.h> - -#ifndef errno -extern int errno; -#endif - -#ifdef THINK_C -/* Lightspeed C doesn't define these in <errno.h> */ -#define EDOM 33 -#define ERANGE 34 -#endif diff --git a/Include/objimpl.h b/Include/objimpl.h index e6f9929..4ed2975 100644 --- a/Include/objimpl.h +++ b/Include/objimpl.h @@ -24,8 +24,3 @@ extern varobject *newvarobject PROTO((typeobject *, unsigned int)); #define NEWVAROBJ(type, typeobj, n) ((type *) newvarobject(typeobj, n)) extern int StopPrint; /* Set when printing is interrupted */ - -/* Malloc interface */ -#include "malloc.h" - -extern char *strdup PROTO((const char *)); diff --git a/Include/opcode.h b/Include/opcode.h index a4fe6b2..b0dc71d 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -1,9 +1,10 @@ /* Instruction opcodes for compiled code */ -#define DUP_TOP 0 +#define STOP_CODE 0 #define POP_TOP 1 #define ROT_TWO 2 #define ROT_THREE 3 +#define DUP_TOP 4 #define UNARY_POSITIVE 10 #define UNARY_NEGATIVE 11 @@ -76,5 +77,9 @@ #define SETUP_EXCEPT 121 /* "" */ #define SETUP_FINALLY 122 /* "" */ +#define SET_LINENO 127 /* Current line number */ + /* Comparison operator codes (argument to COMPARE_OP) */ enum cmp_op {LT, LE, EQ, NE, GT, GE, IN, NOT_IN, IS, IS_NOT, EXC_MATCH, BAD}; + +#define HAS_ARG(op) ((op) >= HAVE_ARGUMENT) diff --git a/Include/parsetok.h b/Include/parsetok.h index c8142b0..07d9715 100644 --- a/Include/parsetok.h +++ b/Include/parsetok.h @@ -1,9 +1,5 @@ /* Parser-tokenizer link interface */ -#if 0 -extern int parsetok PROTO((struct tok_state *, grammar *, int start, - node **n_ret)); -#endif extern int parsestring PROTO((char *, grammar *, int start, node **n_ret)); -extern int parsefile PROTO((FILE *, grammar *, int start, +extern int parsefile PROTO((FILE *, char *, grammar *, int start, char *ps1, char *ps2, node **n_ret)); diff --git a/Include/pgenheaders.h b/Include/pgenheaders.h new file mode 100644 index 0000000..95fdbf2 --- /dev/null +++ b/Include/pgenheaders.h @@ -0,0 +1,15 @@ +/* Include files and extern declarations used by most of the parser. + This is a precompiled header for THINK C. */ + +#include <stdio.h> + +#ifdef THINK_C +#define label label_ +#include <proto.h> +#undef label +#endif + +#include "PROTO.h" +#include "malloc.h" + +extern void fatal PROTO((char *)); diff --git a/Include/pyerrors.h b/Include/pyerrors.h index f0e3762..21c57d1 100644 --- a/Include/pyerrors.h +++ b/Include/pyerrors.h @@ -7,7 +7,7 @@ int err_occurred PROTO((void)); void err_get PROTO((object **, object **)); void err_clear PROTO((void)); -/* Predefined exceptions (in run.c) */ +/* Predefined exceptions */ extern object *RuntimeError; extern object *EOFError; @@ -29,5 +29,6 @@ extern object *KeyboardInterrupt; extern int err_badarg PROTO((void)); extern object *err_nomem PROTO((void)); extern object *err_errno PROTO((object *)); +extern void err_input PROTO((int)); extern void err_badcall PROTO((void)); diff --git a/Include/pythonrun.h b/Include/pythonrun.h new file mode 100644 index 0000000..51ff3b7 --- /dev/null +++ b/Include/pythonrun.h @@ -0,0 +1,23 @@ +/* Interfaces to parse and execute pieces of python code */ + +void initall PROTO((void)); + +int run PROTO((FILE *, char *)); + +int run_script PROTO((FILE *, char *)); +int run_tty_1 PROTO((FILE *, char *)); +int run_tty_loop PROTO((FILE *, char *)); + +int parse_string PROTO((char *, int, struct _node **)); +int parse_file PROTO((FILE *, char *, int, struct _node **)); + +object *eval_node PROTO((struct _node *, char *, object *, object *)); + +object *run_string PROTO((char *, int, object *, object *)); +object *run_file PROTO((FILE *, char *, int, object *, object *)); +object *run_err_node PROTO((int, struct _node *, char *, object *, object *)); +object *run_node PROTO((struct _node *, char *, object *, object *)); + +void print_error PROTO((void)); + +void goaway PROTO((int)); diff --git a/Include/structmember.h b/Include/structmember.h new file mode 100644 index 0000000..13af70d --- /dev/null +++ b/Include/structmember.h @@ -0,0 +1,40 @@ +/* Interface to map C struct members to Python object attributes */ + +/* The offsetof() macro calculates the offset of a structure member + in its structure. Unfortunately this cannot be written down + portably, hence it is provided by a Standard C header file. + For pre-Standard C compilers, here is a version that usually works + (but watch out!): */ + +#ifndef offsetof +#define offsetof(type, member) ( (int) & ((type*)0) -> member ) +#endif + +/* An array of memberlist structures defines the name, type and offset + of selected members of a C structure. These can be read by + getmember() and set by setmember() (except if their READONLY flag + is set). The array must be terminated with an entry whose name + pointer is NULL. */ + +struct memberlist { + char *name; + int type; + int offset; + int readonly; +}; + +/* Types */ +#define T_SHORT 0 +#define T_INT 1 +#define T_LONG 2 +#define T_FLOAT 3 +#define T_DOUBLE 4 +#define T_STRING 5 +#define T_OBJECT 6 + +/* Readonly flag */ +#define READONLY 1 +#define RO READONLY /* Shorthand */ + +object *getmember PROTO((char *, struct memberlist *, char *)); +int setmember PROTO((char *, struct memberlist *, char *, object *)); diff --git a/Include/sysmodule.h b/Include/sysmodule.h index 8a2644a..7f449cf 100644 --- a/Include/sysmodule.h +++ b/Include/sysmodule.h @@ -3,4 +3,4 @@ object *sysget PROTO((char *)); int sysset PROTO((char *, object *)); FILE *sysgetfile PROTO((char *, FILE *)); -void initsys PROTO((int, char **)); +void initsys PROTO((void)); diff --git a/Include/traceback.h b/Include/traceback.h new file mode 100644 index 0000000..920feff --- /dev/null +++ b/Include/traceback.h @@ -0,0 +1,6 @@ +/* Traceback interface */ + +int tb_here PROTO((struct _frame *, int, int)); +object *tb_fetch PROTO((void)); +int tb_store PROTO((object *)); +int tb_print PROTO((object *, FILE *)); diff --git a/Include/tupleobject.h b/Include/tupleobject.h index d22e6b9..46a0031 100644 --- a/Include/tupleobject.h +++ b/Include/tupleobject.h @@ -14,6 +14,11 @@ inserted in the tuple. Similarly, gettupleitem does not increment the returned item's reference count. */ +typedef struct { + OB_VARHEAD + object *ob_item[1]; +} tupleobject; + extern typeobject Tupletype; #define is_tupleobject(op) ((op)->ob_type == &Tupletype) @@ -22,3 +27,6 @@ extern object *newtupleobject PROTO((int size)); extern int gettuplesize PROTO((object *)); extern object *gettupleitem PROTO((object *, int)); extern int settupleitem PROTO((object *, int, object *)); + +/* Macro, trading safety for speed */ +#define GETTUPLEITEM(op, i) ((op)->ob_item[i]) diff --git a/Modules/cgen.py b/Modules/cgen.py index 0cdeaa6..1e345d1 100644 --- a/Modules/cgen.py +++ b/Modules/cgen.py @@ -33,8 +33,8 @@ digits = '0123456789' # def getnum(s): n = '' - while s[:1] in digits: - n = n + s[:1] + while s and s[0] in digits: + n = n + s[0] s = s[1:] return n, s diff --git a/Modules/cstubs b/Modules/cstubs index f0f5ade..88a77bc 100644 --- a/Modules/cstubs +++ b/Modules/cstubs @@ -25,24 +25,13 @@ Each definition must be contained on one line: N*retval */ -#include <stdio.h> #include <gl.h> #include <device.h> -#include "PROTO.h" -#include "object.h" -#include "intobject.h" -#include "floatobject.h" -#include "listobject.h" -#include "tupleobject.h" -#include "dictobject.h" -#include "methodobject.h" -#include "moduleobject.h" -#include "objimpl.h" + +#include "allobjects.h" #include "import.h" -#include "sigtype.h" #include "modsupport.h" #include "cgensupport.h" -#include "errors.h" /* Some stubs are too complicated for the stub generator. diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 218658f..e811088 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -1,20 +1,11 @@ /* Math module -- standard C math library functions, pi and e */ -#include <stdio.h> -#include <math.h> +#include "allobjects.h" -#include "PROTO.h" -#include "object.h" -#include "intobject.h" -#include "tupleobject.h" -#include "floatobject.h" -#include "dictobject.h" -#include "methodobject.h" -#include "moduleobject.h" -#include "objimpl.h" -#include "import.h" #include "modsupport.h" +#include <math.h> + static int getdoublearg(args, px) register object *args; diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index c2166dc..ea0ac6c 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1,6 +1,5 @@ /* POSIX module implementation */ -#include <stdio.h> #include <signal.h> #include <string.h> #include <setjmp.h> @@ -14,20 +13,8 @@ #include <sys/dir.h> #endif -#include "PROTO.h" -#include "object.h" -#include "intobject.h" -#include "stringobject.h" -#include "tupleobject.h" -#include "listobject.h" -#include "dictobject.h" -#include "methodobject.h" -#include "moduleobject.h" -#include "objimpl.h" -#include "import.h" -#include "sigtype.h" +#include "allobjects.h" #include "modsupport.h" -#include "errors.h" extern char *strerror PROTO((int)); @@ -140,7 +127,6 @@ posix_do_stat(self, args, statfunc) v = newtupleobject(10); if (v == NULL) return NULL; - errno = 0; #define SET(i, st_member) settupleitem(v, i, newintobject((long)st.st_member)) SET(0, st_mode); SET(1, st_ino); @@ -153,9 +139,9 @@ posix_do_stat(self, args, statfunc) SET(8, st_mtime); SET(9, st_ctime); #undef SET - if (errno != 0) { + if (err_occurred()) { DECREF(v); - return err_nomem(); + return NULL; } return v; } @@ -335,6 +321,8 @@ posix_utimes(self, args) #ifdef NO_GETCWD +#include "errno.h" + /* Quick hack to get posix.getcwd() working for pure BSD 4.3 */ /* XXX This assumes MAXPATHLEN = 1024 !!! */ diff --git a/Modules/stdwinmodule.c b/Modules/stdwinmodule.c index cae07cf..da511ec 100644 --- a/Modules/stdwinmodule.c +++ b/Modules/stdwinmodule.c @@ -38,22 +38,11 @@ XXX more? */ -#include <stdio.h> -#include "stdwin.h" +#include "allobjects.h" -#include "PROTO.h" -#include "object.h" -#include "intobject.h" -#include "stringobject.h" -#include "tupleobject.h" -#include "dictobject.h" -#include "methodobject.h" -#include "moduleobject.h" -#include "objimpl.h" -#include "import.h" #include "modsupport.h" -#include "errors.h" +#include "stdwin.h" /* Window and menu object types declared here because of forward references */ diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 334b2d3..28d4ff7 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -1,6 +1,11 @@ /* Time module */ -#include <stdio.h> +#include "allobjects.h" + +#include "modsupport.h" + +#include "sigtype.h" + #include <signal.h> #include <setjmp.h> @@ -11,18 +16,6 @@ typedef unsigned long time_t; extern time_t time(); #endif /* !__STDC__ */ -#include "PROTO.h" -#include "object.h" -#include "intobject.h" -#include "dictobject.h" -#include "methodobject.h" -#include "moduleobject.h" -#include "objimpl.h" -#include "import.h" -#include "sigtype.h" -#include "modsupport.h" -#include "errors.h" - /* Time methods */ diff --git a/Objects/classobject.c b/Objects/classobject.c index edc6070..4ee32d4 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -1,28 +1,17 @@ /* Class object implementation */ -#include <stdio.h> +#include "allobjects.h" -#include "PROTO.h" -#include "node.h" -#include "object.h" -#include "stringobject.h" -#include "tupleobject.h" -#include "dictobject.h" -#include "funcobject.h" -#include "classobject.h" -#include "objimpl.h" -#include "errors.h" +#include "structmember.h" typedef struct { OB_HEAD - node *cl_tree; /* The entire classdef parse tree */ object *cl_bases; /* A tuple */ object *cl_methods; /* A dictionary */ } classobject; object * -newclassobject(tree, bases, methods) - node *tree; +newclassobject(bases, methods) object *bases; /* NULL or tuple of classobjects! */ object *methods; { @@ -30,7 +19,6 @@ newclassobject(tree, bases, methods) op = NEWOBJ(classobject, &Classtype); if (op == NULL) return NULL; - op->cl_tree = tree; if (bases != NULL) INCREF(bases); op->cl_bases = bases; @@ -70,6 +58,7 @@ class_getattr(op, name) v = class_getattr(gettupleitem(op->cl_bases, i), name); if (v != NULL) return v; + err_clear(); } } err_setstr(NameError, name); @@ -242,6 +231,22 @@ classmethodgetself(cm) /* Class method methods */ +#define OFF(x) offsetof(classmethodobject, x) + +static struct memberlist classmethod_memberlist[] = { + {"cm_func", T_OBJECT, OFF(cm_func)}, + {"cm_self", T_OBJECT, OFF(cm_self)}, + {NULL} /* Sentinel */ +}; + +static object * +classmethod_getattr(cm, name) + register classmethodobject *cm; + char *name; +{ + return getmember((char *)cm, classmethod_memberlist, name); +} + static void classmethod_dealloc(cm) register classmethodobject *cm; @@ -259,7 +264,7 @@ typeobject Classmethodtype = { 0, classmethod_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ - 0, /*tp_getattr*/ + classmethod_getattr, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ diff --git a/Objects/fileobject.c b/Objects/fileobject.c index 7eb6f5c..09690c6 100644 --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -2,19 +2,16 @@ /* XXX This should become a built-in module 'io'. It should support more functionality, better exception handling for invalid calls, etc. + (Especially reading on a write-only file or vice versa!) It should also cooperate with posix to support popen(), which should share most code but have a special close function. */ -#include <stdio.h> +#include "allobjects.h" -#include "PROTO.h" -#include "object.h" -#include "stringobject.h" -#include "intobject.h" -#include "fileobject.h" -#include "methodobject.h" -#include "objimpl.h" -#include "errors.h" +#include "errno.h" +#ifndef errno +extern int errno; +#endif typedef struct { OB_HEAD @@ -29,7 +26,7 @@ getfilefile(f) object *f; { if (!is_fileobject(f)) { - errno = EBADF; + err_badcall(); return NULL; } return ((fileobject *)f)->f_fp; @@ -49,7 +46,6 @@ newopenfileobject(fp, name, mode) f->f_mode = newstringobject(mode); if (f->f_name == NULL || f->f_mode == NULL) { DECREF(f); - errno = ENOMEM; return NULL; } f->f_fp = fp; @@ -67,6 +63,7 @@ newfileobject(name, mode) return NULL; if ((f->f_fp = fopen(name, mode)) == NULL) { DECREF(f); + err_errno(RuntimeError); /* XXX Should use another error */ return NULL; } return (object *)f; @@ -75,7 +72,7 @@ newfileobject(name, mode) /* Methods */ static void -filedealloc(f) +file_dealloc(f) fileobject *f; { if (f->f_fp != NULL) @@ -88,7 +85,7 @@ filedealloc(f) } static void -fileprint(f, fp, flags) +file_print(f, fp, flags) fileobject *f; FILE *fp; int flags; @@ -101,11 +98,11 @@ fileprint(f, fp, flags) } static object * -filerepr(f) +file_repr(f) fileobject *f; { char buf[300]; - /* XXX This differs from fileprint if the filename contains + /* XXX This differs from file_print if the filename contains quotes or other funny characters. */ sprintf(buf, "<%s file '%.256s', mode '%.10s'>", f->f_fp == NULL ? "closed" : "open", @@ -115,12 +112,12 @@ filerepr(f) } static object * -fileclose(f, args) +file_close(f, args) fileobject *f; object *args; { if (args != NULL) { - errno = EINVAL; + err_badarg(); return NULL; } if (f->f_fp != NULL) { @@ -132,30 +129,28 @@ fileclose(f, args) } static object * -fileread(f, args) +file_read(f, args) fileobject *f; object *args; { int n; object *v; if (f->f_fp == NULL) { - errno = EBADF; + err_badarg(); return NULL; } if (args == NULL || !is_intobject(args)) { - errno = EINVAL; + err_badarg(); return NULL; } n = getintvalue(args); if (n < 0) { - errno = EDOM; + err_badarg(); return NULL; } v = newsizedstringobject((char *)NULL, n); - if (v == NULL) { - errno = ENOMEM; + if (v == NULL) return NULL; - } n = fread(getstringvalue(v), 1, n, f->f_fp); /* EOF is reported as an empty string */ /* XXX should detect real I/O errors? */ @@ -166,14 +161,14 @@ fileread(f, args) /* XXX Should this be unified with raw_input()? */ static object * -filereadline(f, args) +file_readline(f, args) fileobject *f; object *args; { int n; object *v; if (f->f_fp == NULL) { - errno = EBADF; + err_badarg(); return NULL; } if (args == NULL) { @@ -181,21 +176,23 @@ filereadline(f, args) } else if (is_intobject(args)) { n = getintvalue(args); - if (n < 0 || n > 0x7fff /*XXX*/ ) { - errno = EDOM; + if (n < 0) { + err_badarg(); return NULL; } } else { - errno = EINVAL; + err_badarg(); return NULL; } v = newsizedstringobject((char *)NULL, n); - if (v == NULL) { - errno = ENOMEM; + if (v == NULL) return NULL; - } - if (fgets(getstringvalue(v), n+1, f->f_fp) == NULL) { +#ifndef THINK_C + /* XXX Think C reads n characters, others read n-1 characters... */ + n = n+1; +#endif + if (fgets(getstringvalue(v), n, f->f_fp) == NULL) { /* EOF is reported as an empty string */ /* XXX should detect real I/O errors? */ n = 0; @@ -208,17 +205,17 @@ filereadline(f, args) } static object * -filewrite(f, args) +file_write(f, args) fileobject *f; object *args; { int n, n2; if (f->f_fp == NULL) { - errno = EBADF; + err_badarg(); return NULL; } if (args == NULL || !is_stringobject(args)) { - errno = EINVAL; + err_badarg(); return NULL; } errno = 0; @@ -226,36 +223,27 @@ filewrite(f, args) if (n2 != n) { if (errno == 0) errno = EIO; + err_errno(RuntimeError); return NULL; } INCREF(None); return None; } -static struct methodlist { - char *ml_name; - method ml_meth; -} filemethods[] = { - {"write", filewrite}, - {"read", fileread}, - {"readline", filereadline}, - {"close", fileclose}, +static struct methodlist file_methods[] = { + {"write", file_write}, + {"read", file_read}, + {"readline", file_readline}, + {"close", file_close}, {NULL, NULL} /* sentinel */ }; static object * -filegetattr(f, name) +file_getattr(f, name) fileobject *f; char *name; { - struct methodlist *ml = filemethods; - for (; ml->ml_name != NULL; ml++) { - if (strcmp(name, ml->ml_name) == 0) - return newmethodobject(ml->ml_name, ml->ml_meth, - (object *)f); - } - err_setstr(NameError, name); - return NULL; + return findmethod(file_methods, (object *)f, name); } typeobject Filetype = { @@ -264,10 +252,10 @@ typeobject Filetype = { "file", sizeof(fileobject), 0, - filedealloc, /*tp_dealloc*/ - fileprint, /*tp_print*/ - filegetattr, /*tp_getattr*/ + file_dealloc, /*tp_dealloc*/ + file_print, /*tp_print*/ + file_getattr, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ - filerepr, /*tp_repr*/ + file_repr, /*tp_repr*/ }; diff --git a/Objects/floatobject.c b/Objects/floatobject.c index c2b132e..82d4643 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -3,16 +3,10 @@ /* XXX There should be overflow checks here, but it's hard to check for any kind of float exception without losing portability. */ -#include <stdio.h> -#include <math.h> -#include <ctype.h> +#include "allobjects.h" -#include "PROTO.h" -#include "object.h" -#include "floatobject.h" -#include "stringobject.h" -#include "objimpl.h" -#include "errors.h" +#include <ctype.h> +#include <math.h> #ifndef THINK_C extern double fmod PROTO((double, double)); diff --git a/Objects/frameobject.c b/Objects/frameobject.c new file mode 100644 index 0000000..6da3929 --- /dev/null +++ b/Objects/frameobject.c @@ -0,0 +1,132 @@ +/* Frame object implementation */ + +#include "allobjects.h" + +#include "compile.h" +#include "frameobject.h" +#include "opcode.h" +#include "structmember.h" + +#define OFF(x) offsetof(frameobject, x) + +static struct memberlist frame_memberlist[] = { + {"f_back", T_OBJECT, OFF(f_back)}, + {"f_code", T_OBJECT, OFF(f_code)}, + {"f_globals", T_OBJECT, OFF(f_globals)}, + {"f_locals", T_OBJECT, OFF(f_locals)}, + {NULL} /* Sentinel */ +}; + +static object * +frame_getattr(f, name) + frameobject *f; + char *name; +{ + return getmember((char *)f, frame_memberlist, name); +} + +static void +frame_dealloc(f) + frameobject *f; +{ + XDECREF(f->f_back); + XDECREF(f->f_code); + XDECREF(f->f_globals); + XDECREF(f->f_locals); + XDEL(f->f_valuestack); + XDEL(f->f_blockstack); + DEL(f); +} + +typeobject Frametype = { + OB_HEAD_INIT(&Typetype) + 0, + "frame", + sizeof(frameobject), + 0, + frame_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + frame_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; + +frameobject * +newframeobject(back, code, globals, locals, nvalues, nblocks) + frameobject *back; + codeobject *code; + object *globals; + object *locals; + int nvalues; + int nblocks; +{ + frameobject *f; + if ((back != NULL && !is_frameobject(back)) || + code == NULL || !is_codeobject(code) || + globals == NULL || !is_dictobject(globals) || + locals == NULL || !is_dictobject(locals) || + nvalues < 0 || nblocks < 0) { + err_badcall(); + return NULL; + } + f = NEWOBJ(frameobject, &Frametype); + if (f != NULL) { + if (back) + INCREF(back); + f->f_back = back; + INCREF(code); + f->f_code = code; + INCREF(globals); + f->f_globals = globals; + INCREF(locals); + f->f_locals = locals; + f->f_valuestack = NEW(object *, nvalues+1); + f->f_blockstack = NEW(block, nblocks+1); + f->f_nvalues = nvalues; + f->f_nblocks = nblocks; + f->f_iblock = 0; + if (f->f_valuestack == NULL || f->f_blockstack == NULL) { + err_nomem(); + DECREF(f); + f = NULL; + } + } + return f; +} + +/* Block management */ + +void +setup_block(f, type, handler, level) + frameobject *f; + int type; + int handler; + int level; +{ + block *b; + if (f->f_iblock >= f->f_nblocks) { + fprintf(stderr, "XXX block stack overflow\n"); + abort(); + } + b = &f->f_blockstack[f->f_iblock++]; + b->b_type = type; + b->b_level = level; + b->b_handler = handler; +} + +block * +pop_block(f) + frameobject *f; +{ + block *b; + if (f->f_iblock <= 0) { + fprintf(stderr, "XXX block stack underflow\n"); + abort(); + } + b = &f->f_blockstack[--f->f_iblock]; + return b; +} diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 8850872..23236da 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -1,11 +1,8 @@ /* Function object implementation */ -#include <stdio.h> +#include "allobjects.h" -#include "PROTO.h" -#include "object.h" -#include "funcobject.h" -#include "objimpl.h" +#include "structmember.h" typedef struct { OB_HEAD @@ -52,8 +49,24 @@ getfuncglobals(op) /* Methods */ +#define OFF(x) offsetof(funcobject, x) + +static struct memberlist func_memberlist[] = { + {"func_code", T_OBJECT, OFF(func_code)}, + {"func_globals",T_OBJECT, OFF(func_globals)}, + {NULL} /* Sentinel */ +}; + +static object * +func_getattr(op, name) + funcobject *op; + char *name; +{ + return getmember((char *)op, func_memberlist, name); +} + static void -funcdealloc(op) +func_dealloc(op) funcobject *op; { DECREF(op->func_code); @@ -67,9 +80,9 @@ typeobject Functype = { "function", sizeof(funcobject), 0, - funcdealloc, /*tp_dealloc*/ + func_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ - 0, /*tp_getattr*/ + func_getattr, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ diff --git a/Objects/intobject.c b/Objects/intobject.c index b0dd036..d70fcef 100644 --- a/Objects/intobject.c +++ b/Objects/intobject.c @@ -1,19 +1,14 @@ /* Integer object implementation */ -#include <stdio.h> - -#include "PROTO.h" -#include "object.h" -#include "intobject.h" -#include "stringobject.h" -#include "objimpl.h" -#include "errors.h" +#include "allobjects.h" /* Standard Booleans */ + intobject FalseObject = { OB_HEAD_INIT(&Inttype) 0 }; + intobject TrueObject = { OB_HEAD_INIT(&Inttype) 1 @@ -33,21 +28,58 @@ err_zdiv() return NULL; } +/* Integers are quite normal objects, to make object handling uniform. + (Using odd pointers to represent integers would save much space + but require extra checks for this special case throughout the code.) + Since, a typical Python program spends much of its time allocating + and deallocating integers, these operations should be very fast. + Therefore we use a dedicated allocation scheme with a much lower + overhead (in space and time) than straight malloc(): a simple + dedicated free list, filled when necessary with memory from malloc(). +*/ + +#define BLOCK_SIZE 1000 /* 1K less typical malloc overhead */ +#define N_INTOBJECTS (BLOCK_SIZE / sizeof(intobject)) + +static intobject * +fill_free_list() +{ + intobject *p, *q; + p = NEW(intobject, N_INTOBJECTS); + if (p == NULL) + return (intobject *)err_nomem(); + q = p + N_INTOBJECTS; + while (--q > p) + *(intobject **)q = q-1; + *(intobject **)q = NULL; + return p + N_INTOBJECTS - 1; +} + +static intobject *free_list = NULL; + object * newintobject(ival) long ival; { - /* For efficiency, this code is copied from newobject() */ - register intobject *op = (intobject *) malloc(sizeof(intobject)); - if (op == NULL) { - err_nomem(); - } - else { - NEWREF(op); - op->ob_type = &Inttype; - op->ob_ival = ival; + register intobject *v; + if (free_list == NULL) { + if ((free_list = fill_free_list()) == NULL) + return NULL; } - return (object *) op; + v = free_list; + free_list = *(intobject **)free_list; + NEWREF(v); + v->ob_type = &Inttype; + v->ob_ival = ival; + return (object *) v; +} + +static void +int_dealloc(v) + intobject *v; +{ + *(intobject **)v = free_list; + free_list = v; } long @@ -65,7 +97,7 @@ getintvalue(op) /* Methods */ static void -intprint(v, fp, flags) +int_print(v, fp, flags) intobject *v; FILE *fp; int flags; @@ -74,7 +106,7 @@ intprint(v, fp, flags) } static object * -intrepr(v) +int_repr(v) intobject *v; { char buf[20]; @@ -83,7 +115,7 @@ intrepr(v) } static int -intcompare(v, w) +int_compare(v, w) intobject *v, *w; { register long i = v->ob_ival; @@ -92,7 +124,7 @@ intcompare(v, w) } static object * -intadd(v, w) +int_add(v, w) intobject *v; register object *w; { @@ -110,7 +142,7 @@ intadd(v, w) } static object * -intsub(v, w) +int_sub(v, w) intobject *v; register object *w; { @@ -128,7 +160,7 @@ intsub(v, w) } static object * -intmul(v, w) +int_mul(v, w) intobject *v; register object *w; { @@ -147,7 +179,7 @@ intmul(v, w) } static object * -intdiv(v, w) +int_div(v, w) intobject *v; register object *w; { @@ -161,7 +193,7 @@ intdiv(v, w) } static object * -intrem(v, w) +int_rem(v, w) intobject *v; register object *w; { @@ -175,7 +207,7 @@ intrem(v, w) } static object * -intpow(v, w) +int_pow(v, w) intobject *v; register object *w; { @@ -203,7 +235,7 @@ intpow(v, w) } static object * -intneg(v) +int_neg(v) intobject *v; { register long a, x; @@ -215,7 +247,7 @@ intneg(v) } static object * -intpos(v) +int_pos(v) intobject *v; { INCREF(v); @@ -223,14 +255,14 @@ intpos(v) } static number_methods int_as_number = { - intadd, /*tp_add*/ - intsub, /*tp_subtract*/ - intmul, /*tp_multiply*/ - intdiv, /*tp_divide*/ - intrem, /*tp_remainder*/ - intpow, /*tp_power*/ - intneg, /*tp_negate*/ - intpos, /*tp_plus*/ + int_add, /*tp_add*/ + int_sub, /*tp_subtract*/ + int_mul, /*tp_multiply*/ + int_div, /*tp_divide*/ + int_rem, /*tp_remainder*/ + int_pow, /*tp_power*/ + int_neg, /*tp_negate*/ + int_pos, /*tp_plus*/ }; typeobject Inttype = { @@ -239,12 +271,12 @@ typeobject Inttype = { "int", sizeof(intobject), 0, - free, /*tp_dealloc*/ - intprint, /*tp_print*/ + int_dealloc, /*tp_dealloc*/ + int_print, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ - intcompare, /*tp_compare*/ - intrepr, /*tp_repr*/ + int_compare, /*tp_compare*/ + int_repr, /*tp_repr*/ &int_as_number, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ diff --git a/Objects/listobject.c b/Objects/listobject.c index 97088c5..c59604d 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -1,22 +1,6 @@ /* List object implementation */ -#include <stdio.h> - -#include "PROTO.h" -#include "object.h" -#include "intobject.h" -#include "stringobject.h" -#include "tupleobject.h" -#include "methodobject.h" -#include "listobject.h" -#include "objimpl.h" -#include "modsupport.h" -#include "errors.h" - -typedef struct { - OB_VARHEAD - object **ob_item; -} listobject; +#include "allobjects.h" object * newlistobject(size) diff --git a/Objects/methodobject.c b/Objects/methodobject.c index c8b5ee0..5cc4b88 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -1,15 +1,8 @@ /* Method object implementation */ -#include <stdio.h> +#include "allobjects.h" -#include "PROTO.h" -#include "object.h" -#include "node.h" -#include "stringobject.h" -#include "methodobject.h" -#include "objimpl.h" #include "token.h" -#include "errors.h" typedef struct { OB_HEAD @@ -75,11 +68,10 @@ meth_print(m, fp, flags) int flags; { if (m->m_self == NULL) - fprintf(fp, "<%s method>", m->m_name); + fprintf(fp, "<built-in function '%s'>", m->m_name); else - fprintf(fp, "<%s method of %s object at %lx>", - m->m_name, m->m_self->ob_type->tp_name, - (long)m->m_self); + fprintf(fp, "<built-in method '%s' of some %s object>", + m->m_name, m->m_self->ob_type->tp_name); } static object * @@ -88,11 +80,11 @@ meth_repr(m) { char buf[200]; if (m->m_self == NULL) - sprintf(buf, "<%.80s method>", m->m_name); + sprintf(buf, "<built-in function '%.80s'>", m->m_name); else - sprintf(buf, "<%.80s method of %.80s object at %lx>", - m->m_name, m->m_self->ob_type->tp_name, - (long)m->m_self); + sprintf(buf, + "<built-in method '%.80s' of some %.80s object>", + m->m_name, m->m_self->ob_type->tp_name); return newstringobject(buf); } @@ -112,3 +104,20 @@ typeobject Methodtype = { 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ }; + +/* Find a method in a module's method table. + Usually called from an object's getattr method. */ + +object * +findmethod(ml, op, name) + struct methodlist *ml; + object *op; + char *name; +{ + for (; ml->ml_name != NULL; ml++) { + if (strcmp(name, ml->ml_name) == 0) + return newmethodobject(ml->ml_name, ml->ml_meth, op); + } + err_setstr(NameError, name); + return NULL; +} diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 22a793f..cf96a70 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -1,14 +1,6 @@ /* Module object implementation */ -#include <stdio.h> - -#include "PROTO.h" -#include "object.h" -#include "stringobject.h" -#include "dictobject.h" -#include "moduleobject.h" -#include "objimpl.h" -#include "errors.h" +#include "allobjects.h" typedef struct { OB_HEAD @@ -37,31 +29,12 @@ getmoduledict(m) object *m; { if (!is_moduleobject(m)) { - err_badarg(); + err_badcall(); return NULL; } return ((moduleobject *)m) -> md_dict; } -int -setmoduledict(m, v) - object *m; - object *v; -{ - if (!is_moduleobject(m)) { - err_badarg(); - return -1; - } - if (!is_dictobject(v)) { - err_badarg(); - return -1; - } - DECREF(((moduleobject *)m) -> md_dict); - INCREF(v); - ((moduleobject *)m) -> md_dict = v; - return 0; -} - char * getmodulename(m) object *m; @@ -76,7 +49,7 @@ getmodulename(m) /* Methods */ static void -moduledealloc(m) +module_dealloc(m) moduleobject *m; { if (m->md_name != NULL) @@ -87,33 +60,37 @@ moduledealloc(m) } static void -moduleprint(m, fp, flags) +module_print(m, fp, flags) moduleobject *m; FILE *fp; int flags; { - fprintf(fp, "<module %s>", getstringvalue(m->md_name)); + fprintf(fp, "<module '%s'>", getstringvalue(m->md_name)); } static object * -modulerepr(m) +module_repr(m) moduleobject *m; { char buf[100]; - sprintf(buf, "<module %.80s>", getstringvalue(m->md_name)); + sprintf(buf, "<module '%.80s'>", getstringvalue(m->md_name)); return newstringobject(buf); } static object * -modulegetattr(m, name) +module_getattr(m, name) moduleobject *m; char *name; { object *res; - if (strcmp(name, "__dict") == 0) { + if (strcmp(name, "__dict__") == 0) { INCREF(m->md_dict); return m->md_dict; } + if (strcmp(name, "__name__") == 0) { + INCREF(m->md_name); + return m->md_name; + } res = dictlookup(m->md_dict, name); if (res == NULL) err_setstr(NameError, name); @@ -123,15 +100,13 @@ modulegetattr(m, name) } static int -modulesetattr(m, name, v) +module_setattr(m, name, v) moduleobject *m; char *name; object *v; { - if (strcmp(name, "__dict") == 0) { - /* Can't allow assignment to __dict, it would screw up - module's functions which still use the old dictionary. */ - err_setstr(NameError, "__dict is a reserved member name"); + if (strcmp(name, "__dict__") == 0 || strcmp(name, "__name__") == 0) { + err_setstr(NameError, "can't assign to reserved member name"); return NULL; } if (v == NULL) @@ -146,10 +121,10 @@ typeobject Moduletype = { "module", /*tp_name*/ sizeof(moduleobject), /*tp_size*/ 0, /*tp_itemsize*/ - moduledealloc, /*tp_dealloc*/ - moduleprint, /*tp_print*/ - modulegetattr, /*tp_getattr*/ - modulesetattr, /*tp_setattr*/ - 0, /*tp_compare*/ - modulerepr, /*tp_repr*/ + module_dealloc, /*tp_dealloc*/ + module_print, /*tp_print*/ + module_getattr, /*tp_getattr*/ + module_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + module_repr, /*tp_repr*/ }; diff --git a/Objects/object.c b/Objects/object.c index ebeb0f8..f2b4d1f 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1,16 +1,14 @@ -/* Object implementation; and 'noobject' implementation */ +/* Generic object operations; and implementation of None (NoObject) */ -#include <stdio.h> +#include "allobjects.h" -#include "PROTO.h" -#include "object.h" -#include "stringobject.h" -#include "objimpl.h" -#include "errors.h" - -int StopPrint; /* Flag to indicate printing must be stopped */ +#ifdef REF_DEBUG +long ref_total; +#endif -/* Object allocation routines used by NEWOBJ and NEWVAROBJ macros */ +/* Object allocation routines used by NEWOBJ and NEWVAROBJ macros. + These are used by the individual routines for object creation. + Do not call them otherwise, they do not initialize the object! */ object * newobject(tp) @@ -43,6 +41,8 @@ newvarobject(tp, size) #endif +int StopPrint; /* Flag to indicate printing must be stopped */ + static int prlevel; void @@ -52,6 +52,7 @@ printobject(op, fp, flags) int flags; { /* Hacks to make printing a long or recursive object interruptible */ + /* XXX Interrupts should leave a more permanent error */ prlevel++; if (!StopPrint && intrcheck()) { fprintf(fp, "\n[print interrupted]\n"); @@ -61,12 +62,16 @@ printobject(op, fp, flags) if (op == NULL) { fprintf(fp, "<nil>"); } - else if (op->ob_type->tp_print == NULL) { - fprintf(fp, "<%s object at %lx>", - op->ob_type->tp_name, (long)op); - } else { - (*op->ob_type->tp_print)(op, fp, flags); + if (op->ob_refcnt <= 0) + fprintf(fp, "(refcnt %d):", op->ob_refcnt); + if (op->ob_type->tp_print == NULL) { + fprintf(fp, "<%s object at %lx>", + op->ob_type->tp_name, (long)op); + } + else { + (*op->ob_type->tp_print)(op, fp, flags); + } } } prlevel--; @@ -78,17 +83,16 @@ object * reprobject(v) object *v; { - object *w; + object *w = NULL; /* Hacks to make converting a long or recursive object interruptible */ prlevel++; if (!StopPrint && intrcheck()) { StopPrint = 1; - w = NULL; err_set(KeyboardInterrupt); } if (!StopPrint) { if (v == NULL) { - w = newstringobject("<nil>"); + w = newstringobject("<NULL>"); } else if (v->ob_type->tp_repr == NULL) { char buf[100]; @@ -99,6 +103,10 @@ reprobject(v) else { w = (*v->ob_type->tp_repr)(v); } + if (StopPrint) { + XDECREF(w); + w = NULL; + } } prlevel--; if (prlevel == 0) @@ -124,30 +132,76 @@ cmpobject(v, w) return ((*tp->tp_compare)(v, w)); } +object * +getattr(v, name) + object *v; + char *name; +{ + if (v->ob_type->tp_getattr == NULL) { + err_setstr(TypeError, "attribute-less object"); + return NULL; + } + else { + return (*v->ob_type->tp_getattr)(v, name); + } +} + +int +setattr(v, name, w) + object *v; + char *name; + object *w; +{ + if (v->ob_type->tp_setattr == NULL) { + if (v->ob_type->tp_getattr == NULL) + err_setstr(TypeError, "attribute-less object"); + else + err_setstr(TypeError, "object has read-only attributes"); + return NULL; + } + else { + return (*v->ob_type->tp_setattr)(v, name, w); + } +} + /* NoObject is usable as a non-NULL undefined value, used by the macro None. There is (and should be!) no way to create other objects of this type, -so there is exactly one. +so there is exactly one (which is indestructible, by the way). */ static void -noprint(op, fp, flags) +none_print(op, fp, flags) object *op; FILE *fp; int flags; { - fprintf(fp, "<no value>"); + fprintf(fp, "None"); +} + +static object * +none_repr(op) + object *op; +{ + return newstringobject("None"); } static typeobject Notype = { OB_HEAD_INIT(&Typetype) 0, - "novalue", + "None", 0, 0, 0, /*tp_dealloc*/ /*never called*/ - noprint, /*tp_print*/ + none_print, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + none_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ }; object NoObject = { @@ -170,15 +224,30 @@ NEWREF(op) refchain._ob_next = op; } -DELREF(op) - object *op; +UNREF(op) + register object *op; { + register object *p; if (op->ob_refcnt < 0) { - fprintf(stderr, "negative refcnt\n"); + fprintf(stderr, "UNREF negative refcnt\n"); + abort(); + } + for (p = refchain._ob_next; p != &refchain; p = p->_ob_next) { + if (p == op) + break; + } + if (p == &refchain) { /* Not found */ + fprintf(stderr, "UNREF unknown object\n"); abort(); } op->_ob_next->_ob_prev = op->_ob_prev; op->_ob_prev->_ob_next = op->_ob_next; +} + +DELREF(op) + object *op; +{ + UNREF(op); (*(op)->ob_type->tp_dealloc)(op); } diff --git a/Objects/stringobject.c b/Objects/stringobject.c index 40cd15a..1881bdf 100644 --- a/Objects/stringobject.c +++ b/Objects/stringobject.c @@ -1,13 +1,6 @@ /* String object implementation */ -#include <stdio.h> - -#include "PROTO.h" -#include "object.h" -#include "stringobject.h" -#include "intobject.h" -#include "objimpl.h" -#include "errors.h" +#include "allobjects.h" object * newsizedstringobject(str, size) diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 960d78a..89ba4e9 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -1,19 +1,6 @@ /* Tuple object implementation */ -#include <stdio.h> - -#include "PROTO.h" -#include "object.h" -#include "stringobject.h" -#include "tupleobject.h" -#include "intobject.h" -#include "objimpl.h" -#include "errors.h" - -typedef struct { - OB_VARHEAD - object *ob_item[1]; -} tupleobject; +#include "allobjects.h" object * newtupleobject(size) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index f7acaad..f80c518 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1,16 +1,11 @@ /* Type object implementation */ -#include <stdio.h> - -#include "PROTO.h" -#include "object.h" -#include "stringobject.h" -#include "objimpl.h" +#include "allobjects.h" /* Type object implementation */ static void -typeprint(v, fp, flags) +type_print(v, fp, flags) typeobject *v; FILE *fp; int flags; @@ -19,7 +14,7 @@ typeprint(v, fp, flags) } static object * -typerepr(v) +type_repr(v) typeobject *v; { char buf[100]; @@ -27,21 +22,16 @@ typerepr(v) return newstringobject(buf); } -typedef struct { - OB_HEAD - long ob_ival; -} intobject; - typeobject Typetype = { OB_HEAD_INIT(&Typetype) 0, /* Number of items for varobject */ "type", /* Name of this type */ sizeof(typeobject), /* Basic object size */ 0, /* Item size for varobject */ - 0, /*tp_dealloc*/ - typeprint, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - typerepr, /*tp_repr*/ + 0, /*tp_dealloc*/ + type_print, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + type_repr, /*tp_repr*/ }; diff --git a/Parser/acceler.c b/Parser/acceler.c index 7ff10b2..ce16711 100644 --- a/Parser/acceler.c +++ b/Parser/acceler.c @@ -1,11 +1,52 @@ /* Parser accelerator module */ -#include <stdio.h> +/* The parser as originally conceived had disappointing performance. + This module does some precomputation that speeds up the selection + of a DFA based upon a token, turning a search through an array + into a simple indexing operation. The parser now cannot work + without the accelerators installed. Note that the accelerators + are installed dynamically when the parser is initialized, they + are not part of the static data structure written on graminit.[ch] + by the parser generator. */ -#include "PROTO.h" +#include "pgenheaders.h" #include "grammar.h" #include "token.h" -#include "malloc.h" +#include "parser.h" + +/* Forward references */ +static void fixdfa PROTO((grammar *, dfa *)); +static void fixstate PROTO((grammar *, dfa *, state *)); + +void +addaccelerators(g) + grammar *g; +{ + dfa *d; + int i; +#ifdef DEBUG + printf("Adding parser accellerators ...\n"); +#endif + d = g->g_dfa; + for (i = g->g_ndfas; --i >= 0; d++) + fixdfa(g, d); + g->g_accel = 1; +#ifdef DEBUG + printf("Done.\n"); +#endif +} + +static void +fixdfa(g, d) + grammar *g; + dfa *d; +{ + state *s; + int j; + s = d->d_state; + for (j = 0; j < d->d_nstates; j++, s++) + fixstate(g, d, s); +} static void fixstate(g, d, s) @@ -69,33 +110,3 @@ fixstate(g, d, s) } DEL(accel); } - -static void -fixdfa(g, d) - grammar *g; - dfa *d; -{ - state *s; - int j; - s = d->d_state; - for (j = 0; j < d->d_nstates; j++, s++) - fixstate(g, d, s); -} - -void -addaccelerators(g) - grammar *g; -{ - dfa *d; - int i; -#ifdef DEBUG - printf("Adding parser accellerators ...\n"); -#endif - d = g->g_dfa; - for (i = g->g_ndfas; --i >= 0; d++) - fixdfa(g, d); - g->g_accel = 1; -#ifdef DEBUG - printf("Done.\n"); -#endif -} diff --git a/Parser/bitset.c b/Parser/bitset.c index b43fb82..655240a 100644 --- a/Parser/bitset.c +++ b/Parser/bitset.c @@ -1,7 +1,6 @@ -/* Bitset primitives */ +/* Bitset primitives used by the parser generator */ -#include "PROTO.h" -#include "malloc.h" +#include "pgenheaders.h" #include "bitset.h" bitset diff --git a/Parser/firstsets.c b/Parser/firstsets.c index 0f28dd0..b4a9e3c 100644 --- a/Parser/firstsets.c +++ b/Parser/firstsets.c @@ -1,14 +1,29 @@ /* Computation of FIRST stets */ -#include <stdio.h> - -#include "PROTO.h" -#include "malloc.h" +#include "pgenheaders.h" #include "grammar.h" #include "token.h" extern int debugging; +/* Forward */ +static void calcfirstset PROTO((grammar *, dfa *)); + +void +addfirstsets(g) + grammar *g; +{ + int i; + dfa *d; + + printf("Adding FIRST sets ...\n"); + for (i = 0; i < g->g_ndfas; i++) { + d = &g->g_dfa[i]; + if (d->d_first == NULL) + calcfirstset(g, d); + } +} + static void calcfirstset(g, d) grammar *g; @@ -92,18 +107,3 @@ calcfirstset(g, d) printf(" }\n"); } } - -void -addfirstsets(g) - grammar *g; -{ - int i; - dfa *d; - - printf("Adding FIRST sets ...\n"); - for (i = 0; i < g->g_ndfas; i++) { - d = &g->g_dfa[i]; - if (d->d_first == NULL) - calcfirstset(g, d); - } -} diff --git a/Parser/grammar.c b/Parser/grammar.c index ad9c2b0..221bf64 100644 --- a/Parser/grammar.c +++ b/Parser/grammar.c @@ -1,10 +1,9 @@ /* Grammar implementation */ -#include <stdio.h> +#include "pgenheaders.h" + #include <ctype.h> -#include "PROTO.h" -#include "malloc.h" #include "assert.h" #include "token.h" #include "grammar.h" @@ -127,6 +126,21 @@ findlabel(ll, type, str) abort(); } +/* Forward */ +static void translabel PROTO((grammar *, label *)); + +void +translatelabels(g) + grammar *g; +{ + int i; + + printf("Translating labels ...\n"); + /* Don't translate EMPTY */ + for (i = EMPTY+1; i < g->g_ll.ll_nlabels; i++) + translabel(g, &g->g_ll.ll_label[i]); +} + static void translabel(g, lb) grammar *g; @@ -193,15 +207,3 @@ translabel(g, lb) else printf("Can't translate label '%s'\n", labelrepr(lb)); } - -void -translatelabels(g) - grammar *g; -{ - int i; - - printf("Translating labels ...\n"); - /* Don't translate EMPTY */ - for (i = EMPTY+1; i < g->g_ll.ll_nlabels; i++) - translabel(g, &g->g_ll.ll_label[i]); -} diff --git a/Parser/grammar1.c b/Parser/grammar1.c index 0cd66af..6c10158 100644 --- a/Parser/grammar1.c +++ b/Parser/grammar1.c @@ -1,7 +1,6 @@ /* Grammar subroutines needed by parser */ -#include "PROTO.h" -#define NULL 0 +#include "pgenheaders.h" #include "assert.h" #include "grammar.h" #include "token.h" diff --git a/Parser/intrcheck.c b/Parser/intrcheck.c index f963208..8c35114 100644 --- a/Parser/intrcheck.c +++ b/Parser/intrcheck.c @@ -2,7 +2,7 @@ #ifdef MSDOS -/* This might work for MS-DOS: */ +/* This might work for MS-DOS (untested though): */ void initintr() @@ -37,7 +37,7 @@ initintr() int intrcheck() { - /* Static to make it faster(?) only */ + /* Static to make it faster only */ static EventRecord e; /* XXX This fails if the user first types ahead and then @@ -59,7 +59,7 @@ intrcheck() #ifndef OK -/* Default version -- should work for Unix and Standard C */ +/* Default version -- for real operating systems and for Standard C */ #include <stdio.h> #include <signal.h> diff --git a/Parser/listnode.c b/Parser/listnode.c index e0a979e..9d24c0f 100644 --- a/Parser/listnode.c +++ b/Parser/listnode.c @@ -1,13 +1,31 @@ /* List a node on a file */ -#include <stdio.h> - -#include "PROTO.h" +#include "pgenheaders.h" #include "token.h" #include "node.h" +/* Forward */ +static void list1node PROTO((FILE *, node *)); + +void +listtree(n) + node *n; +{ + listnode(stdout, n); +} + static int level, atbol; +void +listnode(fp, n) + FILE *fp; + node *n; +{ + level = 0; + atbol = 1; + list1node(fp, n); +} + static void list1node(fp, n) FILE *fp; @@ -49,20 +67,3 @@ list1node(fp, n) else fprintf(fp, "? "); } - -void -listnode(fp, n) - FILE *fp; - node *n; -{ - level = 0; - atbol = 1; - list1node(fp, n); -} - -void -listtree(n) - node *n; -{ - listnode(stdout, n); -} diff --git a/Parser/metagrammar.c b/Parser/metagrammar.c index a7e6364..c4606a5 100644 --- a/Parser/metagrammar.c +++ b/Parser/metagrammar.c @@ -1,6 +1,7 @@ -#include "PROTO.h" +#include "pgenheaders.h" #include "metagrammar.h" #include "grammar.h" +#include "pgen.h" static arc arcs_0_0[3] = { {2, 0}, {3, 0}, diff --git a/Parser/node.c b/Parser/node.c index 264fd9e..024dbd4 100644 --- a/Parser/node.c +++ b/Parser/node.c @@ -1,11 +1,10 @@ /* Parse tree node implementation */ -#include "PROTO.h" -#include "malloc.h" +#include "pgenheaders.h" #include "node.h" node * -newnode(type) +newtree(type) int type; { node *n = NEW(node, 1); @@ -13,6 +12,7 @@ newnode(type) return NULL; n->n_type = type; n->n_str = NULL; + n->n_lineno = 0; n->n_nchildren = 0; n->n_child = NULL; return n; @@ -22,10 +22,11 @@ newnode(type) #define XXXROUNDUP(n) ((n) == 1 ? 1 : ((n) + XXX - 1) / XXX * XXX) node * -addchild(n1, type, str) +addchild(n1, type, str, lineno) register node *n1; int type; char *str; + int lineno; { register int nch = n1->n_nchildren; register int nch1 = nch+1; @@ -41,11 +42,26 @@ addchild(n1, type, str) n = &n1->n_child[n1->n_nchildren++]; n->n_type = type; n->n_str = str; + n->n_lineno = lineno; n->n_nchildren = 0; n->n_child = NULL; return n; } +/* Forward */ +static void freechildren PROTO((node *)); + + +void +freetree(n) + node *n; +{ + if (n != NULL) { + freechildren(n); + DEL(n); + } +} + static void freechildren(n) node *n; @@ -58,13 +74,3 @@ freechildren(n) if (STR(n) != NULL) DEL(STR(n)); } - -void -freenode(n) - node *n; -{ - if (n != NULL) { - freechildren(n); - DEL(n); - } -} diff --git a/Parser/parser.c b/Parser/parser.c index 294c534..831d870 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -4,20 +4,17 @@ /* XXX To do: error recovery */ -#include <stdio.h> +#include "pgenheaders.h" #include "assert.h" - -#include "PROTO.h" -#include "malloc.h" #include "token.h" #include "grammar.h" #include "node.h" #include "parser.h" #include "errcode.h" -extern int debugging; #ifdef DEBUG +extern int debugging; #define D(x) if (!debugging); else x #else #define D(x) @@ -94,7 +91,7 @@ newparser(g, start) if (ps == NULL) return NULL; ps->p_grammar = g; - ps->p_tree = newnode(start); + ps->p_tree = newtree(start); if (ps->p_tree == NULL) { DEL(ps); return NULL; @@ -110,24 +107,25 @@ delparser(ps) { /* NB If you want to save the parse tree, you must set p_tree to NULL before calling delparser! */ - freenode(ps->p_tree); + freetree(ps->p_tree); DEL(ps); } /* PARSER STACK OPERATIONS */ -static int shift PROTO((stack *, int, char *, int)); +static int shift PROTO((stack *, int, char *, int, int)); static int -shift(s, type, str, newstate) +shift(s, type, str, newstate, lineno) register stack *s; int type; char *str; int newstate; + int lineno; { assert(!s_empty(s)); - if (addchild(s->s_top->s_parent, type, str) == NULL) { + if (addchild(s->s_top->s_parent, type, str, lineno) == NULL) { fprintf(stderr, "shift: no mem in addchild\n"); return -1; } @@ -135,19 +133,20 @@ shift(s, type, str, newstate) return 0; } -static int push PROTO((stack *, int, dfa *, int)); +static int push PROTO((stack *, int, dfa *, int, int)); static int -push(s, type, d, newstate) +push(s, type, d, newstate, lineno) register stack *s; int type; dfa *d; int newstate; + int lineno; { register node *n; n = s->s_top->s_parent; assert(!s_empty(s)); - if (addchild(n, type, (char *)NULL) == NULL) { + if (addchild(n, type, (char *)NULL, lineno) == NULL) { fprintf(stderr, "push: no mem in addchild\n"); return -1; } @@ -198,10 +197,11 @@ classify(g, type, str) } int -addtoken(ps, type, str) +addtoken(ps, type, str, lineno) register parser_state *ps; register int type; char *str; + int lineno; { register int ilabel; @@ -230,7 +230,8 @@ addtoken(ps, type, str) int nt = (x >> 8) + NT_OFFSET; int arrow = x & ((1<<7)-1); dfa *d1 = finddfa(ps->p_grammar, nt); - if (push(&ps->p_stack, nt, d1, arrow) < 0) { + if (push(&ps->p_stack, nt, d1, + arrow, lineno) < 0) { D(printf(" MemError: push.\n")); return E_NOMEM; } @@ -239,7 +240,8 @@ addtoken(ps, type, str) } /* Shift the token */ - if (shift(&ps->p_stack, type, str, x) < 0) { + if (shift(&ps->p_stack, type, str, + x, lineno) < 0) { D(printf(" MemError: shift.\n")); return E_NOMEM; } diff --git a/Parser/parser.h b/Parser/parser.h index 16eee0e..1ada8cc 100644 --- a/Parser/parser.h +++ b/Parser/parser.h @@ -5,7 +5,7 @@ typedef struct _stackentry { int s_state; /* State in current DFA */ dfa *s_dfa; /* Current DFA */ - node *s_parent; /* Where to add next node */ + struct _node *s_parent; /* Where to add next node */ } stackentry; typedef struct _stack { @@ -22,4 +22,5 @@ typedef struct { parser_state *newparser PROTO((struct _grammar *g, int start)); void delparser PROTO((parser_state *ps)); -int addtoken PROTO((parser_state *ps, int type, char *str)); +int addtoken PROTO((parser_state *ps, int type, char *str, int lineno)); +void addaccelerators PROTO((grammar *g)); diff --git a/Parser/parsetok.c b/Parser/parsetok.c index 100ca65..c75656f 100644 --- a/Parser/parsetok.c +++ b/Parser/parsetok.c @@ -1,74 +1,19 @@ /* Parser-tokenizer link implementation */ -#include <stdio.h> - -#include "PROTO.h" -#include "malloc.h" +#include "pgenheaders.h" #include "tokenizer.h" #include "node.h" #include "grammar.h" #include "parser.h" +#include "parsetok.h" #include "errcode.h" -extern int debugging; - -/* Parse input coming from the given tokenizer structure. - Return error code. */ - -static int -parsetok(tok, g, start, n_ret) - struct tok_state *tok; - grammar *g; - int start; - node **n_ret; -{ - parser_state *ps; - int ret; - - if ((ps = newparser(g, start)) == NULL) { - fprintf(stderr, "no mem for new parser\n"); - return E_NOMEM; - } - - for (;;) { - char *a, *b; - int type; - int len; - char *str; - - type = tok_get(tok, &a, &b); - if (type == ERRORTOKEN) { - ret = tok->done; - break; - } - len = b - a; - str = NEW(char, len + 1); - if (str == NULL) { - fprintf(stderr, "no mem for next token\n"); - ret = E_NOMEM; - break; - } - strncpy(str, a, len); - str[len] = '\0'; - ret = addtoken(ps, (int)type, str); - if (ret != E_OK) { - if (ret == E_DONE) { - *n_ret = ps->p_tree; - ps->p_tree = NULL; - } - else if (tok->lineno <= 1 && tok->done == E_EOF) - ret = E_EOF; - break; - } - } - - delparser(ps); - return ret; -} +/* Forward */ +static int parsetok PROTO((struct tok_state *, grammar *, int, node **)); -/* Parse input coming from a string. Return error code. */ +/* Parse input coming from a string. Return error code, print some errors. */ int parsestring(s, g, start, n_ret) @@ -94,11 +39,12 @@ parsestring(s, g, start, n_ret) } -/* Parse input coming from a file. Return error code. */ +/* Parse input coming from a file. Return error code, print some errors. */ int -parsefile(fp, g, start, ps1, ps2, n_ret) +parsefile(fp, filename, g, start, ps1, ps2, n_ret) FILE *fp; + char *filename; grammar *g; int start; char *ps1, *ps2; @@ -114,7 +60,8 @@ parsefile(fp, g, start, ps1, ps2, n_ret) ret = parsetok(tok, g, start, n_ret); if (ret == E_TOKEN || ret == E_SYNTAX) { char *p; - fprintf(stderr, "Parsing error at line %d:\n", tok->lineno); + fprintf(stderr, "Parsing error: file %s, line %d:\n", + filename, tok->lineno); *tok->inp = '\0'; if (tok->inp > tok->buf && tok->inp[-1] == '\n') tok->inp[-1] = '\0'; @@ -130,3 +77,58 @@ parsefile(fp, g, start, ps1, ps2, n_ret) tok_free(tok); return ret; } + + +/* Parse input coming from the given tokenizer structure. + Return error code. */ + +static int +parsetok(tok, g, start, n_ret) + struct tok_state *tok; + grammar *g; + int start; + node **n_ret; +{ + parser_state *ps; + int ret; + + if ((ps = newparser(g, start)) == NULL) { + fprintf(stderr, "no mem for new parser\n"); + return E_NOMEM; + } + + for (;;) { + char *a, *b; + int type; + int len; + char *str; + + type = tok_get(tok, &a, &b); + if (type == ERRORTOKEN) { + ret = tok->done; + break; + } + len = b - a; + str = NEW(char, len + 1); + if (str == NULL) { + fprintf(stderr, "no mem for next token\n"); + ret = E_NOMEM; + break; + } + strncpy(str, a, len); + str[len] = '\0'; + ret = addtoken(ps, (int)type, str, tok->lineno); + if (ret != E_OK) { + if (ret == E_DONE) { + *n_ret = ps->p_tree; + ps->p_tree = NULL; + } + else if (tok->lineno <= 1 && tok->done == E_EOF) + ret = E_EOF; + break; + } + } + + delparser(ps); + return ret; +} diff --git a/Parser/pgen.c b/Parser/pgen.c index 34d9b71..21795d6 100644 --- a/Parser/pgen.c +++ b/Parser/pgen.c @@ -1,12 +1,10 @@ /* Parser generator */ +/* XXX This file is not yet fully PROTOized */ /* For a description, see the comments at end of this file */ -#include <stdio.h> +#include "pgenheaders.h" #include "assert.h" - -#include "PROTO.h" -#include "malloc.h" #include "token.h" #include "node.h" #include "grammar.h" diff --git a/Parser/pgen.h b/Parser/pgen.h index 7fcf277..45eb2ed 100644 --- a/Parser/pgen.h +++ b/Parser/pgen.h @@ -3,4 +3,4 @@ extern grammar gram; extern grammar *meta_grammar PROTO((void)); -extern grammar *pgen PROTO((node *)); +extern grammar *pgen PROTO((struct _node *)); diff --git a/Parser/pgenmain.c b/Parser/pgenmain.c index 678be5d..6eae230 100644 --- a/Parser/pgenmain.c +++ b/Parser/pgenmain.c @@ -1,8 +1,14 @@ /* Parser generator main program */ -#include <stdio.h> +/* This expects a filename containing the grammar as argv[1] (UNIX) + or asks the console for such a file name (THINK C). + It writes its output on two files in the current directory: + - "graminit.c" gets the grammar as a bunch of initialized data + - "graminit.h" gets the grammar's non-terminals as #defines. + Error messages and status info during the generation process are + written to stdout, or sometimes to stderr. */ -#include "PROTO.h" +#include "pgenheaders.h" #include "grammar.h" #include "node.h" #include "parsetok.h" @@ -10,24 +16,51 @@ int debugging; +/* Forward */ +grammar *getgrammar PROTO((char *filename)); #ifdef THINK_C -char * -askfile() +int main PROTO((int, char **)); +char *askfile PROTO((void)); +#endif + +int +main(argc, argv) + int argc; + char **argv; { - char buf[256]; - static char name[256]; - printf("Input file name: "); - if (fgets(buf, sizeof buf, stdin) == NULL) { - printf("EOF\n"); + grammar *g; + node *n; + FILE *fp; + char *filename; + +#ifdef THINK_C + filename = askfile(); +#else + if (argc != 2) { + fprintf(stderr, "usage: %s grammar\n", argv[0]); + exit(2); + } + filename = argv[1]; +#endif + g = getgrammar(filename); + fp = fopen("graminit.c", "w"); + if (fp == NULL) { + perror("graminit.c"); exit(1); } - if (sscanf(buf, " %s ", name) != 1) { - printf("No file\n"); + printf("Writing graminit.c ...\n"); + printgrammar(g, fp); + fclose(fp); + fp = fopen("graminit.h", "w"); + if (fp == NULL) { + perror("graminit.h"); exit(1); } - return name; + printf("Writing graminit.h ...\n"); + printnonterminals(g, fp); + fclose(fp); + exit(0); } -#endif grammar * getgrammar(filename) @@ -44,7 +77,7 @@ getgrammar(filename) } g0 = meta_grammar(); n = NULL; - parsefile(fp, g0, g0->g_start, (char *)NULL, (char *)NULL, &n); + parsefile(fp, filename, g0, g0->g_start, (char *)NULL, (char *)NULL, &n); fclose(fp); if (n == NULL) { fprintf(stderr, "Parsing error.\n"); @@ -58,43 +91,25 @@ getgrammar(filename) return g; } -main(argc, argv) - int argc; - char **argv; -{ - grammar *g; - node *n; - FILE *fp; - char *filename; - #ifdef THINK_C - filename = askfile(); -#else - if (argc != 2) { - fprintf(stderr, "usage: %s grammar\n", argv[0]); - exit(2); - } - filename = argv[1]; -#endif - g = getgrammar(filename); - fp = fopen("graminit.c", "w"); - if (fp == NULL) { - perror("graminit.c"); +char * +askfile() +{ + char buf[256]; + static char name[256]; + printf("Input file name: "); + if (fgets(buf, sizeof buf, stdin) == NULL) { + printf("EOF\n"); exit(1); } - printf("Writing graminit.c ...\n"); - printgrammar(g, fp); - fclose(fp); - fp = fopen("graminit.h", "w"); - if (fp == NULL) { - perror("graminit.h"); + /* XXX The (unsigned char *) case is needed by THINK C */ + if (sscanf((unsigned char *)buf, " %s ", name) != 1) { + printf("No file\n"); exit(1); } - printf("Writing graminit.h ...\n"); - printnonterminals(g, fp); - fclose(fp); - exit(0); + return name; } +#endif void fatal(msg) @@ -104,8 +119,6 @@ fatal(msg) exit(1); } -/* TO DO: - - - improve user interface - - check for duplicate definitions of names (instead of fatal err) +/* XXX TO DO: + - check for duplicate definitions of names (instead of fatal err) */ diff --git a/Parser/printgrammar.c b/Parser/printgrammar.c index f6aa2cc..00a8d47 100644 --- a/Parser/printgrammar.c +++ b/Parser/printgrammar.c @@ -1,10 +1,44 @@ /* Print a bunch of C initializers that represent a grammar */ -#include <stdio.h> - -#include "PROTO.h" +#include "pgenheaders.h" #include "grammar.h" +/* Forward */ +static void printarcs PROTO((int, dfa *, FILE *)); +static void printstates PROTO((grammar *, FILE *)); +static void printdfas PROTO((grammar *, FILE *)); +static void printlabels PROTO((grammar *, FILE *)); + +void +printgrammar(g, fp) + grammar *g; + FILE *fp; +{ + fprintf(fp, "#include \"pgenheaders.h\"\n"); + fprintf(fp, "#include \"grammar.h\"\n"); + printdfas(g, fp); + printlabels(g, fp); + fprintf(fp, "grammar gram = {\n"); + fprintf(fp, "\t%d,\n", g->g_ndfas); + fprintf(fp, "\tdfas,\n"); + fprintf(fp, "\t{%d, labels},\n", g->g_ll.ll_nlabels); + fprintf(fp, "\t%d\n", g->g_start); + fprintf(fp, "};\n"); +} + +void +printnonterminals(g, fp) + grammar *g; + FILE *fp; +{ + dfa *d; + int i; + + d = g->g_dfa; + for (i = g->g_ndfas; --i >= 0; d++) + fprintf(fp, "#define %s %d\n", d->d_name, d->d_type); +} + static void printarcs(i, d, fp) int i; @@ -89,33 +123,3 @@ printlabels(g, fp) } fprintf(fp, "};\n"); } - -void -printgrammar(g, fp) - grammar *g; - FILE *fp; -{ - fprintf(fp, "#include \"PROTO.h\"\n"); - fprintf(fp, "#include \"grammar.h\"\n"); - printdfas(g, fp); - printlabels(g, fp); - fprintf(fp, "grammar gram = {\n"); - fprintf(fp, "\t%d,\n", g->g_ndfas); - fprintf(fp, "\tdfas,\n"); - fprintf(fp, "\t{%d, labels},\n", g->g_ll.ll_nlabels); - fprintf(fp, "\t%d\n", g->g_start); - fprintf(fp, "};\n"); -} - -void -printnonterminals(g, fp) - grammar *g; - FILE *fp; -{ - dfa *d; - int i; - - d = g->g_dfa; - for (i = g->g_ndfas; --i >= 0; d++) - fprintf(fp, "#define %s %d\n", d->d_name, d->d_type); -} diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 97eda75..ad6f63a 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -2,13 +2,14 @@ /* XXX This is rather old, should be restructured perhaps */ /* XXX Need a better interface to report errors than writing to stderr */ +/* XXX Should use editor resource to fetch true tab size on Macintosh */ + +#include "pgenheaders.h" -#include <stdio.h> #include <ctype.h> #include "string.h" -#include "PROTO.h" -#include "malloc.h" +#include "fgetsintr.h" #include "tokenizer.h" #include "errcode.h" @@ -20,6 +21,11 @@ #define TABSIZE 8 #endif +/* Forward */ +static struct tok_state *tok_new PROTO((void)); +static int tok_nextc PROTO((struct tok_state *tok)); +static void tok_backup PROTO((struct tok_state *tok, int c)); + /* Token names */ char *tok_name[] = { @@ -352,7 +358,9 @@ tok_get(tok, p_start, p_end) This is also recognized by vi, when it occurs near the beginning or end of the file. (Will vi never die...?) */ int x; - if (sscanf(tok->cur, " vi:set tabsize=%d:", &x) == 1 && + /* XXX The case to (unsigned char *) is needed by THINK C */ + if (sscanf((unsigned char *)tok->cur, + " vi:set tabsize=%d:", &x) == 1 && x >= 1 && x <= 40) { fprintf(stderr, "# vi:set tabsize=%d:\n", x); tok->tabsize = x; diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c new file mode 100644 index 0000000..dc88581 --- /dev/null +++ b/Python/bltinmodule.c @@ -0,0 +1,535 @@ +/* Built-in functions */ + +#include "allobjects.h" + +#include "node.h" +#include "graminit.h" +#include "errcode.h" +#include "sysmodule.h" +#include "builtinmodule.h" +#include "import.h" +#include "pythonrun.h" +#include "compile.h" /* For ceval.h */ +#include "ceval.h" +#include "modsupport.h" + +static object * +builtin_abs(self, v) + object *self; + object *v; +{ + /* XXX This should be a method in the as_number struct in the type */ + if (v == NULL) { + /* */ + } + else if (is_intobject(v)) { + long x = getintvalue(v); + if (x < 0) + x = -x; + return newintobject(x); + } + else if (is_floatobject(v)) { + double x = getfloatvalue(v); + if (x < 0) + x = -x; + return newfloatobject(x); + } + err_setstr(TypeError, "abs() argument must be float or int"); + return NULL; +} + +static object * +builtin_chr(self, v) + object *self; + object *v; +{ + long x; + char s[1]; + if (v == NULL || !is_intobject(v)) { + err_setstr(TypeError, "chr() must have int argument"); + return NULL; + } + x = getintvalue(v); + if (x < 0 || x >= 256) { + err_setstr(RuntimeError, "chr() arg not in range(256)"); + return NULL; + } + s[0] = x; + return newsizedstringobject(s, 1); +} + +static object * +builtin_dir(self, v) + object *self; + object *v; +{ + object *d; + if (v == NULL) { + d = getlocals(); + } + else { + if (!is_moduleobject(v)) { + err_setstr(TypeError, + "dir() argument, must be module or absent"); + return NULL; + } + d = getmoduledict(v); + } + v = getdictkeys(d); + if (sortlist(v) != 0) { + DECREF(v); + v = NULL; + } + return v; +} + +static object * +builtin_divmod(self, v) + object *self; + object *v; +{ + object *x, *y; + long xi, yi, xdivy, xmody; + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { + err_setstr(TypeError, "divmod() requires 2 int arguments"); + return NULL; + } + x = gettupleitem(v, 0); + y = gettupleitem(v, 1); + if (!is_intobject(x) || !is_intobject(y)) { + err_setstr(TypeError, "divmod() requires 2 int arguments"); + return NULL; + } + xi = getintvalue(x); + yi = getintvalue(y); + if (yi == 0) { + err_setstr(TypeError, "divmod() division by zero"); + return NULL; + } + if (yi < 0) { + xdivy = -xi / -yi; + } + else { + xdivy = xi / yi; + } + xmody = xi - xdivy*yi; + if (xmody < 0 && yi > 0 || xmody > 0 && yi < 0) { + xmody += yi; + xdivy -= 1; + } + v = newtupleobject(2); + x = newintobject(xdivy); + y = newintobject(xmody); + if (v == NULL || x == NULL || y == NULL || + settupleitem(v, 0, x) != 0 || + settupleitem(v, 1, y) != 0) { + XDECREF(v); + XDECREF(x); + XDECREF(y); + return NULL; + } + return v; +} + +static object * +exec_eval(v, start) + object *v; + int start; +{ + object *str = NULL, *globals = NULL, *locals = NULL; + int n; + if (v != NULL) { + if (is_stringobject(v)) + str = v; + else if (is_tupleobject(v) && + ((n = gettuplesize(v)) == 2 || n == 3)) { + str = gettupleitem(v, 0); + globals = gettupleitem(v, 1); + if (n == 3) + locals = gettupleitem(v, 2); + } + } + if (str == NULL || !is_stringobject(str) || + globals != NULL && !is_dictobject(globals) || + locals != NULL && !is_dictobject(locals)) { + err_setstr(TypeError, + "exec/eval arguments must be string[,dict[,dict]]"); + return NULL; + } + return run_string(getstringvalue(str), start, globals, locals); +} + +static object * +builtin_eval(self, v) + object *self; + object *v; +{ + return exec_eval(v, eval_input); +} + +static object * +builtin_exec(self, v) + object *self; + object *v; +{ + return exec_eval(v, file_input); +} + +static object * +builtin_float(self, v) + object *self; + object *v; +{ + if (v == NULL) { + /* */ + } + else if (is_floatobject(v)) { + INCREF(v); + return v; + } + else if (is_intobject(v)) { + long x = getintvalue(v); + return newfloatobject((double)x); + } + err_setstr(TypeError, "float() argument must be float or int"); + return NULL; +} + +static object * +builtin_input(self, v) + object *self; + object *v; +{ + FILE *in = sysgetfile("stdin", stdin); + FILE *out = sysgetfile("stdout", stdout); + node *n; + int err; + object *m, *d; + flushline(); + if (v != NULL) + printobject(v, out, PRINT_RAW); + m = add_module("__main__"); + d = getmoduledict(m); + return run_file(in, "<stdin>", expr_input, d, d); +} + +static object * +builtin_int(self, v) + object *self; + object *v; +{ + if (v == NULL) { + /* */ + } + else if (is_intobject(v)) { + INCREF(v); + return v; + } + else if (is_floatobject(v)) { + double x = getfloatvalue(v); + return newintobject((long)x); + } + err_setstr(TypeError, "int() argument must be float or int"); + return NULL; +} + +static object * +builtin_len(self, v) + object *self; + object *v; +{ + long len; + typeobject *tp; + if (v == NULL) { + err_setstr(TypeError, "len() without argument"); + return NULL; + } + tp = v->ob_type; + if (tp->tp_as_sequence != NULL) { + len = (*tp->tp_as_sequence->sq_length)(v); + } + else if (tp->tp_as_mapping != NULL) { + len = (*tp->tp_as_mapping->mp_length)(v); + } + else { + err_setstr(TypeError, "len() of unsized object"); + return NULL; + } + return newintobject(len); +} + +static object * +min_max(v, sign) + object *v; + int sign; +{ + int i, n, cmp; + object *w, *x; + sequence_methods *sq; + if (v == NULL) { + err_setstr(TypeError, "min() or max() without argument"); + return NULL; + } + sq = v->ob_type->tp_as_sequence; + if (sq == NULL) { + err_setstr(TypeError, "min() or max() of non-sequence"); + return NULL; + } + n = (*sq->sq_length)(v); + if (n == 0) { + err_setstr(RuntimeError, "min() or max() of empty sequence"); + return NULL; + } + w = (*sq->sq_item)(v, 0); /* Implies INCREF */ + for (i = 1; i < n; i++) { + x = (*sq->sq_item)(v, i); /* Implies INCREF */ + cmp = cmpobject(x, w); + if (cmp * sign > 0) { + DECREF(w); + w = x; + } + else + DECREF(x); + } + return w; +} + +static object * +builtin_min(self, v) + object *self; + object *v; +{ + return min_max(v, -1); +} + +static object * +builtin_max(self, v) + object *self; + object *v; +{ + return min_max(v, 1); +} + +static object * +builtin_open(self, v) + object *self; + object *v; +{ + object *name, *mode; + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2 || + !is_stringobject(name = gettupleitem(v, 0)) || + !is_stringobject(mode = gettupleitem(v, 1))) { + err_setstr(TypeError, "open() requires 2 string arguments"); + return NULL; + } + v = newfileobject(getstringvalue(name), getstringvalue(mode)); + return v; +} + +static object * +builtin_ord(self, v) + object *self; + object *v; +{ + if (v == NULL || !is_stringobject(v)) { + err_setstr(TypeError, "ord() must have string argument"); + return NULL; + } + if (getstringsize(v) != 1) { + err_setstr(RuntimeError, "ord() arg must have length 1"); + return NULL; + } + return newintobject((long)(getstringvalue(v)[0] & 0xff)); +} + +static object * +builtin_range(self, v) + object *self; + object *v; +{ + static char *errmsg = "range() requires 1-3 int arguments"; + int i, n; + long ilow, ihigh, istep; + if (v != NULL && is_intobject(v)) { + ilow = 0; ihigh = getintvalue(v); istep = 1; + } + else if (v == NULL || !is_tupleobject(v)) { + err_setstr(TypeError, errmsg); + return NULL; + } + else { + n = gettuplesize(v); + if (n < 1 || n > 3) { + err_setstr(TypeError, errmsg); + return NULL; + } + for (i = 0; i < n; i++) { + if (!is_intobject(gettupleitem(v, i))) { + err_setstr(TypeError, errmsg); + return NULL; + } + } + if (n == 3) { + istep = getintvalue(gettupleitem(v, 2)); + --n; + } + else + istep = 1; + ihigh = getintvalue(gettupleitem(v, --n)); + if (n > 0) + ilow = getintvalue(gettupleitem(v, 0)); + else + ilow = 0; + } + if (istep == 0) { + err_setstr(RuntimeError, "zero step for range()"); + return NULL; + } + /* XXX ought to check overflow of subtraction */ + if (istep > 0) + n = (ihigh - ilow + istep - 1) / istep; + else + n = (ihigh - ilow + istep + 1) / istep; + if (n < 0) + n = 0; + v = newlistobject(n); + if (v == NULL) + return NULL; + for (i = 0; i < n; i++) { + object *w = newintobject(ilow); + if (w == NULL) { + DECREF(v); + return NULL; + } + setlistitem(v, i, w); + ilow += istep; + } + return v; +} + +static object * +builtin_raw_input(self, v) + object *self; + object *v; +{ + FILE *in = sysgetfile("stdin", stdin); + FILE *out = sysgetfile("stdout", stdout); + char *p; + int err; + int n = 1000; + flushline(); + if (v != NULL) + printobject(v, out, PRINT_RAW); + v = newsizedstringobject((char *)NULL, n); + if (v != NULL) { + if ((err = fgets_intr(getstringvalue(v), n+1, in)) != E_OK) { + err_input(err); + DECREF(v); + return NULL; + } + else { + n = strlen(getstringvalue(v)); + if (n > 0 && getstringvalue(v)[n-1] == '\n') + n--; + resizestring(&v, n); + } + } + return v; +} + +static object * +builtin_reload(self, v) + object *self; + object *v; +{ + return reload_module(v); +} + +static object * +builtin_type(self, v) + object *self; + object *v; +{ + if (v == NULL) { + err_setstr(TypeError, "type() requres an argument"); + return NULL; + } + v = (object *)v->ob_type; + INCREF(v); + return v; +} + +static struct methodlist builtin_methods[] = { + {"abs", builtin_abs}, + {"chr", builtin_chr}, + {"dir", builtin_dir}, + {"divmod", builtin_divmod}, + {"eval", builtin_eval}, + {"exec", builtin_exec}, + {"float", builtin_float}, + {"input", builtin_input}, + {"int", builtin_int}, + {"len", builtin_len}, + {"min", builtin_min}, + {"max", builtin_max}, + {"open", builtin_open}, /* XXX move to OS module */ + {"ord", builtin_ord}, + {"range", builtin_range}, + {"raw_input", builtin_raw_input}, + {"reload", builtin_reload}, + {"type", builtin_type}, + {NULL, NULL}, +}; + +static object *builtin_dict; + +object * +getbuiltin(name) + char *name; +{ + return dictlookup(builtin_dict, name); +} + +/* Predefined exceptions */ + +object *RuntimeError; +object *EOFError; +object *TypeError; +object *MemoryError; +object *NameError; +object *SystemError; +object *KeyboardInterrupt; + +static object * +newstdexception(name, message) + char *name, *message; +{ + object *v = newstringobject(message); + if (v == NULL || dictinsert(builtin_dict, name, v) != 0) + fatal("no mem for new standard exception"); + return v; +} + +static void +initerrors() +{ + RuntimeError = newstdexception("RuntimeError", "run-time error"); + EOFError = newstdexception("EOFError", "end-of-file read"); + TypeError = newstdexception("TypeError", "type error"); + MemoryError = newstdexception("MemoryError", "out of memory"); + NameError = newstdexception("NameError", "undefined name"); + SystemError = newstdexception("SystemError", "system error"); + KeyboardInterrupt = + newstdexception("KeyboardInterrupt", "keyboard interrupt"); +} + +void +initbuiltin() +{ + object *m; + m = initmodule("builtin", builtin_methods); + builtin_dict = getmoduledict(m); + INCREF(builtin_dict); + initerrors(); + (void) dictinsert(builtin_dict, "None", None); +} diff --git a/Python/ceval.c b/Python/ceval.c index 0074cd0..5c9548d 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1,309 +1,62 @@ -/* Evaluate compiled expression nodes */ +/* Execute compiled code */ -#include <stdio.h> -#include <ctype.h> -#include "string.h" +#include "allobjects.h" -#include "PROTO.h" -#include "object.h" -#include "objimpl.h" -#include "intobject.h" -#include "stringobject.h" -#include "tupleobject.h" -#include "listobject.h" -#include "dictobject.h" -#include "builtinobject.h" -#include "methodobject.h" -#include "moduleobject.h" -#include "context.h" -#include "funcobject.h" -#include "classobject.h" -#include "token.h" -#include "graminit.h" -#include "run.h" #include "import.h" -#include "support.h" #include "sysmodule.h" #include "compile.h" +#include "frameobject.h" +#include "ceval.h" #include "opcode.h" +#include "builtinmodule.h" +#include "traceback.h" -/* List access macros */ -#ifdef NDEBUG -#define GETITEM(v, i) GETLISTITEM((listobject *)(v), (i)) -#define GETITEMNAME(v, i) GETSTRINGVALUE((stringobject *)GETITEM((v), (i))) -#else -#define GETITEM(v, i) getlistitem((v), (i)) -#define GETITEMNAME(v, i) getstringvalue(getlistitem((v), (i))) +#ifndef NDEBUG +#define TRACE #endif -typedef struct { - int b_type; /* what kind of block this is */ - int b_handler; /* where to jump to find handler */ - int b_level; /* value stack level to pop to */ -} block; - -typedef struct _frame { - OB_HEAD - struct _frame *f_back; /* previous frame, or NULL */ - codeobject *f_code; /* code segment */ - object *f_locals; /* local symbol table (dictobject) */ - object *f_globals; /* global symbol table (dictobject) */ - object **f_valuestack; /* malloc'ed array */ - block *f_blockstack; /* malloc'ed array */ - int f_nvalues; /* size of f_valuestack */ - int f_nblocks; /* size of f_blockstack */ - int f_ivalue; /* index in f_valuestack */ - int f_iblock; /* index in f_blockstack */ - int f_nexti; /* index in f_code (next instruction) */ -} frameobject; - -#define is_frameobject(op) ((op)->ob_type == &Frametype) - -static void -frame_dealloc(f) - frameobject *f; -{ - XDECREF(f->f_back); - XDECREF(f->f_code); - XDECREF(f->f_locals); - XDECREF(f->f_globals); - XDEL(f->f_valuestack); - XDEL(f->f_blockstack); - DEL(f); -} -typeobject Frametype = { - OB_HEAD_INIT(&Typetype) - 0, - "frame", - sizeof(frameobject), - 0, - frame_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*/ -}; - -static frameobject * newframeobject PROTO( - (frameobject *, codeobject *, object *, object *, int, int)); - -static frameobject * -newframeobject(back, code, locals, globals, nvalues, nblocks) - frameobject *back; - codeobject *code; - object *locals; - object *globals; - int nvalues; - int nblocks; -{ - frameobject *f; - if ((back != NULL && !is_frameobject(back)) || - code == NULL || !is_codeobject(code) || - locals == NULL || !is_dictobject(locals) || - globals == NULL || !is_dictobject(globals) || - nvalues < 0 || nblocks < 0) { - err_badcall(); - return NULL; - } - f = NEWOBJ(frameobject, &Frametype); - if (f != NULL) { - if (back) - INCREF(back); - f->f_back = back; - INCREF(code); - f->f_code = code; - INCREF(locals); - f->f_locals = locals; - INCREF(globals); - f->f_globals = globals; - f->f_valuestack = NEW(object *, nvalues+1); - f->f_blockstack = NEW(block, nblocks+1); - f->f_nvalues = nvalues; - f->f_nblocks = nblocks; - f->f_ivalue = f->f_iblock = f->f_nexti = 0; - if (f->f_valuestack == NULL || f->f_blockstack == NULL) { - err_nomem(); - DECREF(f); - f = NULL; - } - } - return f; -} - -#define GETUSTRINGVALUE(s) ((unsigned char *)GETSTRINGVALUE(s)) - -#define Push(f, v) ((f)->f_valuestack[(f)->f_ivalue++] = (v)) -#define Pop(f) ((f)->f_valuestack[--(f)->f_ivalue]) -#define Top(f) ((f)->f_valuestack[(f)->f_ivalue-1]) -#define Empty(f) ((f)->f_ivalue == 0) -#define Full(f) ((f)->f_ivalue == (f)->f_nvalues) -#define Nextbyte(f) (GETUSTRINGVALUE((f)->f_code->co_code)[(f)->f_nexti++]) -#define Peekbyte(f) (GETUSTRINGVALUE((f)->f_code->co_code)[(f)->f_nexti]) -#define Peekint(f) \ - (GETUSTRINGVALUE((f)->f_code->co_code)[(f)->f_nexti] + \ - GETUSTRINGVALUE((f)->f_code->co_code)[(f)->f_nexti+1]) -#define Prevbyte(f) (GETUSTRINGVALUE((f)->f_code->co_code)[(f)->f_nexti-1]) -#define Jumpto(f, x) ((f)->f_nexti = (x)) -#define Jumpby(f, x) ((f)->f_nexti += (x)) -#define Getconst(f, i) (GETITEM((f)->f_code->co_consts, (i))) -#define Getname(f, i) (GETITEMNAME((f)->f_code->co_names, (i))) - -/* Corresponding functions, for debugging */ - -static void -push(f, v) - frameobject *f; - object *v; -{ - if (Full(f)) { - printf("stack overflow\n"); - abort(); - } - Push(f, v); -} - -static object * -pop(f) - frameobject *f; -{ - if (Empty(f)) { - printf("stack underflow\n"); - abort(); - } - return Pop(f); -} - -static object * -top(f) - frameobject *f; -{ - if (Empty(f)) { - printf("stack underflow\n"); - abort(); - } - return Top(f); -} - -static int -nextbyte(f) - frameobject *f; -{ - stringobject *code = (f)->f_code->co_code; - if (f->f_nexti >= getstringsize((object *)code)) { - printf("ran off end of instructions\n"); - abort(); - } - return GETUSTRINGVALUE(code)[f->f_nexti++]; -} - +#ifdef TRACE static int -nextint(f) - frameobject *f; -{ - int a, b; -#ifdef NDEBUG - a = Nextbyte(f); - b = Nextbyte(f); -#else - a = nextbyte(f); - b = nextbyte(f); -#endif - return a + (b << 8); -} - -/* Tracing versions */ - -static void -trace_push(f, v) - frameobject *f; +prtrace(v, str) object *v; + char *str; { - printf("\tpush "); + printf("%s ", str); printobject(v, stdout, 0); printf("\n"); - push(f, v); -} - -static object * -trace_pop(f) - frameobject *f; -{ - object *v; - v = pop(f); - printf("\tpop "); - printobject(v, stdout, 0); - printf("\n"); - return v; } +#endif -static object * -trace_top(f) - frameobject *f; -{ - object *v; - v = top(f); - printf("\ttop "); - printobject(v, stdout, 0); - printf("\n"); - return v; -} +static frameobject *current_frame; -static int -trace_nextop(f) - frameobject *f; +object * +getlocals() { - int op; - int arg; - - printf("%d: ", f->f_nexti); - op = nextbyte(f); - if (op < HAVE_ARGUMENT) - printf("op %3d\n", op); - else { - arg = Peekint(f); - printf("op %d arg %d\n", op, arg); - } - return op; + if (current_frame == NULL) + return NULL; + else + return current_frame->f_locals; } -/* Block management */ - -static void -setup_block(f, type, handler) - frameobject *f; - int type; - int handler; +object * +getglobals() { - block *b; - if (f->f_iblock >= f->f_nblocks) { - printf("block stack overflow\n"); - abort(); - } - b = &f->f_blockstack[f->f_iblock++]; - b->b_type = type; - b->b_level = f->f_ivalue; - b->b_handler = handler + f->f_nexti; + if (current_frame == NULL) + return NULL; + else + return current_frame->f_globals; } -static block * -pop_block(f) - frameobject *f; +void +printtraceback(fp) + FILE *fp; { - block *b; - if (f->f_iblock <= 0) { - printf("block stack underflow\n"); - abort(); - } - b = &f->f_blockstack[--f->f_iblock]; - while (f->f_ivalue > b->b_level) { - object *v = Pop(f); - XDECREF(v); + object *v = tb_fetch(); + if (v != NULL) { + fprintf(fp, "Stack backtrace (innermost last):\n"); + tb_print(v, fp); + DECREF(v); } - return b; } @@ -323,19 +76,29 @@ flushline() } } -static object * -checkerror(ctx, v) - context *ctx; + +/* Test a value used as condition, e.g., in a for or if statement */ + +static int +testbool(v) object *v; { - if (v == NULL) - puterrno(ctx); - return v; + if (is_intobject(v)) + return getintvalue(v) != 0; + if (is_floatobject(v)) + return getfloatvalue(v) != 0.0; + if (v->ob_type->tp_as_sequence != NULL) + return (*v->ob_type->tp_as_sequence->sq_length)(v) != 0; + if (v->ob_type->tp_as_mapping != NULL) + return (*v->ob_type->tp_as_mapping->mp_length)(v) != 0; + if (v == None) + return 0; + /* All other objects are 'true' */ + return 1; } static object * -add(ctx, v, w) - context *ctx; +add(v, w) object *v, *w; { if (v->ob_type->tp_as_number != NULL) @@ -343,27 +106,24 @@ add(ctx, v, w) else if (v->ob_type->tp_as_sequence != NULL) v = (*v->ob_type->tp_as_sequence->sq_concat)(v, w); else { - type_error(ctx, "+ not supported by operands"); + err_setstr(TypeError, "+ not supported by operands"); return NULL; } - return checkerror(ctx, v); + return v; } static object * -sub(ctx, v, w) - context *ctx; +sub(v, w) object *v, *w; { if (v->ob_type->tp_as_number != NULL) - return checkerror(ctx, - (*v->ob_type->tp_as_number->nb_subtract)(v, w)); - type_error(ctx, "bad operand type(s) for -"); + return (*v->ob_type->tp_as_number->nb_subtract)(v, w); + err_setstr(TypeError, "bad operand type(s) for -"); return NULL; } static object * -mul(ctx, v, w) - context *ctx; +mul(v, w) object *v, *w; { typeobject *tp; @@ -375,259 +135,234 @@ mul(ctx, v, w) } tp = v->ob_type; if (tp->tp_as_number != NULL) - return checkerror(ctx, (*tp->tp_as_number->nb_multiply)(v, w)); + return (*tp->tp_as_number->nb_multiply)(v, w); if (tp->tp_as_sequence != NULL) { if (!is_intobject(w)) { - type_error(ctx, "can't multiply sequence with non-int"); + err_setstr(TypeError, + "can't multiply sequence with non-int"); return NULL; } if (tp->tp_as_sequence->sq_repeat == NULL) { - type_error(ctx, "sequence does not support *"); + err_setstr(TypeError, "sequence does not support *"); return NULL; } - return checkerror(ctx, (*tp->tp_as_sequence->sq_repeat) - (v, (int)getintvalue(w))); + return (*tp->tp_as_sequence->sq_repeat) + (v, (int)getintvalue(w)); } - type_error(ctx, "bad operand type(s) for *"); + err_setstr(TypeError, "bad operand type(s) for *"); return NULL; } static object * -div(ctx, v, w) - context *ctx; +div(v, w) object *v, *w; { if (v->ob_type->tp_as_number != NULL) - return checkerror(ctx, - (*v->ob_type->tp_as_number->nb_divide)(v, w)); - type_error(ctx, "bad operand type(s) for /"); + return (*v->ob_type->tp_as_number->nb_divide)(v, w); + err_setstr(TypeError, "bad operand type(s) for /"); return NULL; } static object * -rem(ctx, v, w) - context *ctx; +rem(v, w) object *v, *w; { if (v->ob_type->tp_as_number != NULL) - return checkerror(ctx, - (*v->ob_type->tp_as_number->nb_remainder)(v, w)); - type_error(ctx, "bad operand type(s) for %"); + return (*v->ob_type->tp_as_number->nb_remainder)(v, w); + err_setstr(TypeError, "bad operand type(s) for %"); return NULL; } static object * -neg(ctx, v) - context *ctx; +neg(v) object *v; { if (v->ob_type->tp_as_number != NULL) - return checkerror(ctx, - (*v->ob_type->tp_as_number->nb_negative)(v)); - type_error(ctx, "bad operand type(s) for unary -"); + return (*v->ob_type->tp_as_number->nb_negative)(v); + err_setstr(TypeError, "bad operand type(s) for unary -"); return NULL; } static object * -pos(ctx, v) - context *ctx; +pos(v) object *v; { if (v->ob_type->tp_as_number != NULL) - return checkerror(ctx, - (*v->ob_type->tp_as_number->nb_positive)(v)); - type_error(ctx, "bad operand type(s) for unary +"); + return (*v->ob_type->tp_as_number->nb_positive)(v); + err_setstr(TypeError, "bad operand type(s) for unary +"); return NULL; } static object * -not(ctx, v) - context *ctx; +not(v) object *v; { - int outcome = testbool(ctx, v); - if (ctx->ctx_exception) - return NULL; - return checkerror(ctx, newintobject((long) !outcome)); + int outcome = testbool(v); + object *w = outcome == 0 ? True : False; + INCREF(w); + return w; } static object * -call_builtin(ctx, func, args) - context *ctx; +call_builtin(func, arg) object *func; - object *args; + object *arg; { - if (is_builtinobject(func)) { - function funcptr = getbuiltinfunction(func); - return (*funcptr)(ctx, args); - } if (is_methodobject(func)) { method meth = getmethod(func); object *self = getself(func); - return checkerror(ctx, (*meth)(self, args)); + return (*meth)(self, arg); } if (is_classobject(func)) { - if (args != NULL) { - type_error(ctx, "classobject() allows no arguments"); + if (arg != NULL) { + err_setstr(TypeError, + "classobject() allows no arguments"); return NULL; } - return checkerror(ctx, newclassmemberobject(func)); + return newclassmemberobject(func); } - type_error(ctx, "call of non-function"); + err_setstr(TypeError, "call of non-function"); return NULL; } -static object *eval_compiled PROTO((context *, codeobject *, object *, int)); - -/* XXX Eventually, this should not call eval_compiled recursively - but create a new frame */ - static object * -call_function(ctx, func, args) - context *ctx; +call_function(func, arg) object *func; - object *args; + object *arg; { - object *newargs = NULL; - object *savelocals, *newlocals, *saveglobals; - object *c, *v; + object *newarg = NULL; + object *newlocals, *newglobals; + object *co, *v; if (is_classmethodobject(func)) { object *self = classmethodgetself(func); func = classmethodgetfunc(func); - if (args == NULL) { - args = self; + if (arg == NULL) { + arg = self; } else { - newargs = checkerror(ctx, newtupleobject(2)); - if (newargs == NULL) + newarg = newtupleobject(2); + if (newarg == NULL) return NULL; INCREF(self); - INCREF(args); - settupleitem(newargs, 0, self); - settupleitem(newargs, 1, args); - args = newargs; + INCREF(arg); + settupleitem(newarg, 0, self); + settupleitem(newarg, 1, arg); + arg = newarg; } } else { if (!is_funcobject(func)) { - type_error(ctx, "call of non-function"); + err_setstr(TypeError, "call of non-function"); return NULL; } } - c = checkerror(ctx, getfunccode(func)); - if (c == NULL) { - XDECREF(newargs); + co = getfunccode(func); + if (co == NULL) { + XDECREF(newarg); return NULL; } - if (!is_codeobject(c)) { - printf("Bad code\n"); + if (!is_codeobject(co)) { + fprintf(stderr, "XXX Bad code\n"); abort(); } - newlocals = checkerror(ctx, newdictobject()); + newlocals = newdictobject(); if (newlocals == NULL) { - XDECREF(newargs); + XDECREF(newarg); return NULL; } - savelocals = ctx->ctx_locals; - ctx->ctx_locals = newlocals; - saveglobals = ctx->ctx_globals; - ctx->ctx_globals = getfuncglobals(func); + newglobals = getfuncglobals(func); + INCREF(newglobals); - v = eval_compiled(ctx, (codeobject *)c, args, 1); + v = eval_code((codeobject *)co, newglobals, newlocals, arg); - DECREF(ctx->ctx_locals); - ctx->ctx_locals = savelocals; - ctx->ctx_globals = saveglobals; + DECREF(newlocals); + DECREF(newglobals); - XDECREF(newargs); + XDECREF(newarg); return v; } static object * -apply_subscript(ctx, v, w) - context *ctx; +apply_subscript(v, w) object *v, *w; { typeobject *tp = v->ob_type; if (tp->tp_as_sequence == NULL && tp->tp_as_mapping == NULL) { - type_error(ctx, "unsubscriptable object"); + err_setstr(TypeError, "unsubscriptable object"); return NULL; } if (tp->tp_as_sequence != NULL) { int i; if (!is_intobject(w)) { - type_error(ctx, "sequence subscript not int"); + err_setstr(TypeError, "sequence subscript not int"); return NULL; } i = getintvalue(w); - return checkerror(ctx, (*tp->tp_as_sequence->sq_item)(v, i)); + return (*tp->tp_as_sequence->sq_item)(v, i); } - return checkerror(ctx, (*tp->tp_as_mapping->mp_subscript)(v, w)); + return (*tp->tp_as_mapping->mp_subscript)(v, w); } static object * -loop_subscript(ctx, v, w) - context *ctx; +loop_subscript(v, w) object *v, *w; { sequence_methods *sq = v->ob_type->tp_as_sequence; int i, n; if (sq == NULL) { - type_error(ctx, "loop over non-sequence"); + err_setstr(TypeError, "loop over non-sequence"); return NULL; } i = getintvalue(w); n = (*sq->sq_length)(v); if (i >= n) return NULL; /* End of loop */ - return checkerror(ctx, (*sq->sq_item)(v, i)); + return (*sq->sq_item)(v, i); } static int -slice_index(ctx, v, isize, pi) - context *ctx; +slice_index(v, isize, pi) object *v; int isize; int *pi; { if (v != NULL) { if (!is_intobject(v)) { - type_error(ctx, "slice index must be int"); - return 0; + err_setstr(TypeError, "slice index must be int"); + return -1; } *pi = getintvalue(v); if (*pi < 0) *pi += isize; } - return 1; + return 0; } static object * -apply_slice(ctx, u, v, w) /* u[v:w] */ - context *ctx; +apply_slice(u, v, w) /* return u[v:w] */ object *u, *v, *w; { typeobject *tp = u->ob_type; int ilow, ihigh, isize; if (tp->tp_as_sequence == NULL) { - type_error(ctx, "only sequences can be sliced"); + err_setstr(TypeError, "only sequences can be sliced"); return NULL; } ilow = 0; isize = ihigh = (*tp->tp_as_sequence->sq_length)(u); - if (!slice_index(ctx, v, isize, &ilow)) + if (slice_index(v, isize, &ilow) != 0) return NULL; - if (!slice_index(ctx, w, isize, &ihigh)) + if (slice_index(w, isize, &ihigh) != 0) return NULL; - return checkerror(ctx, (*tp->tp_as_sequence->sq_slice)(u, ilow, ihigh)); + return (*tp->tp_as_sequence->sq_slice)(u, ilow, ihigh); } -static void -assign_subscript(ctx, w, key, v) - context *ctx; + +static int +assign_subscript(w, key, v) /* w[key] = v */ object *w; object *key; object *v; @@ -636,47 +371,48 @@ assign_subscript(ctx, w, key, v) sequence_methods *sq; mapping_methods *mp; int (*func)(); - int err; if ((sq = tp->tp_as_sequence) != NULL && (func = sq->sq_ass_item) != NULL) { if (!is_intobject(key)) { - type_error(ctx, "sequence subscript must be integer"); - return; + err_setstr(TypeError, + "sequence subscript must be integer"); + return -1; } - err = (*func)(w, (int)getintvalue(key), v); + else + return (*func)(w, (int)getintvalue(key), v); } else if ((mp = tp->tp_as_mapping) != NULL && (func = mp->mp_ass_subscript) != NULL) { - err = (*func)(w, key, v); + return (*func)(w, key, v); } else { - type_error(ctx, "can't assign to this subscripted object"); - return; + err_setstr(TypeError, + "can't assign to this subscripted object"); + return -1; } - if (err != 0) - puterrno(ctx); } -static void -assign_slice(ctx, u, v, w, x) /* u[v:w] = x */ - context *ctx; +static int +assign_slice(u, v, w, x) /* u[v:w] = x */ object *u, *v, *w, *x; { - typeobject *tp = u->ob_type; + sequence_methods *sq = u->ob_type->tp_as_sequence; int ilow, ihigh, isize; - if (tp->tp_as_sequence == NULL || - tp->tp_as_sequence->sq_ass_slice == NULL) { - type_error(ctx, "unassignable slice"); - return; + if (sq == NULL) { + err_setstr(TypeError, "assign to slice of non-sequence"); + return -1; + } + if (sq == NULL || sq->sq_ass_slice == NULL) { + err_setstr(TypeError, "unassignable slice"); + return -1; } ilow = 0; - isize = ihigh = (*tp->tp_as_sequence->sq_length)(u); - if (!slice_index(ctx, v, isize, &ilow)) - return; - if (!slice_index(ctx, w, isize, &ihigh)) - return; - if ((*tp->tp_as_sequence->sq_ass_slice)(u, ilow, ihigh, x) != 0) - puterrno(ctx); + isize = ihigh = (*sq->sq_length)(u); + if (slice_index(v, isize, &ilow) != 0) + return -1; + if (slice_index(w, isize, &ihigh) != 0) + return -1; + return (*sq->sq_ass_slice)(u, ilow, ihigh, x); } static int @@ -695,9 +431,50 @@ cmp_exception(err, v) return err == v; } +static int +cmp_member(v, w) + object *v, *w; +{ + int i, n, cmp; + object *x; + sequence_methods *sq; + /* Special case for char in string */ + if (is_stringobject(w)) { + register char *s, *end; + register char c; + if (!is_stringobject(v) || getstringsize(v) != 1) { + err_setstr(TypeError, + "string member test needs char left operand"); + return -1; + } + c = getstringvalue(v)[0]; + s = getstringvalue(w); + end = s + getstringsize(w); + while (s < end) { + if (c == *s++) + return 1; + } + return 0; + } + sq = w->ob_type->tp_as_sequence; + if (sq == NULL) { + err_setstr(TypeError, + "'in' or 'not in' needs sequence right argument"); + return -1; + } + n = (*sq->sq_length)(w); + for (i = 0; i < n; i++) { + x = (*sq->sq_item)(w, i); + cmp = cmpobject(v, x); + XDECREF(x); + if (cmp == 0) + return 1; + } + return 0; +} + static object * -cmp_outcome(ctx, op, v, w) - register context *ctx; +cmp_outcome(op, v, w) enum cmp_op op; register object *v; register object *w; @@ -705,44 +482,43 @@ cmp_outcome(ctx, op, v, w) register int cmp; register int res = 0; switch (op) { - case IN: - case NOT_IN: - cmp = cmp_member(ctx, v, w); - break; case IS: case IS_NOT: - cmp = (v == w); + res = (v == w); + if (op == IS_NOT) + res = !res; + break; + case IN: + case NOT_IN: + res = cmp_member(v, w); + if (res < 0) + return NULL; + if (op == NOT_IN) + res = !res; break; case EXC_MATCH: - cmp = cmp_exception(v, w); + res = cmp_exception(v, w); break; default: - cmp = cmp_values(ctx, v, w); - } - if (ctx->ctx_exception) - return NULL; - switch (op) { - case EXC_MATCH: - case IS: - case IN: res = cmp; break; - case IS_NOT: - case NOT_IN: res = !cmp; break; - case LT: res = cmp < 0; break; - case LE: res = cmp <= 0; break; - case EQ: res = cmp == 0; break; - case NE: res = cmp != 0; break; - case GT: res = cmp > 0; break; - case GE: res = cmp >= 0; break; - /* XXX no default? */ + cmp = cmpobject(v, w); + switch (op) { + case LT: res = cmp < 0; break; + case LE: res = cmp <= 0; break; + case EQ: res = cmp == 0; break; + case NE: res = cmp != 0; break; + case GT: res = cmp > 0; break; + case GE: res = cmp >= 0; break; + /* XXX no default? (res is initialized to 0 though) */ + } } v = res ? True : False; INCREF(v); return v; } -static void -import_from(ctx, v, name) - context *ctx; +static int +import_from(locals, v, name) + object *locals; object *v; char *name; { @@ -758,27 +534,27 @@ import_from(ctx, v, name) x = dictlookup(w, name); if (x == NULL) { /* XXX can't happen? */ - name_error(ctx, name); - break; - } - if (dictinsert(ctx->ctx_locals, name, x) != 0) { - puterrno(ctx); - break; + err_setstr(NameError, name); + return -1; } + if (dictinsert(locals, name, x) != 0) + return -1; } + return 0; } else { x = dictlookup(w, name); - if (x == NULL) - name_error(ctx, name); - else if (dictinsert(ctx->ctx_locals, name, x) != 0) - puterrno(ctx); + if (x == NULL) { + err_setstr(NameError, name); + return -1; + } + else + return dictinsert(locals, name, x); } } static object * -build_class(ctx, v, w) - context *ctx; +build_class(v, w) object *v; /* None or tuple containing base classes */ object *w; /* dictionary */ { @@ -787,7 +563,8 @@ build_class(ctx, v, w) for (i = gettuplesize(v); --i >= 0; ) { object *x = gettupleitem(v, i); if (!is_classobject(x)) { - type_error(ctx, "base is not a class object"); + err_setstr(TypeError, + "base is not a class object"); return NULL; } } @@ -796,85 +573,152 @@ build_class(ctx, v, w) v = NULL; } if (!is_dictobject(w)) { - sys_error(ctx, "build_class with non-dictionary"); + err_setstr(SystemError, "build_class with non-dictionary"); return NULL; } - return checkerror(ctx, newclassobject(v, w)); + return newclassobject(v, w); } -static object * -eval_compiled(ctx, co, arg, needvalue) - context *ctx; + +/* 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 */ +}; + +/* Interpreter main loop */ + +object * +eval_code(co, globals, locals, arg) codeobject *co; + object *globals; + object *locals; object *arg; - int needvalue; { - frameobject *f; - register object *v; + register unsigned char *next_instr; + register int opcode; /* Current opcode */ + register int oparg; /* Current opcode argument, if any */ + register object **stack_pointer; + register enum why_code why; /* Reason for block stack unwind */ + register int err; /* Error status -- nonzero if error */ + register object *x; /* Result object -- NULL if error */ + register object *v; /* Temporary objects popped off stack */ register object *w; register object *u; - register object *x; - char *name; - int i, op; - FILE *fp; -#ifndef NDEBUG - int trace = dictlookup(ctx->ctx_globals, "__trace") != NULL; + register object *t; + register frameobject *f; /* Current frame */ + int lineno; /* Current line number */ + object *retval; /* Return value iff why == WHY_RETURN */ + char *name; /* Name used by some instructions */ + FILE *fp; /* Used by print operations */ +#ifdef TRACE + int trace = dictlookup(globals, "__trace__") != NULL; #endif - f = newframeobject( - (frameobject *)NULL, /*back*/ - co, /*code*/ - ctx->ctx_locals, /*locals*/ - ctx->ctx_globals, /*globals*/ - 50, /*nvalues*/ - 20); /*nblocks*/ - if (f == NULL) { - puterrno(ctx); - return NULL; - } +/* Code access macros */ -#define EMPTY() Empty(f) -#define FULL() Full(f) #define GETCONST(i) Getconst(f, i) #define GETNAME(i) Getname(f, i) -#define JUMPTO(x) Jumpto(f, x) -#define JUMPBY(x) Jumpby(f, x) - -#ifdef NDEBUG - -#define PUSH(v) Push(f, v) -#define TOP() Top(f) -#define POP() Pop(f) - +#define FIRST_INSTR() (GETUSTRINGVALUE(f->f_code->co_code)) +#define INSTR_OFFSET() (next_instr - FIRST_INSTR()) +#define NEXTOP() (*next_instr++) +#define NEXTARG() (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2]) +#define JUMPTO(x) (next_instr = FIRST_INSTR() + (x)) +#define JUMPBY(x) (next_instr += (x)) + +/* Stack manipulation macros */ + +#define STACK_LEVEL() (stack_pointer - f->f_valuestack) +#define EMPTY() (STACK_LEVEL() == 0) +#define TOP() (stack_pointer[-1]) +#define BASIC_PUSH(v) (*stack_pointer++ = (v)) +#define BASIC_POP() (*--stack_pointer) + +#ifdef TRACE +#define PUSH(v) (BASIC_PUSH(v), trace && prtrace(TOP(), "push")) +#define POP() (trace && prtrace(TOP(), "pop"), BASIC_POP()) #else - -#define PUSH(v) if(trace) trace_push(f, v); else push(f, v) -#define TOP() (trace ? trace_top(f) : top(f)) -#define POP() (trace ? trace_pop(f) : pop(f)) - +#define PUSH(v) BASIC_PUSH(v) +#define POP() BASIC_POP() #endif + f = newframeobject( + current_frame, /*back*/ + co, /*code*/ + globals, /*globals*/ + locals, /*locals*/ + 50, /*nvalues*/ + 20); /*nblocks*/ + if (f == NULL) + return NULL; + + current_frame = f; + + next_instr = GETUSTRINGVALUE(f->f_code->co_code); + + stack_pointer = f->f_valuestack; + if (arg != NULL) { INCREF(arg); PUSH(arg); } - while (f->f_nexti < getstringsize((object *)f->f_code->co_code) && - !ctx->ctx_exception) { -#ifdef NDEBUG - op = Nextbyte(f); -#else - op = trace ? trace_nextop(f) : nextbyte(f); + why = WHY_NOT; + err = 0; + x = None; /* Not a reference, just anything non-NULL */ + lineno = -1; + + for (;;) { + static ticker; + + /* Do periodic things */ + + if (--ticker < 0) { + ticker = 100; + if (intrcheck()) { + err_set(KeyboardInterrupt); + why = WHY_EXCEPTION; + tb_here(f, INSTR_OFFSET(), lineno); + break; + } + } + + /* Extract opcode and argument */ + + opcode = NEXTOP(); + if (HAS_ARG(opcode)) + oparg = NEXTARG(); + +#ifdef TRACE + /* Instruction tracing */ + + if (trace) { + if (HAS_ARG(opcode)) { + printf("%d: %d, %d\n", + (int) (INSTR_OFFSET() - 3), + opcode, oparg); + } + else { + printf("%d: %d\n", + (int) (INSTR_OFFSET() - 1), opcode); + } + } #endif - if (op >= HAVE_ARGUMENT) - i = nextint(f); - switch (op) { + + /* Main switch on opcode */ - case DUP_TOP: - v = TOP(); - INCREF(v); - PUSH(v); - break; + switch (opcode) { + + /* BEWARE! + It is essential that any operation that fails sets either + x to NULL, err to nonzero, or why to anything but WHY_NOT, + and that no operation that succeeds does this! */ + + /* case STOP_CODE: this is an error! */ case POP_TOP: v = POP(); @@ -897,125 +741,130 @@ eval_compiled(ctx, co, arg, needvalue) PUSH(w); break; + case DUP_TOP: + v = TOP(); + INCREF(v); + PUSH(v); + break; + case UNARY_POSITIVE: v = POP(); - u = pos(ctx, v); + x = pos(v); DECREF(v); - PUSH(u); + PUSH(x); break; case UNARY_NEGATIVE: v = POP(); - u = neg(ctx, v); + x = neg(v); DECREF(v); - PUSH(u); + PUSH(x); break; case UNARY_NOT: v = POP(); - u = not(ctx, v); + x = not(v); DECREF(v); - PUSH(u); + PUSH(x); break; case UNARY_CONVERT: v = POP(); - u = checkerror(ctx, reprobject(v)); + x = reprobject(v); DECREF(v); - PUSH(u); + PUSH(x); break; case UNARY_CALL: v = POP(); if (is_classmethodobject(v) || is_funcobject(v)) - u = call_function(ctx, v, (object *)NULL); + x = call_function(v, (object *)NULL); else - u = call_builtin(ctx, v, (object *)NULL); + x = call_builtin(v, (object *)NULL); DECREF(v); - PUSH(u); + PUSH(x); break; case BINARY_MULTIPLY: w = POP(); v = POP(); - u = mul(ctx, v, w); + x = mul(v, w); DECREF(v); DECREF(w); - PUSH(u); + PUSH(x); break; case BINARY_DIVIDE: w = POP(); v = POP(); - u = div(ctx, v, w); + x = div(v, w); DECREF(v); DECREF(w); - PUSH(u); + PUSH(x); break; case BINARY_MODULO: w = POP(); v = POP(); - u = rem(ctx, v, w); + x = rem(v, w); DECREF(v); DECREF(w); - PUSH(u); + PUSH(x); break; case BINARY_ADD: w = POP(); v = POP(); - u = add(ctx, v, w); + x = add(v, w); DECREF(v); DECREF(w); - PUSH(u); + PUSH(x); break; case BINARY_SUBTRACT: w = POP(); v = POP(); - u = sub(ctx, v, w); + x = sub(v, w); DECREF(v); DECREF(w); - PUSH(u); + PUSH(x); break; case BINARY_SUBSCR: w = POP(); v = POP(); - u = apply_subscript(ctx, v, w); + x = apply_subscript(v, w); DECREF(v); DECREF(w); - PUSH(u); + PUSH(x); break; case BINARY_CALL: w = POP(); v = POP(); if (is_classmethodobject(v) || is_funcobject(v)) - u = call_function(ctx, v, w); + x = call_function(v, w); else - u = call_builtin(ctx, v, w); + x = call_builtin(v, w); DECREF(v); DECREF(w); - PUSH(u); + PUSH(x); break; case SLICE+0: case SLICE+1: case SLICE+2: case SLICE+3: - op -= SLICE; - if (op & 2) + if ((opcode-SLICE) & 2) w = POP(); else w = NULL; - if (op & 1) + if ((opcode-SLICE) & 1) v = POP(); else v = NULL; u = POP(); - x = apply_slice(ctx, u, v, w); + x = apply_slice(u, v, w); DECREF(u); XDECREF(v); XDECREF(w); @@ -1026,19 +875,18 @@ eval_compiled(ctx, co, arg, needvalue) case STORE_SLICE+1: case STORE_SLICE+2: case STORE_SLICE+3: - op -= SLICE; - if (op & 2) + if ((opcode-STORE_SLICE) & 2) w = POP(); else w = NULL; - if (op & 1) + if ((opcode-STORE_SLICE) & 1) v = POP(); else v = NULL; u = POP(); - x = POP(); - assign_slice(ctx, u, v, w, x); /* u[v:w] = x */ - DECREF(x); + t = POP(); + err = assign_slice(u, v, w, t); /* u[v:w] = t */ + DECREF(t); DECREF(u); XDECREF(v); XDECREF(w); @@ -1048,18 +896,17 @@ eval_compiled(ctx, co, arg, needvalue) case DELETE_SLICE+1: case DELETE_SLICE+2: case DELETE_SLICE+3: - op -= SLICE; - if (op & 2) + if ((opcode-DELETE_SLICE) & 2) w = POP(); else w = NULL; - if (op & 1) + if ((opcode-DELETE_SLICE) & 1) v = POP(); else v = NULL; u = POP(); - x = NULL; - assign_slice(ctx, u, v, w, x); /* del u[v:w] */ + err = assign_slice(u, v, w, (object *)NULL); + /* del u[v:w] */ DECREF(u); XDECREF(v); XDECREF(w); @@ -1070,7 +917,7 @@ eval_compiled(ctx, co, arg, needvalue) v = POP(); u = POP(); /* v[w] = u */ - assign_subscript(ctx, v, w, u); + err = assign_subscript(v, w, u); DECREF(u); DECREF(v); DECREF(w); @@ -1080,7 +927,7 @@ eval_compiled(ctx, co, arg, needvalue) w = POP(); v = POP(); /* del v[w] */ - assign_subscript(ctx, v, w, (object *)NULL); + err = assign_subscript(v, w, (object *)NULL); DECREF(v); DECREF(w); break; @@ -1125,113 +972,126 @@ eval_compiled(ctx, co, arg, needvalue) break; case BREAK_LOOP: - raise_pseudo(ctx, BREAK_PSEUDO); + why = WHY_BREAK; break; case RAISE_EXCEPTION: v = POP(); w = POP(); - if (!is_stringobject(w)) { - DECREF(v); - DECREF(v); - type_error(ctx, "exceptions must be strings"); - } - else { - raise_exception(ctx, w, v); - } + if (!is_stringobject(w)) + err_setstr(TypeError, + "exceptions must be strings"); + else + err_setval(w, v); + DECREF(v); + DECREF(w); + why = WHY_EXCEPTION; break; case LOAD_LOCALS: - v = ctx->ctx_locals; + v = f->f_locals; INCREF(v); PUSH(v); break; case RETURN_VALUE: - v = POP(); - raise_pseudo(ctx, RETURN_PSEUDO); - ctx->ctx_errval = v; + retval = POP(); + why = WHY_RETURN; break; case REQUIRE_ARGS: - if (EMPTY()) - type_error(ctx, + if (EMPTY()) { + err_setstr(TypeError, "function expects argument(s)"); + why = WHY_EXCEPTION; + } break; case REFUSE_ARGS: - if (!EMPTY()) - type_error(ctx, + if (!EMPTY()) { + err_setstr(TypeError, "function expects no argument(s)"); + why = WHY_EXCEPTION; + } break; case BUILD_FUNCTION: v = POP(); - x = checkerror(ctx, newfuncobject(v, ctx->ctx_globals)); + x = newfuncobject(v, f->f_globals); DECREF(v); PUSH(x); break; case POP_BLOCK: - (void) pop_block(f); + { + block *b = pop_block(f); + while (STACK_LEVEL() > b->b_level) { + v = POP(); + DECREF(v); + } + } break; case END_FINALLY: v = POP(); - w = POP(); if (is_intobject(v)) { - raise_pseudo(ctx, (int)getintvalue(v)); - DECREF(v); - if (w == None) - DECREF(w); - else - ctx->ctx_errval = w; + why = (enum why_code) getintvalue(v); + if (why == WHY_RETURN) + retval = POP(); } - else if (is_stringobject(v)) - raise_exception(ctx, v, w); - else if (v == None) { - DECREF(v); + else if (is_stringobject(v)) { + w = POP(); + err_setval(v, w); + DECREF(w); + w = POP(); + tb_store(w); DECREF(w); + why = WHY_RERAISE; } - else { - sys_error(ctx, "'finally' pops bad exception"); + else if (v != None) { + err_setstr(SystemError, + "'finally' pops bad exception"); + why = WHY_EXCEPTION; } + DECREF(v); break; case BUILD_CLASS: w = POP(); v = POP(); - x = build_class(ctx, v, w); + x = build_class(v, w); PUSH(x); DECREF(v); DECREF(w); break; case STORE_NAME: - name = GETNAME(i); + name = GETNAME(oparg); v = POP(); - if (dictinsert(ctx->ctx_locals, name, v) != 0) - mem_error(ctx, "insert in symbol table"); + err = dictinsert(f->f_locals, name, v); DECREF(v); break; case DELETE_NAME: - name = GETNAME(i); - if (dictremove(ctx->ctx_locals, name) != 0) - name_error(ctx, name); + name = GETNAME(oparg); + if ((err = dictremove(f->f_locals, name)) != 0) + err_setstr(NameError, name); break; case UNPACK_TUPLE: v = POP(); if (!is_tupleobject(v)) { - type_error(ctx, "unpack non-tuple"); + err_setstr(TypeError, "unpack non-tuple"); + why = WHY_EXCEPTION; } - else if (gettuplesize(v) != i) { - error(ctx, "unpack tuple of wrong size"); + else if (gettuplesize(v) != oparg) { + err_setstr(RuntimeError, + "unpack tuple of wrong size"); + why = WHY_EXCEPTION; } else { - for (; --i >= 0; ) { - w = gettupleitem(v, i); + for (; --oparg >= 0; ) { + w = gettupleitem(v, oparg); INCREF(w); PUSH(w); } @@ -1242,14 +1102,17 @@ eval_compiled(ctx, co, arg, needvalue) case UNPACK_LIST: v = POP(); if (!is_listobject(v)) { - type_error(ctx, "unpack non-list"); + err_setstr(TypeError, "unpack non-list"); + why = WHY_EXCEPTION; } - else if (getlistsize(v) != i) { - error(ctx, "unpack tuple of wrong size"); + else if (getlistsize(v) != oparg) { + err_setstr(RuntimeError, + "unpack list of wrong size"); + why = WHY_EXCEPTION; } else { - for (; --i >= 0; ) { - w = getlistitem(v, i); + for (; --oparg >= 0; ) { + w = getlistitem(v, oparg); INCREF(w); PUSH(w); } @@ -1258,144 +1121,120 @@ eval_compiled(ctx, co, arg, needvalue) break; case STORE_ATTR: - name = GETNAME(i); + name = GETNAME(oparg); v = POP(); u = POP(); - /* v.name = u */ - if (v->ob_type->tp_setattr == NULL) { - type_error(ctx, "object without writable attributes"); - } - else { - if ((*v->ob_type->tp_setattr)(v, name, u) != 0) - puterrno(ctx); - } + err = setattr(v, name, u); /* v.name = u */ DECREF(v); DECREF(u); break; case DELETE_ATTR: - name = GETNAME(i); + name = GETNAME(oparg); v = POP(); - /* del v.name */ - if (v->ob_type->tp_setattr == NULL) { - type_error(ctx, - "object without writable attributes"); - } - else { - if ((*v->ob_type->tp_setattr) - (v, name, (object *)NULL) != 0) - puterrno(ctx); - } + err = setattr(v, name, (object *)NULL); + /* del v.name */ DECREF(v); break; case LOAD_CONST: - v = GETCONST(i); - INCREF(v); - PUSH(v); + x = GETCONST(oparg); + INCREF(x); + PUSH(x); break; case LOAD_NAME: - name = GETNAME(i); - v = dictlookup(ctx->ctx_locals, name); - if (v == NULL) { - v = dictlookup(ctx->ctx_globals, name); - if (v == NULL) - v = dictlookup(ctx->ctx_builtins, name); + name = GETNAME(oparg); + x = dictlookup(f->f_locals, name); + if (x == NULL) { + x = dictlookup(f->f_globals, name); + if (x == NULL) + x = getbuiltin(name); } - if (v == NULL) - name_error(ctx, name); - /* XXX could optimize */ + if (x == NULL) + err_setstr(NameError, name); else - INCREF(v); - PUSH(v); + INCREF(x); + PUSH(x); break; case BUILD_TUPLE: - v = checkerror(ctx, newtupleobject(i)); - if (v != NULL) { - for (; --i >= 0;) { + x = newtupleobject(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { w = POP(); - settupleitem(v, i, w); + err = settupleitem(x, oparg, w); + if (err != 0) + break; } + PUSH(x); } - PUSH(v); break; case BUILD_LIST: - v = checkerror(ctx, newlistobject(i)); - if (v != NULL) { - for (; --i >= 0;) { + x = newlistobject(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { w = POP(); - setlistitem(v, i, w); + err = setlistitem(x, oparg, w); + if (err != 0) + break; } + PUSH(x); } - PUSH(v); break; case BUILD_MAP: - v = checkerror(ctx, newdictobject()); - PUSH(v); + x = newdictobject(); + PUSH(x); break; case LOAD_ATTR: - name = GETNAME(i); + name = GETNAME(oparg); v = POP(); - if (v->ob_type->tp_getattr == NULL) { - type_error(ctx, "attribute-less object"); - u = NULL; - } - else { - u = checkerror(ctx, - (*v->ob_type->tp_getattr)(v, name)); - } + x = getattr(v, name); DECREF(v); - PUSH(u); + PUSH(x); break; case COMPARE_OP: w = POP(); v = POP(); - u = cmp_outcome(ctx, (enum cmp_op)i, v, w); + x = cmp_outcome((enum cmp_op)oparg, v, w); DECREF(v); DECREF(w); - PUSH(u); + PUSH(x); break; case IMPORT_NAME: - name = GETNAME(i); - u = import_module(ctx, name); - if (u != NULL) { - INCREF(u); - PUSH(u); - } + name = GETNAME(oparg); + x = import_module(name); + XINCREF(x); + PUSH(x); break; case IMPORT_FROM: - name = GETNAME(i); + name = GETNAME(oparg); v = TOP(); - import_from(ctx, v, name); + err = import_from(f->f_locals, v, name); break; case JUMP_FORWARD: - JUMPBY(i); + JUMPBY(oparg); break; case JUMP_IF_FALSE: - if (!testbool(ctx, TOP())) - JUMPBY(i); + if (!testbool(TOP())) + JUMPBY(oparg); break; case JUMP_IF_TRUE: - if (testbool(ctx, TOP())) - JUMPBY(i); + if (testbool(TOP())) + JUMPBY(oparg); break; case JUMP_ABSOLUTE: - JUMPTO(i); - /* XXX Should check for interrupts more often? */ - if (intrcheck()) - intr_error(ctx); + JUMPTO(oparg); break; case FOR_LOOP: @@ -1406,157 +1245,168 @@ eval_compiled(ctx, co, arg, needvalue) s, i are popped, and we jump */ w = POP(); /* Loop index */ v = POP(); /* Sequence object */ - x = loop_subscript(ctx, v, w); - if (x != NULL) { + u = loop_subscript(v, w); + if (u != NULL) { PUSH(v); - u = checkerror(ctx, - newintobject(getintvalue(w)+1)); - PUSH(u); - DECREF(w); + x = newintobject(getintvalue(w)+1); PUSH(x); + DECREF(w); + PUSH(u); } else { DECREF(v); DECREF(w); - JUMPBY(i); + /* A NULL can mean "s exhausted" + but also an error: */ + if (err_occurred()) + why = WHY_EXCEPTION; + else + JUMPBY(oparg); } break; case SETUP_LOOP: - setup_block(f, SETUP_LOOP, i); - break; - case SETUP_EXCEPT: - setup_block(f, SETUP_EXCEPT, i); + case SETUP_FINALLY: + setup_block(f, opcode, INSTR_OFFSET() + oparg, + STACK_LEVEL()); break; - case SETUP_FINALLY: - setup_block(f, SETUP_FINALLY, i); + case SET_LINENO: +#ifdef TRACE + if (trace) + printf("--- Line %d ---\n", oparg); +#endif + lineno = oparg; break; default: - printf("opcode %d\n", op); - sys_error(ctx, "eval_compiled: unknown opcode"); + fprintf(stderr, + "XXX lineno: %d, opcode: %d\n", + lineno, opcode); + err_setstr(SystemError, "eval_code: unknown opcode"); + why = WHY_EXCEPTION; break; + } /* switch */ + + + /* Quickly continue if no error occurred */ + + if (why == WHY_NOT) { + if (err == 0 && x != NULL) + continue; /* Normal, fast path */ + why = WHY_EXCEPTION; + x = None; + err = 0; } + +#ifndef NDEBUG + /* Double-check exception status */ - /* Unwind block stack if an exception occurred */ + if (why == WHY_EXCEPTION || why == WHY_RERAISE) { + if (!err_occurred()) { + fprintf(stderr, "XXX ghost error\n"); + err_setstr(SystemError, "ghost error"); + why = WHY_EXCEPTION; + } + } + else { + if (err_occurred()) { + fprintf(stderr, "XXX undetected error\n"); + why = WHY_EXCEPTION; + } + } +#endif + + /* Log traceback info if this is a real exception */ + + if (why == WHY_EXCEPTION) { + int lasti = INSTR_OFFSET() - 1; + if (HAS_ARG(opcode)) + lasti -= 2; + tb_here(f, lasti, lineno); + } + + /* For the rest, treat WHY_RERAISE as WHY_EXCEPTION */ - while (ctx->ctx_exception && f->f_iblock > 0) { + if (why == WHY_RERAISE) + why = WHY_EXCEPTION; + + /* Unwind stacks if a (pseudo) exception occurred */ + + while (why != WHY_NOT && f->f_iblock > 0) { block *b = pop_block(f); - if (b->b_type == SETUP_LOOP && - ctx->ctx_exception == BREAK_PSEUDO) { - clear_exception(ctx); + while (STACK_LEVEL() > b->b_level) { + v = POP(); + XDECREF(v); + } + if (b->b_type == SETUP_LOOP && why == WHY_BREAK) { + why = WHY_NOT; JUMPTO(b->b_handler); break; } - else if (b->b_type == SETUP_FINALLY || - b->b_type == SETUP_EXCEPT && - ctx->ctx_exception == CATCHABLE_EXCEPTION) { - v = ctx->ctx_errval; - if (v == NULL) - v = None; - INCREF(v); - PUSH(v); - v = ctx->ctx_error; - if (v == NULL) - v = newintobject(ctx->ctx_exception); - else - INCREF(v); - PUSH(v); - clear_exception(ctx); + if (b->b_type == SETUP_FINALLY || + b->b_type == SETUP_EXCEPT && + why == WHY_EXCEPTION) { + if (why == WHY_EXCEPTION) { + object *exc, *val; + err_get(&exc, &val); + if (val == NULL) { + val = None; + INCREF(val); + } + v = tb_fetch(); + /* Make the raw exception data + available to the handler, + so a program can emulate the + Python main loop. Don't do + this for 'finally'. */ + if (b->b_type == SETUP_EXCEPT) { +#if 0 /* Oops, this breaks too many things */ + sysset("exc_traceback", v); +#endif + sysset("exc_value", val); + sysset("exc_type", exc); + err_clear(); + } + PUSH(v); + PUSH(val); + PUSH(exc); + } + else { + if (why == WHY_RETURN) + PUSH(retval); + v = newintobject((long)why); + PUSH(v); + } + why = WHY_NOT; JUMPTO(b->b_handler); break; } - } - } + } /* unwind stack */ + + /* End the loop if we still have an error (or return) */ + + if (why != WHY_NOT) + break; + + } /* main loop */ - if (ctx->ctx_exception) { - while (!EMPTY()) { - v = POP(); - XDECREF(v); - } - v = NULL; - if (ctx->ctx_exception == RETURN_PSEUDO) { - if (needvalue) { - v = ctx->ctx_errval; - INCREF(v); - clear_exception(ctx); - } - else { - /* XXX Can detect this statically! */ - type_error(ctx, "unexpected return statement"); - } - } - } - else { - if (needvalue) - v = POP(); - else - v = NULL; - if (!EMPTY()) { - sys_error(ctx, "stack not cleaned up"); - XDECREF(v); - while (!EMPTY()) { - v = POP(); - XDECREF(v); - } - v = NULL; - } + /* Pop remaining stack entries */ + + while (!EMPTY()) { + v = POP(); + XDECREF(v); } - -#undef EMPTY -#undef FULL -#undef GETCONST -#undef GETNAME -#undef JUMPTO -#undef JUMPBY - -#undef POP -#undef TOP -#undef PUSH + /* Restore previous frame and release the current one */ + + current_frame = f->f_back; DECREF(f); - return v; - -} - -/* Provisional interface until everything is compilable */ - -#include "node.h" - -static object * -eval_or_exec(ctx, n, arg, needvalue) - context *ctx; - node *n; - object *arg; - int needvalue; -{ - object *v; - codeobject *co = compile(n); - freenode(n); /* XXX A rather strange place to do this! */ - if (co == NULL) { - puterrno(ctx); + + if (why == WHY_RETURN) + return retval; + else return NULL; - } - v = eval_compiled(ctx, co, arg, needvalue); - DECREF(co); - return v; -} - -object * -eval_node(ctx, n) - context *ctx; - node *n; -{ - return eval_or_exec(ctx, n, (object *)NULL, 1/*needvalue*/); -} - -void -exec_node(ctx, n) - context *ctx; - node *n; -{ - (void) eval_or_exec(ctx, n, (object *)NULL, 0/*needvalue*/); } diff --git a/Python/compile.c b/Python/compile.c index 2f5fd69..87acf39 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1,31 +1,49 @@ /* Compile an expression node to intermediate code */ -#include <stdio.h> -#include <ctype.h> -#include "string.h" - -#include "PROTO.h" -#include "object.h" -#include "objimpl.h" -#include "intobject.h" -#include "floatobject.h" -#include "stringobject.h" -#include "listobject.h" +/* XXX TO DO: + XXX Compute maximum needed stack sizes while compiling + XXX Generate simple jump for break/return outside 'try...finally' + XXX Include function name in code (and module names?) +*/ + +#include "allobjects.h" + #include "node.h" #include "token.h" #include "graminit.h" -#include "errors.h" #include "compile.h" #include "opcode.h" +#include "structmember.h" + +#include <ctype.h> + +#define OFF(x) offsetof(codeobject, x) + +static struct memberlist code_memberlist[] = { + {"co_code", T_OBJECT, OFF(co_code)}, + {"co_consts", T_OBJECT, OFF(co_consts)}, + {"co_names", T_OBJECT, OFF(co_names)}, + {"co_filename", T_OBJECT, OFF(co_filename)}, + {NULL} /* Sentinel */ +}; + +static object * +code_getattr(co, name) + codeobject *co; + char *name; +{ + return getmember((char *)co, code_memberlist, name); +} static void -code_dealloc(c) - codeobject *c; +code_dealloc(co) + codeobject *co; { - XDECREF(c->co_code); - XDECREF(c->co_consts); - XDECREF(c->co_names); - DEL(c); + XDECREF(co->co_code); + XDECREF(co->co_consts); + XDECREF(co->co_names); + XDECREF(co->co_filename); + DEL(co); } typeobject Codetype = { @@ -36,7 +54,7 @@ typeobject Codetype = { 0, code_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ - 0, /*tp_getattr*/ + code_getattr, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ @@ -45,13 +63,14 @@ typeobject Codetype = { 0, /*tp_as_mapping*/ }; -static codeobject *newcodeobject PROTO((object *, object *, object *)); +static codeobject *newcodeobject PROTO((object *, object *, object *, char *)); static codeobject * -newcodeobject(code, consts, names) +newcodeobject(code, consts, names, filename) object *code; object *consts; object *names; + char *filename; { codeobject *co; int i; @@ -78,6 +97,10 @@ newcodeobject(code, consts, names) co->co_consts = consts; INCREF(names); co->co_names = names; + if ((co->co_filename = newstringobject(filename)) == NULL) { + DECREF(co); + co = NULL; + } } return co; } @@ -90,10 +113,13 @@ struct compiling { object *c_names; /* list of strings (names) */ int c_nexti; /* index into c_code */ int c_errors; /* counts errors occurred */ + int c_infunction; /* set when compiling a function */ + int c_loops; /* counts nested loops */ + char *c_filename; /* filename of current node */ }; /* Prototypes */ -static int com_init PROTO((struct compiling *)); +static int com_init PROTO((struct compiling *, char *)); static void com_free PROTO((struct compiling *)); static void com_done PROTO((struct compiling *)); static void com_node PROTO((struct compiling *, struct _node *)); @@ -108,8 +134,9 @@ static int com_addname PROTO((struct compiling *, object *)); static void com_addopname PROTO((struct compiling *, int, node *)); static int -com_init(c) +com_init(c, filename) struct compiling *c; + char *filename; { if ((c->c_code = newsizedstringobject((char *)NULL, 0)) == NULL) goto fail_3; @@ -119,6 +146,9 @@ com_init(c) goto fail_1; c->c_nexti = 0; c->c_errors = 0; + c->c_infunction = 0; + c->c_loops = 0; + c->c_filename = filename; return 1; fail_1: @@ -153,6 +183,8 @@ com_addbyte(c, byte) { int len; if (byte < 0 || byte > 255) { + fprintf(stderr, "XXX compiling bad byte: %d\n", byte); + abort(); err_setstr(SystemError, "com_addbyte: byte out of range"); c->c_errors++; } @@ -1076,6 +1108,10 @@ com_return_stmt(c, n) node *n; { REQ(n, return_stmt); /* 'return' [testlist] NEWLINE */ + if (!c->c_infunction) { + err_setstr(TypeError, "'return' outside function"); + c->c_errors++; + } if (NCH(n) == 2) com_addoparg(c, LOAD_CONST, com_addconst(c, None)); else @@ -1134,6 +1170,9 @@ com_if_stmt(c, n) /*'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] */ for (i = 0; i+3 < NCH(n); i+=4) { int a = 0; + node *ch = CHILD(n, i+1); + if (i > 0) + com_addoparg(c, SET_LINENO, ch->n_lineno); com_node(c, CHILD(n, i+1)); com_addfwref(c, JUMP_IF_FALSE, &a); com_addbyte(c, POP_TOP); @@ -1158,10 +1197,13 @@ com_while_stmt(c, n) REQ(n, while_stmt); /* 'while' test ':' suite ['else' ':' suite] */ com_addfwref(c, SETUP_LOOP, &break_anchor); begin = c->c_nexti; + com_addoparg(c, SET_LINENO, n->n_lineno); com_node(c, CHILD(n, 1)); com_addfwref(c, JUMP_IF_FALSE, &anchor); com_addbyte(c, POP_TOP); + c->c_loops++; com_node(c, CHILD(n, 3)); + c->c_loops--; com_addoparg(c, JUMP_ABSOLUTE, begin); com_backpatch(c, anchor); com_addbyte(c, POP_TOP); @@ -1190,9 +1232,12 @@ com_for_stmt(c, n) com_addoparg(c, LOAD_CONST, com_addconst(c, v)); XDECREF(v); begin = c->c_nexti; + com_addoparg(c, SET_LINENO, n->n_lineno); com_addfwref(c, FOR_LOOP, &anchor); com_assign(c, CHILD(n, 1), 1/*assigning*/); + c->c_loops++; com_node(c, CHILD(n, 5)); + c->c_loops--; com_addoparg(c, JUMP_ABSOLUTE, begin); com_backpatch(c, anchor); com_addbyte(c, POP_BLOCK); @@ -1225,7 +1270,6 @@ com_for_stmt(c, n) <code for S> POP_BLOCK LOAD_CONST <nil> - LOAD_CONST <nil> L: <code for Sf> END_FINALLY @@ -1242,13 +1286,9 @@ com_for_stmt(c, n) stack until its level is the same as indicated on the block stack. (The label is ignored.) END_FINALLY: - Pops two entries from the *value* stack and re-raises - the exception they specify. If the top entry is nil, - no exception is raised. If it is a number, a pseudo - exception is raised ('return' or 'break'). Otherwise, - a real exception (specified by a string) is raised. - The second entry popped from the is the value that goes - with the exception (or the return value). + Pops a variable number of entries from the *value* stack + and re-raises the exception they specify. The number of + entries popped depends on the (pseudo) exception type. The block stack is unwound when an exception is raised: when a SETUP_FINALLY entry is found, the exception is pushed @@ -1257,6 +1297,9 @@ com_for_stmt(c, n) stack. Code generated for "try: S except E1, V1: S1 except E2, V2: S2 ...": + (The contents of the value stack is shown in [], with the top + at the right; 'tb' is trace-back info, 'val' the exception's + associated value, and 'exc' the exception.) Value stack Label Instruction Argument [] SETUP_EXCEPT L1 @@ -1264,22 +1307,23 @@ com_for_stmt(c, n) [] POP_BLOCK [] JUMP_FORWARD L0 - [val, exc] L1: DUP - [val, exc, exc] <evaluate E1> - [val, exc, exc, E1] COMPARE_OP EXC_MATCH - [val, exc, 1-or-0] JUMP_IF_FALSE L2 - [val, exc, 1] POP - [val, exc] POP - [val] <assign to V1> + [tb, val, exc] L1: DUP ) + [tb, val, exc, exc] <evaluate E1> ) + [tb, val, exc, exc, E1] COMPARE_OP EXC_MATCH ) only if E1 + [tb, val, exc, 1-or-0] JUMP_IF_FALSE L2 ) + [tb, val, exc, 1] POP ) + [tb, val, exc] POP + [tb, val] <assign to V1> (or POP if no V1) + [tb] POP [] <code for S1> JUMP_FORWARD L0 - [val, exc, 0] L2: POP - [val, exc] DUP + [tb, val, exc, 0] L2: POP + [tb, val, exc] DUP .............................etc....................... - [val, exc, 0] Ln+1: POP - [val, exc] END_FINALLY # re-raise exception + [tb, val, exc, 0] Ln+1: POP + [tb, val, exc] END_FINALLY # re-raise exception [] L0: <next statement> @@ -1323,6 +1367,7 @@ com_try_stmt(c, n) break; } except_anchor = 0; + com_addoparg(c, SET_LINENO, ch->n_lineno); if (NCH(ch) > 1) { com_addbyte(c, DUP_TOP); com_node(c, CHILD(ch, 1)); @@ -1335,6 +1380,7 @@ com_try_stmt(c, n) com_assign(c, CHILD(ch, 3), 1/*assigning*/); else com_addbyte(c, POP_TOP); + com_addbyte(c, POP_TOP); com_node(c, CHILD(n, i+2)); com_addfwref(c, JUMP_FORWARD, &end_anchor); if (except_anchor) { @@ -1346,11 +1392,13 @@ com_try_stmt(c, n) com_backpatch(c, end_anchor); } if (finally_anchor) { + node *ch; com_addbyte(c, POP_BLOCK); com_addoparg(c, LOAD_CONST, com_addconst(c, None)); - com_addoparg(c, LOAD_CONST, com_addconst(c, None)); com_backpatch(c, finally_anchor); - com_node(c, CHILD(n, NCH(n)-1)); + ch = CHILD(n, NCH(n)-1); + com_addoparg(c, SET_LINENO, ch->n_lineno); + com_node(c, ch); com_addbyte(c, END_FINALLY); } } @@ -1382,7 +1430,7 @@ com_funcdef(c, n) { object *v; REQ(n, funcdef); /* funcdef: 'def' NAME parameters ':' suite */ - v = (object *)compile(n); + v = (object *)compile(n, c->c_filename); if (v == NULL) c->c_errors++; else { @@ -1426,7 +1474,7 @@ com_classdef(c, n) com_bases(c, CHILD(n, 4)); else com_addoparg(c, LOAD_CONST, com_addconst(c, None)); - v = (object *)compile(n); + v = (object *)compile(n, c->c_filename); if (v == NULL) c->c_errors++; else { @@ -1459,9 +1507,13 @@ com_node(c, n) /* Trivial parse tree nodes */ case stmt: - case simple_stmt: case flow_stmt: + com_node(c, CHILD(n, 0)); + break; + + case simple_stmt: case compound_stmt: + com_addoparg(c, SET_LINENO, n->n_lineno); com_node(c, CHILD(n, 0)); break; @@ -1479,6 +1531,10 @@ com_node(c, n) case pass_stmt: break; case break_stmt: + if (c->c_loops == 0) { + err_setstr(TypeError, "'break' outside loop"); + c->c_errors++; + } com_addbyte(c, BREAK_LOOP); break; case return_stmt: @@ -1608,48 +1664,50 @@ compile_funcdef(c, n) com_addbyte(c, REQUIRE_ARGS); com_fplist(c, ch); } + c->c_infunction = 1; com_node(c, CHILD(n, 4)); + c->c_infunction = 0; com_addoparg(c, LOAD_CONST, com_addconst(c, None)); com_addbyte(c, RETURN_VALUE); } static void -compile_classdef(c, n) - struct compiling *c; - node *n; -{ - node *ch; - REQ(n, classdef); - /* - classdef: 'class' NAME parameters ['=' baselist] ':' suite - */ - com_addbyte(c, REFUSE_ARGS); - com_node(c, CHILD(n, NCH(n)-1)); - com_addbyte(c, LOAD_LOCALS); - com_addbyte(c, RETURN_VALUE); -} - -static void compile_node(c, n) struct compiling *c; node *n; { + com_addoparg(c, SET_LINENO, n->n_lineno); + switch (TYPE(n)) { case single_input: /* NEWLINE | simple_stmt | compound_stmt NEWLINE */ + com_addbyte(c, REFUSE_ARGS); n = CHILD(n, 0); if (TYPE(n) != NEWLINE) com_node(c, n); + com_addoparg(c, LOAD_CONST, com_addconst(c, None)); + com_addbyte(c, RETURN_VALUE); break; case file_input: + com_addbyte(c, REFUSE_ARGS); com_file_input(c, n); + com_addoparg(c, LOAD_CONST, com_addconst(c, None)); + com_addbyte(c, RETURN_VALUE); break; case expr_input: + com_addbyte(c, REFUSE_ARGS); + com_node(c, CHILD(n, 0)); + com_addoparg(c, LOAD_CONST, com_addconst(c, None)); + com_addbyte(c, RETURN_VALUE); + break; + case eval_input: + com_addbyte(c, REFUSE_ARGS); com_node(c, CHILD(n, 0)); + com_addbyte(c, RETURN_VALUE); break; case funcdef: @@ -1657,7 +1715,11 @@ compile_node(c, n) break; case classdef: - compile_classdef(c, n); + /* 'class' NAME parameters ['=' baselist] ':' suite */ + com_addbyte(c, REFUSE_ARGS); + com_node(c, CHILD(n, NCH(n)-1)); + com_addbyte(c, LOAD_LOCALS); + com_addbyte(c, RETURN_VALUE); break; default: @@ -1668,17 +1730,18 @@ compile_node(c, n) } codeobject * -compile(n) +compile(n, filename) node *n; + char *filename; { struct compiling sc; codeobject *co; - if (!com_init(&sc)) + if (!com_init(&sc, filename)) return NULL; compile_node(&sc, n); com_done(&sc); if (sc.c_errors == 0) - co = newcodeobject(sc.c_code, sc.c_consts, sc.c_names); + co = newcodeobject(sc.c_code, sc.c_consts, sc.c_names, filename); else co = NULL; com_free(&sc); diff --git a/Python/errors.c b/Python/errors.c index 8ddde51..7424b0c 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -11,12 +11,11 @@ return value and then calls puterrno(ctx) to turn the errno value into a true exception. Problems with this approach are: - it used standard errno values to indicate Python-specific errors, - but this means that when such an error code is reported by UNIX the - user gets a confusing message + but this means that when such an error code is reported by a system + call (e.g., in module posix), the user gets a confusing message - errno is a global variable, which makes extensions to a multi- threading environment difficult; e.g., in IRIX, multi-threaded - programs must use the function getoserror() (sp.?) instead of - looking in errno + programs must use the function oserror() instead of looking in errno - there is no portable way to add new error numbers for specic situations -- the value space for errno is reserved to the OS, yet the way to turn module-specific errors into a module-specific @@ -25,21 +24,18 @@ error. The new interface solves all these problems. To return an error, a - built-in function calls err_set(exception), err_set(valexception, + built-in function calls err_set(exception), err_setval(exception, value) or err_setstr(exception, string), and returns NULL. These functions save the value for later use by puterrno(). To adapt this scheme to a multi-threaded environment, only the implementation of err_setval() has to be changed. */ -#include <stdio.h> +#include "errno.h" -#include "PROTO.h" -#include "object.h" -#include "intobject.h" -#include "stringobject.h" -#include "tupleobject.h" -#include "errors.h" +#include "allobjects.h" + +#include "errcode.h" extern char *strerror PROTO((int)); @@ -53,16 +49,12 @@ err_setval(exception, value) object *exception; object *value; { - if (last_exception != NULL) - DECREF(last_exception); - if (exception != NULL) - INCREF(exception); + XDECREF(last_exception); + XINCREF(exception); last_exception = exception; - if (last_exc_val != NULL) - DECREF(last_exc_val); - if (value != NULL) - INCREF(value); + XDECREF(last_exc_val); + XINCREF(value); last_exc_val = value; } @@ -80,8 +72,7 @@ err_setstr(exception, string) { object *value = newstringobject(string); err_setval(exception, value); - if (value != NULL) - DECREF(value); + XDECREF(value); } int @@ -104,14 +95,10 @@ err_get(p_exc, p_val) void err_clear() { - if (last_exception != NULL) { - DECREF(last_exception); - last_exception = NULL; - } - if (last_exc_val != NULL) { - DECREF(last_exc_val); - last_exc_val = NULL; - } + XDECREF(last_exception); + last_exception = NULL; + XDECREF(last_exc_val); + last_exc_val = NULL; } /* Convenience functions to set a type error exception and return 0 */ @@ -126,7 +113,7 @@ err_badarg() object * err_nomem() { - err_setstr(MemoryError, "in built-in function"); + err_set(MemoryError); return NULL; } @@ -140,8 +127,7 @@ err_errno(exc) settupleitem(v, 1, newstringobject(strerror(errno))); } err_setval(exc, v); - if (v != NULL) - DECREF(v); + XDECREF(v); return NULL; } @@ -150,3 +136,34 @@ err_badcall() { err_setstr(SystemError, "bad argument to internal function"); } + +/* Set the error appropriate to the given input error code (see errcode.h) */ + +void +err_input(err) + int err; +{ + switch (err) { + case E_DONE: + case E_OK: + break; + case E_SYNTAX: + err_setstr(RuntimeError, "syntax error"); + break; + case E_TOKEN: + err_setstr(RuntimeError, "illegal token"); + break; + case E_INTR: + err_set(KeyboardInterrupt); + break; + case E_NOMEM: + err_nomem(); + break; + case E_EOF: + err_set(EOFError); + break; + default: + err_setstr(RuntimeError, "unknown input error"); + break; + } +} diff --git a/Python/graminit.c b/Python/graminit.c index c5ea23e..375a239 100644 --- a/Python/graminit.c +++ b/Python/graminit.c @@ -1,4 +1,4 @@ -#include "PROTO.h" +#include "pgenheaders.h" #include "grammar.h" static arc arcs_0_0[3] = { {2, 1}, diff --git a/Python/import.c b/Python/import.c index fd912ba..f4b4ca9 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1,153 +1,67 @@ /* Module definition and import implementation */ -#include <stdio.h> -#include "string.h" +#include "allobjects.h" -#include "PROTO.h" -#include "object.h" -#include "stringobject.h" -#include "listobject.h" -#include "dictobject.h" -#include "moduleobject.h" #include "node.h" -#include "context.h" #include "token.h" #include "graminit.h" -#include "run.h" -#include "support.h" #include "import.h" #include "errcode.h" #include "sysmodule.h" +#include "pythonrun.h" -/* Define pathname separator and delimiter in $PYTHONPATH */ +/* Define pathname separator used in file names */ #ifdef THINK_C #define SEP ':' -#define DELIM ' ' #endif #ifndef SEP #define SEP '/' #endif -#ifndef DELIM -#define DELIM ':' -#endif +static object *modules; + +/* Initialization */ void initimport() { - object *v; - if ((v = newdictobject()) == NULL) - fatal("no mem for module table"); - if (sysset("modules", v) != 0) - fatal("can't assign sys.modules"); - DECREF(v); + if ((modules = newdictobject()) == NULL) + fatal("no mem for dictionary of modules"); } object * -new_module(name) +get_modules() +{ + return modules; +} + +object * +add_module(name) char *name; { object *m; - object *mtab; - mtab = sysget("modules"); - if (mtab == NULL || !is_dictobject(mtab)) { - errno = EBADF; - return NULL; - } + if ((m = dictlookup(modules, name)) != NULL && is_moduleobject(m)) + return m; m = newmoduleobject(name); if (m == NULL) return NULL; - if (dictinsert(mtab, name, m) != 0) { + if (dictinsert(modules, name, m) != 0) { DECREF(m); return NULL; } + DECREF(m); /* Yes, it still exists, in modules! */ return m; } -static void -use_module(ctx, d) - context *ctx; - object *d; -{ - INCREF(d); - DECREF(ctx->ctx_locals); - ctx->ctx_locals = d; - INCREF(d); - DECREF(ctx->ctx_globals); - ctx->ctx_globals = d; -} - -static void -define_module(ctx, name) - context *ctx; - char *name; -{ - object *m; - m = new_module(name); - if (m == NULL) { - puterrno(ctx); - return; - } - use_module(ctx, getmoduledict(m)); - DECREF(m); -} - -static object * -parsepath(path, delim) - char *path; - int delim; -{ - int i, n; - char *p; - object *v, *w; - - n = 1; - p = path; - while ((p = strchr(p, delim)) != NULL) { - n++; - p++; - } - v = newlistobject(n); - if (v == NULL) - return NULL; - for (i = 0; ; i++) { - p = strchr(path, delim); - if (p == NULL) - p = strchr(path, '\0'); /* End of string */ - w = newsizedstringobject(path, (int) (p - path)); - if (w == NULL) { - DECREF(v); - return NULL; - } - setlistitem(v, i, w); - if (*p == '\0') - break; - path = p+1; - } - return v; -} - -void -setpythonpath(path) - char *path; -{ - object *v; - if ((v = parsepath(path, DELIM)) != NULL) { - if (sysset("path", v) != 0) - fatal("can't assign sys.path"); - DECREF(v); - } -} - static FILE * -open_module(name, suffix) +open_module(name, suffix, namebuf) char *name; char *suffix; + char *namebuf; /* XXX No buffer overflow checks! */ { object *path; - char namebuf[256]; FILE *fp; path = sysget("path"); @@ -169,8 +83,8 @@ open_module(name, suffix) len = getstringsize(v); if (len > 0 && namebuf[len-1] != SEP) namebuf[len++] = SEP; - strcpy(namebuf+len, name); /* XXX check for overflow */ - strcat(namebuf, suffix); /* XXX ditto */ + strcpy(namebuf+len, name); + strcat(namebuf, suffix); fp = fopen(namebuf, "r"); if (fp != NULL) break; @@ -180,119 +94,113 @@ open_module(name, suffix) } static object * -load_module(ctx, name) - context *ctx; +get_module(m, name, m_ret) + /*module*/object *m; char *name; + object **m_ret; { - object *m; - char **p; + object *d; FILE *fp; node *n; int err; - object *mtab; - object *save_locals, *save_globals; + char namebuf[256]; - mtab = sysget("modules"); - if (mtab == NULL || !is_dictobject(mtab)) { - errno = EBADF; - return NULL; - } - fp = open_module(name, ".py"); + fp = open_module(name, ".py", namebuf); if (fp == NULL) { - name_error(ctx, name); + if (m == NULL) + err_setstr(NameError, name); + else + err_setstr(RuntimeError, "no module source file"); return NULL; } - err = parseinput(fp, file_input, &n); + err = parse_file(fp, namebuf, file_input, &n); fclose(fp); if (err != E_DONE) { - input_error(ctx, err); - return NULL; - } - save_locals = ctx->ctx_locals; - INCREF(save_locals); - save_globals = ctx->ctx_globals; - INCREF(save_globals); - define_module(ctx, name); - exec_node(ctx, n); - DECREF(ctx->ctx_locals); - ctx->ctx_locals = save_locals; - DECREF(ctx->ctx_globals); - ctx->ctx_globals = save_globals; - /* XXX need to free the tree n here; except referenced defs */ - if (ctx->ctx_exception) { - dictremove(mtab, name); /* Undefine the module */ + err_input(err); return NULL; } - m = dictlookup(mtab, name); if (m == NULL) { - error(ctx, "module not defined after loading"); - return NULL; + m = add_module(name); + if (m == NULL) { + freetree(n); + return NULL; + } + *m_ret = m; } + d = getmoduledict(m); + return run_node(n, namebuf, d, d); +} + +static object * +load_module(name) + char *name; +{ + object *m, *v; + v = get_module((object *)NULL, name, &m); + if (v == NULL) + return NULL; + DECREF(v); return m; } object * -import_module(ctx, name) - context *ctx; +import_module(name) char *name; { object *m; - object *mtab; - mtab = sysget("modules"); - if (mtab == NULL || !is_dictobject(mtab)) { - error(ctx, "bad sys.modules"); - return NULL; - } - if ((m = dictlookup(mtab, name)) == NULL) { - m = load_module(ctx, name); - } + if ((m = dictlookup(modules, name)) == NULL) + m = load_module(name); return m; } object * -reload_module(ctx, m) - context *ctx; +reload_module(m) object *m; { - char *name; - FILE *fp; - node *n; - int err; - object *d; - object *save_locals, *save_globals; if (m == NULL || !is_moduleobject(m)) { - type_error(ctx, "reload() argument must be module"); + err_setstr(TypeError, "reload() argument must be module"); return NULL; } - /* XXX Ought to check for builtin module */ - name = getmodulename(m); - fp = open_module(name, ".py"); - if (fp == NULL) { - error(ctx, "reload() cannot find module source file"); - return NULL; + /* XXX Ought to check for builtin modules -- can't reload these... */ + return get_module(m, getmodulename(m), (object **)NULL); +} + +static void +cleardict(d) + object *d; +{ + int i; + for (i = getdictsize(d); --i >= 0; ) { + char *k; + k = getdictkey(d, i); + if (k != NULL) + (void) dictremove(d, k); } - err = parseinput(fp, file_input, &n); - fclose(fp); - if (err != E_DONE) { - input_error(ctx, err); - return NULL; +} + +void +doneimport() +{ + if (modules != NULL) { + int i; + /* Explicitly erase all modules; this is the safest way + to get rid of at least *some* circular dependencies */ + for (i = getdictsize(modules); --i >= 0; ) { + char *k; + k = getdictkey(modules, i); + if (k != NULL) { + object *m; + m = dictlookup(modules, k); + if (m != NULL && is_moduleobject(m)) { + object *d; + d = getmoduledict(m); + if (d != NULL && is_dictobject(d)) { + cleardict(d); + } + } + } + } + cleardict(modules); } - d = newdictobject(); - if (d == NULL) - return NULL; - setmoduledict(m, d); - save_locals = ctx->ctx_locals; - INCREF(save_locals); - save_globals = ctx->ctx_globals; - INCREF(save_globals); - use_module(ctx, d); - exec_node(ctx, n); - DECREF(ctx->ctx_locals); - ctx->ctx_locals = save_locals; - DECREF(ctx->ctx_globals); - ctx->ctx_globals = save_globals; - if (ctx->ctx_exception) - return NULL; - INCREF(None); - return None; + DECREF(modules); } diff --git a/Python/modsupport.c b/Python/modsupport.c index 159f98e..3b195ba 100644 --- a/Python/modsupport.c +++ b/Python/modsupport.c @@ -1,36 +1,8 @@ /* Module support implementation */ -#include <stdio.h> - -#include "PROTO.h" -#include "object.h" -#include "intobject.h" -#include "stringobject.h" -#include "tupleobject.h" -#include "listobject.h" -#include "methodobject.h" -#include "moduleobject.h" +#include "allobjects.h" #include "modsupport.h" #include "import.h" -#include "errors.h" - - -/* Find a method in a module's method table. - Usually called from a module's getattr method. */ - -object * -findmethod(ml, op, name) - struct methodlist *ml; - object *op; - char *name; -{ - for (; ml->ml_name != NULL; ml++) { - if (strcmp(name, ml->ml_name) == 0) - return newmethodobject(ml->ml_name, ml->ml_meth, op); - } - err_setstr(NameError, name); - return NULL; -} object * @@ -40,21 +12,24 @@ initmodule(name, methods) { object *m, *d, *v; struct methodlist *ml; - if ((m = new_module(name)) == NULL) { + char namebuf[256]; + if ((m = add_module(name)) == NULL) { fprintf(stderr, "initializing module: %s\n", name); fatal("can't create a module"); } d = getmoduledict(m); for (ml = methods; ml->ml_name != NULL; ml++) { - v = newmethodobject(ml->ml_name, ml->ml_meth, (object *)NULL); + sprintf(namebuf, "%s.%s", name, ml->ml_name); + v = newmethodobject(strdup(namebuf), ml->ml_meth, + (object *)NULL); + /* XXX The strdup'ed memory is never freed */ if (v == NULL || dictinsert(d, ml->ml_name, v) != 0) { fprintf(stderr, "initializing module: %s\n", name); fatal("can't initialize module"); } DECREF(v); } - DECREF(m); - return m; /* Yes, it still exists, in sys.modules... */ + return m; } diff --git a/Python/pythonmain.c b/Python/pythonmain.c index ffff0ae..f095cdd 100644 --- a/Python/pythonmain.c +++ b/Python/pythonmain.c @@ -1,24 +1,25 @@ /* Python interpreter main program */ -#include <stdio.h> -#include <ctype.h> -#include "string.h" +#include "allobjects.h" -extern char *getpythonpath(); - -#include "PROTO.h" #include "grammar.h" #include "node.h" #include "parsetok.h" #include "graminit.h" #include "errcode.h" -#include "object.h" -#include "stringobject.h" #include "sysmodule.h" +#include "compile.h" +#include "ceval.h" +#include "pythonrun.h" +#include "import.h" + +extern char *getpythonpath(); extern grammar gram; /* From graminit.c */ -int debugging; +#ifdef DEBUG +int debugging; /* Needed by parser.c */ +#endif main(argc, argv) int argc; @@ -26,15 +27,12 @@ main(argc, argv) { char *filename = NULL; FILE *fp = stdin; - int ret; - - initargs(&argc, &argv); - initintr(); /* For intrcheck() */ + initargs(&argc, &argv); if (argc > 1 && strcmp(argv[1], "-") != 0) filename = argv[1]; - + if (filename != NULL) { if ((fp = fopen(filename, "r")) == NULL) { fprintf(stderr, "python: can't open file '%s'\n", @@ -43,89 +41,339 @@ main(argc, argv) } } - /* XXX what is the ideal initialization order? */ - /* XXX exceptions are initialized by initrun but this - may be too late */ + initall(); + + setpythonpath(getpythonpath()); + setpythonargv(argc-1, argv+1); + + goaway(run(fp, filename == NULL ? "<stdin>" : filename)); + /*NOTREACHED*/ +} + +/* Initialize all */ + +void +initall() +{ + static int inited; + + if (inited) + return; + + initimport(); - initsys(argc-1, argv+1); + initbuiltin(); /* Also initializes builtin exceptions */ + initsys(); inittime(); initmath(); - setpythonpath(getpythonpath()); + initcalls(); /* Configuration-dependent initializations */ - initrun(); - initcalls(); + initintr(); /* For intrcheck() */ - if (!isatty(fileno(fp))) { - ret = runfile(fp, file_input, (char *)NULL, (char *)NULL); + inited = 1; +} + +/* Parse input from a file and execute it */ + +int +run(fp, filename) + FILE *fp; + char *filename; +{ + if (filename == NULL) + filename = "???"; + if (isatty(fileno(fp))) + return run_tty_loop(fp, filename); + else + return run_script(fp, filename); +} + +int +run_tty_loop(fp, filename) + FILE *fp; + char *filename; +{ + object *v; + int ret; + v = sysget("ps1"); + if (v == NULL) { + sysset("ps1", v = newstringobject(">>> ")); + XDECREF(v); + } + v = sysget("ps2"); + if (v == NULL) { + sysset("ps2", v = newstringobject("... ")); + XDECREF(v); + } + for (;;) { + ret = run_tty_1(fp, filename); +#ifdef REF_DEBUG + fprintf(stderr, "[%ld refs]\n", ref_total); +#endif + if (ret == E_EOF) + return 0; + /* + if (ret == E_NOMEM) + return -1; + */ + } +} + +int +run_tty_1(fp, filename) + FILE *fp; + char *filename; +{ + object *m, *d, *v, *w; + node *n; + char *ps1, *ps2; + int err; + v = sysget("ps1"); + w = sysget("ps2"); + if (v != NULL && is_stringobject(v)) { + INCREF(v); + ps1 = getstringvalue(v); } else { - object *v, *w; - sysset("ps1", v = newstringobject(">>> ")); - sysset("ps2", w = newstringobject("... ")); - DECREF(v); - DECREF(w); - for (;;) { - char *ps1 = NULL, *ps2 = NULL; - v = sysget("ps1"); - w = sysget("ps2"); - if (v != NULL && is_stringobject(v)) { - INCREF(v); - ps1 = getstringvalue(v); - } - else - v = NULL; - if (w != NULL && is_stringobject(w)) { - INCREF(w); - ps2 = getstringvalue(w); - } - else - w = NULL; - ret = runfile(fp, single_input, ps1, ps2); - if (v != NULL) - DECREF(v); - if (w != NULL) - DECREF(w); - if (ret == E_EOF || ret == E_NOMEM) - break; - } + v = NULL; + ps1 = ""; } - goaway(ret == E_DONE || ret == E_EOF ? 0 : 1); - /*NOTREACHED*/ + if (w != NULL && is_stringobject(w)) { + INCREF(w); + ps2 = getstringvalue(w); + } + else { + w = NULL; + ps2 = ""; + } + err = parsefile(fp, filename, &gram, single_input, ps1, ps2, &n); + XDECREF(v); + XDECREF(w); + if (err == E_EOF) + return E_EOF; + if (err != E_DONE) { + err_input(err); + print_error(); + return err; + } + m = add_module("__main__"); + if (m == NULL) + return -1; + d = getmoduledict(m); + v = run_node(n, filename, d, d); + flushline(); + if (v == NULL) { + print_error(); + return -1; + } + DECREF(v); + return 0; +} + +int +run_script(fp, filename) + FILE *fp; + char *filename; +{ + object *m, *d, *v; + m = add_module("__main__"); + if (m == NULL) + return -1; + d = getmoduledict(m); + v = run_file(fp, filename, file_input, d, d); + flushline(); + if (v == NULL) { + print_error(); + return -1; + } + DECREF(v); + return 0; +} + +void +print_error() +{ + object *exception, *v; + err_get(&exception, &v); + fprintf(stderr, "Unhandled exception: "); + printobject(exception, stderr, PRINT_RAW); + if (v != NULL && v != None) { + fprintf(stderr, ": "); + printobject(v, stderr, PRINT_RAW); + } + fprintf(stderr, "\n"); + XDECREF(exception); + XDECREF(v); + printtraceback(stderr); +} + +object * +run_string(str, start, globals, locals) + char *str; + int start; + /*dict*/object *globals, *locals; +{ + node *n; + int err; + err = parse_string(str, start, &n); + return run_err_node(err, n, "<string>", globals, locals); +} + +object * +run_file(fp, filename, start, globals, locals) + FILE *fp; + char *filename; + int start; + /*dict*/object *globals, *locals; +{ + node *n; + int err; + err = parse_file(fp, filename, start, &n); + return run_err_node(err, n, filename, globals, locals); +} + +object * +run_err_node(err, n, filename, globals, locals) + int err; + node *n; + char *filename; + /*dict*/object *globals, *locals; +{ + if (err != E_DONE) { + err_input(err); + return NULL; + } + return run_node(n, filename, globals, locals); +} + +object * +run_node(n, filename, globals, locals) + node *n; + char *filename; + /*dict*/object *globals, *locals; +{ + if (globals == NULL) { + globals = getglobals(); + if (locals == NULL) + locals = getlocals(); + } + else { + if (locals == NULL) + locals = globals; + } + return eval_node(n, filename, globals, locals); +} + +object * +eval_node(n, filename, globals, locals) + node *n; + char *filename; + object *globals; + object *locals; +{ + codeobject *co; + object *v; + co = compile(n, filename); + freetree(n); + if (co == NULL) + return NULL; + v = eval_code(co, globals, locals, (object *)NULL); + DECREF(co); + return v; +} + +/* Simplified interface to parsefile */ + +int +parse_file(fp, filename, start, n_ret) + FILE *fp; + char *filename; + int start; + node **n_ret; +{ + return parsefile(fp, filename, &gram, start, + (char *)0, (char *)0, n_ret); +} + +/* Simplified interface to parsestring */ + +int +parse_string(str, start, n_ret) + char *str; + int start; + node **n_ret; +{ + int err = parsestring(str, &gram, start, n_ret); + /* Don't confuse early end of string with early end of input */ + if (err == E_EOF) + err = E_SYNTAX; + return err; +} + +/* Print fatal error message and abort */ + +void +fatal(msg) + char *msg; +{ + fprintf(stderr, "Fatal error: %s\n", msg); + abort(); } +/* Clean up and exit */ + +void goaway(sts) int sts; { + flushline(); + + /* XXX Call doneimport() before donecalls(), since donecalls() + calls wdone(), and doneimport() may close windows */ + doneimport(); + donecalls(); + + err_clear(); + +#ifdef REF_DEBUG + fprintf(stderr, "[%ld refs]\n", ref_total); +#endif + #ifdef THINK_C if (sts == 0) Click_On(0); #endif - closerun(); - donecalls(); + +#ifdef TRACE_REFS + if (askyesno("Print left references?")) { +#ifdef THINK_C + Click_On(1); +#endif + printrefs(stderr); + } +#endif /* TRACE_REFS */ + exit(sts); /*NOTREACHED*/ } -/* Parse input from a file and execute it */ - -static int -runfile(fp, start, ps1, ps2) - FILE *fp; - int start; - char *ps1, *ps2; +static +finaloutput() { - node *n; - int ret; - ret = parsefile(fp, &gram, start, ps1, ps2, &n); - if (ret != E_DONE) - return ret; - return execute(n) == 0 ? E_DONE : E_ERROR; +#ifdef TRACE_REFS + if (!askyesno("Print left references?")) + return; +#ifdef THINK_C + Click_On(1); +#endif /* THINK_C */ + printrefs(stderr); +#endif /* TRACE_REFS */ } /* Ask a yes/no question */ -int +static int askyesno(prompt) char *prompt; { @@ -151,15 +399,14 @@ isatty(fd) #endif -/* WISH LIST +/* XXX WISH LIST - - improved per-module error handling; different use of errno - possible new types: - iterator (for range, keys, ...) - improve interpreter error handling, e.g., true tracebacks - - release parse trees when no longer needed (make them objects?) - - faster parser (for long modules) - save precompiled modules on file? - fork threads, locking - allow syntax extensions */ + +/* "Floccinaucinihilipilification" */ diff --git a/Python/structmember.c b/Python/structmember.c new file mode 100644 index 0000000..42c563e --- /dev/null +++ b/Python/structmember.c @@ -0,0 +1,134 @@ +/* Map C struct members to Python object attributes */ + +#include "allobjects.h" + +#include "structmember.h" + +object * +getmember(addr, mlist, name) + char *addr; + struct memberlist *mlist; + char *name; +{ + struct memberlist *l; + + for (l = mlist; l->name != NULL; l++) { + if (strcmp(l->name, name) == 0) { + object *v; + addr += l->offset; + switch (l->type) { + case T_SHORT: + v = newintobject((long) *(short*)addr); + break; + case T_INT: + v = newintobject((long) *(int*)addr); + break; + case T_LONG: + v = newintobject(*(long*)addr); + break; + case T_FLOAT: + v = newfloatobject((double)*(float*)addr); + break; + case T_DOUBLE: + v = newfloatobject(*(double*)addr); + break; + case T_STRING: + if (*(char**)addr == NULL) { + INCREF(None); + v = None; + } + else + v = newstringobject(*(char**)addr); + break; + case T_OBJECT: + v = *(object **)addr; + if (v == NULL) + v = None; + INCREF(v); + break; + default: + err_setstr(SystemError, "bad memberlist type"); + v = NULL; + } + return v; + } + } + + err_setstr(NameError, name); + return NULL; +} + +int +setmember(addr, mlist, name, v) + char *addr; + struct memberlist *mlist; + char *name; + object *v; +{ + struct memberlist *l; + + for (l = mlist; l->name != NULL; l++) { + if (strcmp(l->name, name) == 0) { + if (l->readonly || l->type == T_STRING) { + err_setstr(RuntimeError, "readonly attribute"); + return -1; + } + addr += l->offset; + switch (l->type) { + case T_SHORT: + if (!is_intobject(v)) { + err_badarg(); + return -1; + } + *(short*)addr = getintvalue(v); + break; + case T_INT: + if (!is_intobject(v)) { + err_badarg(); + return -1; + } + *(int*)addr = getintvalue(v); + break; + case T_LONG: + if (!is_intobject(v)) { + err_badarg(); + return -1; + } + *(long*)addr = getintvalue(v); + break; + case T_FLOAT: + if (is_intobject(v)) + *(float*)addr = getintvalue(v); + else if (is_floatobject(v)) + *(float*)addr = getfloatvalue(v); + else { + err_badarg(); + return -1; + } + break; + case T_DOUBLE: + if (is_intobject(v)) + *(double*)addr = getintvalue(v); + else if (is_floatobject(v)) + *(double*)addr = getfloatvalue(v); + else { + err_badarg(); + return -1; + } + break; + case T_OBJECT: + XDECREF(*(object **)addr); + XINCREF(v); + *(object **)addr = v; + break; + default: + err_setstr(SystemError, "bad memberlist type"); + return -1; + } + return 0; + } + } + + err_setstr(NameError, name); + return NULL; +} diff --git a/Python/sysmodule.c b/Python/sysmodule.c index f276fb4..5cc1d96 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -3,31 +3,31 @@ /* Various bits of information used by the interpreter are collected in module 'sys'. +Function member: +- exit(sts): call (C, POSIX) exit(sts) Data members: - stdin, stdout, stderr: standard file objects -- ps1, ps2: primary and secondary prompts (strings) -- path: module search path (list of strings) - modules: the table of modules (dictionary) -Function members: -- exit(sts): call exit() +- path: module search path (list of strings) +- argv: script arguments (list of strings) +- ps1, ps2: optional primary and secondary prompts (strings) */ -#include <stdio.h> +#include "allobjects.h" -#include "PROTO.h" -#include "object.h" -#include "stringobject.h" -#include "listobject.h" -#include "dictobject.h" -#include "fileobject.h" -#include "moduleobject.h" #include "sysmodule.h" -#include "node.h" /* For context.h */ -#include "context.h" /* For import.h */ #include "import.h" -#include "methodobject.h" #include "modsupport.h" -#include "errors.h" + +/* Define delimiter used in $PYTHONPATH */ + +#ifdef THINK_C +#define DELIM ' ' +#endif + +#ifndef DELIM +#define DELIM ':' +#endif static object *sysdict; @@ -64,34 +64,6 @@ sysset(name, v) } static object * -makeargv(argc, argv) - int argc; - char **argv; -{ - int i; - object *av, *v; - if (argc < 0 || argv == NULL) - argc = 0; - av = newlistobject(argc); - if (av != NULL) { - for (i = 0; i < argc; i++) { - v = newstringobject(argv[i]); - if (v == NULL) { - DECREF(av); - av = NULL; - break; - } - setlistitem(av, i, v); - } - } - if (av == NULL) - fatal("no mem for sys.argv"); - return av; -} - -/* sys.exit method */ - -static object * sys_exit(self, args) object *self; object *args; @@ -104,88 +76,115 @@ sys_exit(self, args) /* NOTREACHED */ } +static struct methodlist sys_methods[] = { + {"exit", sys_exit}, + {NULL, NULL} /* sentinel */ +}; + static object *sysin, *sysout, *syserr; void -initsys(argc, argv) - int argc; - char **argv; +initsys() { - object *v; - object *exit; - if ((sysdict = newdictobject()) == NULL) - fatal("can't create sys dict"); + object *m = initmodule("sys", sys_methods); + sysdict = getmoduledict(m); + INCREF(sysdict); /* NB keep an extra ref to the std files to avoid closing them when the user deletes them */ + /* XXX File objects should have a "don't close" flag instead */ sysin = newopenfileobject(stdin, "<stdin>", "r"); sysout = newopenfileobject(stdout, "<stdout>", "w"); syserr = newopenfileobject(stderr, "<stderr>", "w"); - v = makeargv(argc, argv); - exit = newmethodobject("exit", sys_exit, (object *)NULL); if (err_occurred()) - fatal("can't create sys.* objects"); + fatal("can't create sys.std* file objects"); dictinsert(sysdict, "stdin", sysin); dictinsert(sysdict, "stdout", sysout); dictinsert(sysdict, "stderr", syserr); - dictinsert(sysdict, "argv", v); - dictinsert(sysdict, "exit", exit); + dictinsert(sysdict, "modules", get_modules()); if (err_occurred()) fatal("can't insert sys.* objects in sys dict"); - DECREF(exit); - DECREF(v); - /* The other symbols are added elsewhere */ - - /* Only now can we initialize the import stuff, after which - we can turn ourselves into a module */ - initimport(); - if ((v = new_module("sys")) == NULL) - fatal("can't create sys module"); - if (setmoduledict(v, sysdict) != 0) - fatal("can't assign sys dict to sys module"); - DECREF(v); } -static void -cleardict(d) - object *d; +static object * +makepathobject(path, delim) + char *path; + int delim; { - int i; - for (i = getdictsize(d); --i >= 0; ) { - char *k; - k = getdictkey(d, i); - if (k != NULL) { - (void) dictremove(d, k); + int i, n; + char *p; + object *v, *w; + + n = 1; + p = path; + while ((p = strchr(p, delim)) != NULL) { + n++; + p++; + } + v = newlistobject(n); + if (v == NULL) + return NULL; + for (i = 0; ; i++) { + p = strchr(path, delim); + if (p == NULL) + p = strchr(path, '\0'); /* End of string */ + w = newsizedstringobject(path, (int) (p - path)); + if (w == NULL) { + DECREF(v); + return NULL; } + setlistitem(v, i, w); + if (*p == '\0') + break; + path = p+1; } + return v; } void -closesys() +setpythonpath(path) + char *path; { - object *modules; - modules = sysget("modules"); - if (modules != NULL && is_dictobject(modules)) { + object *v; + if ((v = makepathobject(path, DELIM)) == NULL) + fatal("can't create sys.path"); + if (sysset("path", v) != 0) + fatal("can't assign sys.path"); + DECREF(v); +} + +static object * +makeargvobject(argc, argv) + int argc; + char **argv; +{ + object *av; + if (argc < 0 || argv == NULL) + argc = 0; + av = newlistobject(argc); + if (av != NULL) { int i; - /* Explicitly erase all modules; this is the safest way - to get rid of at least *some* circular dependencies */ - INCREF(modules); - for (i = getdictsize(modules); --i >= 0; ) { - char *k; - k = getdictkey(modules, i); - if (k != NULL) { - object *m; - m = dictlookup(modules, k); - if (m != NULL && is_moduleobject(m)) { - object *d; - d = getmoduledict(m); - if (d != NULL && is_dictobject(d)) { - cleardict(d); - } - } + for (i = 0; i < argc; i++) { + object *v = newstringobject(argv[i]); + if (v == NULL) { + DECREF(av); + av = NULL; + break; } + setlistitem(av, i, v); } - cleardict(modules); - DECREF(modules); } - DECREF(sysdict); + return av; +} + +void +setpythonargv(argc, argv) + int argc; + char **argv; +{ + object *av = makeargvobject(argc, argv); + if (av == NULL) + fatal("no mem for sys.argv"); + if (sysset("argv", av) != 0) + fatal("can't assign sys.argv"); + DECREF(av); } diff --git a/Python/traceback.c b/Python/traceback.c new file mode 100644 index 0000000..f32dcf6 --- /dev/null +++ b/Python/traceback.c @@ -0,0 +1,193 @@ +/* Traceback implementation */ + +#include "allobjects.h" + +#include "compile.h" +#include "frameobject.h" +#include "traceback.h" +#include "structmember.h" + +typedef struct _tracebackobject { + OB_HEAD + struct _tracebackobject *tb_next; + frameobject *tb_frame; + int tb_lasti; + int tb_lineno; +} tracebackobject; + +#define OFF(x) offsetof(tracebackobject, x) + +static struct memberlist tb_memberlist[] = { + {"tb_next", T_OBJECT, OFF(tb_next)}, + {"tb_frame", T_OBJECT, OFF(tb_frame)}, + {"tb_lasti", T_INT, OFF(tb_lasti)}, + {"tb_lineno", T_INT, OFF(tb_lineno)}, + {NULL} /* Sentinel */ +}; + +static object * +tb_getattr(tb, name) + tracebackobject *tb; + char *name; +{ + return getmember((char *)tb, tb_memberlist, name); +} + +static void +tb_dealloc(tb) + tracebackobject *tb; +{ + XDECREF(tb->tb_next); + XDECREF(tb->tb_frame); + DEL(tb); +} + +static typeobject Tracebacktype = { + OB_HEAD_INIT(&Typetype) + 0, + "traceback", + sizeof(tracebackobject), + 0, + tb_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + tb_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; + +#define is_tracebackobject(v) ((v)->ob_type == &Tracebacktype) + +static tracebackobject * +newtracebackobject(next, frame, lasti, lineno) + tracebackobject *next; + frameobject *frame; + int lasti, lineno; +{ + tracebackobject *tb; + if ((next != NULL && !is_tracebackobject(next)) || + frame == NULL || !is_frameobject(frame)) { + err_badcall(); + return NULL; + } + tb = NEWOBJ(tracebackobject, &Tracebacktype); + if (tb != NULL) { + XINCREF(next); + tb->tb_next = next; + XINCREF(frame); + tb->tb_frame = frame; + tb->tb_lasti = lasti; + tb->tb_lineno = lineno; + } + return tb; +} + +static tracebackobject *tb_current = NULL; + +int +tb_here(frame, lasti, lineno) + frameobject *frame; + int lasti; + int lineno; +{ + tracebackobject *tb; + tb = newtracebackobject(tb_current, frame, lasti, lineno); + if (tb == NULL) + return -1; + XDECREF(tb_current); + tb_current = tb; + return 0; +} + +object * +tb_fetch() +{ + object *v; + v = (object *)tb_current; + tb_current = NULL; + return v; +} + +int +tb_store(v) + object *v; +{ + if (v != NULL && !is_tracebackobject(v)) { + err_badcall(); + return -1; + } + XDECREF(tb_current); + XINCREF(v); + tb_current = (tracebackobject *)v; + return 0; +} + +static void +tb_displayline(fp, filename, lineno) + FILE *fp; + char *filename; + int lineno; +{ + FILE *xfp; + char buf[1000]; + int i; + if (filename[0] == '<' && filename[strlen(filename)-1] == '>') + return; + xfp = fopen(filename, "r"); + if (xfp == NULL) { + fprintf(fp, " (cannot open \"%s\")\n", filename); + return; + } + for (i = 0; i < lineno; i++) { + if (fgets(buf, sizeof buf, xfp) == NULL) + break; + } + if (i == lineno) { + char *p = buf; + while (*p == ' ' || *p == '\t') + p++; + fprintf(fp, " %s", p); + if (strchr(p, '\n') == NULL) + fprintf(fp, "\n"); + } + fclose(xfp); +} + +static void +tb_printinternal(tb, fp) + tracebackobject *tb; + FILE *fp; +{ + while (tb != NULL) { + if (intrcheck()) { + fprintf(fp, "[interrupted]\n"); + break; + } + fprintf(fp, " File \""); + printobject(tb->tb_frame->f_code->co_filename, fp, PRINT_RAW); + fprintf(fp, "\", line %d\n", tb->tb_lineno); + tb_displayline(fp, + getstringvalue(tb->tb_frame->f_code->co_filename), + tb->tb_lineno); + tb = tb->tb_next; + } +} + +int +tb_print(v, fp) + object *v; + FILE *fp; +{ + if (v == NULL) + return 0; + if (!is_tracebackobject(v)) { + err_badcall(); + return -1; + } + sysset("last_traceback", v); + tb_printinternal((tracebackobject *)v, fp); + return 0; +} |