diff options
author | Guido van Rossum <guido@python.org> | 1994-08-29 12:16:12 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1994-08-29 12:16:12 (GMT) |
commit | 4ca6c9db81ded166c95ce3f829ac4642d02f934d (patch) | |
tree | ee3452a886ec35893b9cb3e83eb0921fbdc9ee1d /Python/compile.c | |
parent | 3a241818377f0189a1f3c0d673c983bed5e94ffb (diff) | |
download | cpython-4ca6c9db81ded166c95ce3f829ac4642d02f934d.zip cpython-4ca6c9db81ded166c95ce3f829ac4642d02f934d.tar.gz cpython-4ca6c9db81ded166c95ce3f829ac4642d02f934d.tar.bz2 |
* Python/compile.c (com_argdefs, com_arglist): avoid referencing
CHILD(n,i) for i >= NCH(n)
Diffstat (limited to 'Python/compile.c')
-rw-r--r-- | Python/compile.c | 459 |
1 files changed, 303 insertions, 156 deletions
diff --git a/Python/compile.c b/Python/compile.c index aee2585..d813400 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1,5 +1,5 @@ /*********************************************************** -Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum, +Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum, Amsterdam, The Netherlands. All Rights Reserved @@ -127,16 +127,16 @@ typeobject Codetype = { "code", sizeof(codeobject), 0, - code_dealloc, /*tp_dealloc*/ + (destructor)code_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ - code_getattr, /*tp_getattr*/ + (getattrfunc)code_getattr, /*tp_getattr*/ 0, /*tp_setattr*/ - code_compare, /*tp_compare*/ - code_repr, /*tp_repr*/ + (cmpfunc)code_compare, /*tp_compare*/ + (reprfunc)code_repr, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ - code_hash, /*tp_hash*/ + (hashfunc)code_hash, /*tp_hash*/ }; codeobject * @@ -151,16 +151,37 @@ newcodeobject(code, consts, names, filename, name) int i; /* Check argument types */ if (code == NULL || !is_stringobject(code) || - consts == NULL || !is_listobject(consts) || - names == NULL || !is_listobject(names) || + consts == NULL || + names == NULL || name == NULL || !(is_stringobject(name) || name == None)) { err_badcall(); return NULL; } + /* Allow two lists instead of two tuples */ + if (is_listobject(consts) && is_listobject(names)) { + consts = listtuple(consts); + if (consts == NULL) + return NULL; + names = listtuple(names); + if (names == NULL) { + DECREF(consts); + return NULL; + } + } + else if (!is_tupleobject(consts) && !is_tupleobject(names)) { + err_badcall(); + return NULL; + } + else { + INCREF(consts); + INCREF(names); + } /* Make sure the list of names contains only strings */ - for (i = getlistsize(names); --i >= 0; ) { - object *v = getlistitem(names, i); + for (i = gettuplesize(names); --i >= 0; ) { + object *v = gettupleitem(names, i); if (v == NULL || !is_stringobject(v)) { + DECREF(consts); + DECREF(names); err_badcall(); return NULL; } @@ -169,15 +190,17 @@ newcodeobject(code, consts, names, filename, name) if (co != NULL) { INCREF(code); co->co_code = (stringobject *)code; - INCREF(consts); co->co_consts = consts; - INCREF(names); co->co_names = names; INCREF(filename); co->co_filename = filename; INCREF(name); co->co_name = name; } + else { + DECREF(consts); + DECREF(names); + } return co; } @@ -194,6 +217,7 @@ struct compiling { int c_nexti; /* index into c_code */ int c_errors; /* counts errors occurred */ int c_infunction; /* set when compiling a function */ + int c_interactive; /* generating code for interactive command */ int c_loops; /* counts nested loops */ int c_begin; /* begin of current loop, for 'continue' */ int c_block[MAXBLOCKS]; /* stack of block types */ @@ -249,6 +273,7 @@ static int com_addconst PROTO((struct compiling *, object *)); static int com_addname PROTO((struct compiling *, object *)); static void com_addopname PROTO((struct compiling *, int, node *)); static void com_list PROTO((struct compiling *, node *, int)); +static int com_argdefs PROTO((struct compiling *, node *, int *)); static int com_init(c, filename) @@ -266,6 +291,7 @@ com_init(c, filename) c->c_nexti = 0; c->c_errors = 0; c->c_infunction = 0; + c->c_interactive = 0; c->c_loops = 0; c->c_begin = 0; c->c_nblocks = 0; @@ -462,20 +488,19 @@ static object * parsenumber(s) char *s; { - extern long strtol PROTO((const char *, char **, int)); - extern unsigned long strtoul PROTO((const char *, char **, int)); - extern double strtod PROTO((const char *, char **)); + extern long mystrtol PROTO((const char *, char **, int)); + extern unsigned long mystrtoul PROTO((const char *, char **, int)); + extern double atof PROTO((const char *)); char *end; long x; - double xx; errno = 0; end = s + strlen(s) - 1; if (*end == 'l' || *end == 'L') return long_scan(s, 0); if (s[0] == '0') - x = (long) strtoul(s, &end, 0); + x = (long) mystrtoul(s, &end, 0); else - x = strtol(s, &end, 0); + x = mystrtol(s, &end, 0); if (*end == '\0') { if (errno != 0) { err_setstr(OverflowError, @@ -484,22 +509,8 @@ parsenumber(s) } return newintobject(x); } - errno = 0; - xx = strtod(s, &end); - if (*end == '\0') { -#ifndef BROKEN_STRTOD - /* Some strtod() versions (e.g., in older SunOS systems) - set errno incorrectly; better to ignore overflows - than not to be able to use float literals at all! */ - if (errno != 0) { - err_setstr(OverflowError, "float literal too large"); - return NULL; - } -#endif - return newfloatobject(xx); - } - err_setstr(SystemError, "bad number syntax?!?!"); - return NULL; + /* XXX Huge floats may silently fail */ + return newfloatobject(atof(s)); } static object * @@ -510,6 +521,7 @@ parsestr(s) int len; char *buf; char *p; + char *end; int c; int quote = *s; if (quote != '\'' && quote != '\"') { @@ -522,11 +534,20 @@ parsestr(s) err_badcall(); return NULL; } + if (len >= 4 && s[0] == quote && s[1] == quote) { + s += 2; + len -= 2; + if (s[--len] != quote || s[--len] != quote) { + err_badcall(); + return NULL; + } + } if (strchr(s, '\\') == NULL) return newsizedstringobject(s, len); v = newsizedstringobject((char *)NULL, len); p = buf = getstringvalue(v); - while (*s != '\0' && *s != quote) { + end = s + len; + while (s < end) { if (*s != '\\') { *p++ = *s++; continue; @@ -534,6 +555,7 @@ parsestr(s) s++; switch (*s++) { /* XXX This assumes ASCII! */ + case '\n': break; case '\\': *p++ = '\\'; break; case '\'': *p++ = '\''; break; case '\"': *p++ = '\"'; break; @@ -649,7 +671,14 @@ com_atom(c, n) com_addoparg(c, LOAD_CONST, i); break; case STRING: - if ((v = parsestr(STR(ch))) == NULL) { + if ((v = parsestr(STR(ch))) != NULL) { + /* String literal concatenation */ + for (i = 1; i < NCH(n) && v != NULL; i++) { + joinstring_decref(&v, + parsestr(STR(CHILD(n, i)))); + } + } + if (v == NULL) { c->c_errors++; i = 255; } @@ -1098,6 +1127,8 @@ com_test(c, n) if (NCH(n) == 1 && TYPE(CHILD(n, 0)) == lambdef) { object *v; int i; + int argcount; + int ndefs = com_argdefs(c, CHILD(n, 0), &argcount); v = (object *) compile(CHILD(n, 0), c->c_filename); if (v == NULL) { c->c_errors++; @@ -1109,6 +1140,8 @@ com_test(c, n) } com_addoparg(c, LOAD_CONST, i); com_addbyte(c, BUILD_FUNCTION); + if (ndefs > 0) + com_addoparg(c, SET_FUNC_ARGS, argcount); } else { int anchor = 0; @@ -1355,7 +1388,10 @@ com_expr_stmt(c, n) REQ(n, expr_stmt); /* testlist ('=' testlist)* */ com_node(c, CHILD(n, NCH(n)-1)); if (NCH(n) == 1) { - com_addbyte(c, PRINT_EXPR); + if (c->c_interactive) + com_addbyte(c, PRINT_EXPR); + else + com_addbyte(c, POP_TOP); } else { int i; @@ -1625,25 +1661,7 @@ com_for_stmt(c, n) com_backpatch(c, break_anchor); } -/* Although 'execpt' and 'finally' clauses can be combined - syntactically, they are compiled separately. In fact, - try: S - except E1: S1 - except E2: S2 - ... - finally: Sf - is equivalent to - try: - try: S - except E1: S1 - except E2: S2 - ... - finally: Sf - meaning that the 'finally' clause is entered even if things - go wrong again in an exception handler. Note that this is - not the case for exception handlers: at most one is entered. - - Code generated for "try: S finally: Sf" is as follows: +/* Code generated for "try: S finally: Sf" is as follows: SETUP_FINALLY L <code for S> @@ -1710,86 +1728,97 @@ com_for_stmt(c, n) */ static void -com_try_stmt(c, n) +com_try_except(c, n) struct compiling *c; node *n; { - int finally_anchor = 0; int except_anchor = 0; - REQ(n, try_stmt); - /* 'try' ':' suite (except_clause ':' suite)* - | 'try' ':' 'finally' ':' suite */ + int end_anchor = 0; + int else_anchor = 0; + int i; + node *ch; - /* XXX This can be simplified because except and finally can - no longer be mixed in a single try statement */ - - if (NCH(n) > 3 && TYPE(CHILD(n, NCH(n)-3)) != except_clause) { - /* Have a 'finally' clause */ - com_addfwref(c, SETUP_FINALLY, &finally_anchor); - block_push(c, SETUP_FINALLY); - } - if (NCH(n) > 3 && TYPE(CHILD(n, 3)) == except_clause) { - /* Have an 'except' clause */ - com_addfwref(c, SETUP_EXCEPT, &except_anchor); - block_push(c, SETUP_EXCEPT); - } + com_addfwref(c, SETUP_EXCEPT, &except_anchor); + block_push(c, SETUP_EXCEPT); com_node(c, CHILD(n, 2)); - if (except_anchor) { - int end_anchor = 0; - int i; - node *ch; - com_addbyte(c, POP_BLOCK); - block_pop(c, SETUP_EXCEPT); - com_addfwref(c, JUMP_FORWARD, &end_anchor); - com_backpatch(c, except_anchor); - for (i = 3; - i < NCH(n) && TYPE(ch = CHILD(n, i)) == except_clause; - i += 3) { - /* except_clause: 'except' [expr [',' expr]] */ - if (except_anchor == 0) { - err_setstr(SyntaxError, - "default 'except:' must be last"); - c->c_errors++; - 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)); - com_addoparg(c, COMPARE_OP, EXC_MATCH); - com_addfwref(c, JUMP_IF_FALSE, &except_anchor); - com_addbyte(c, POP_TOP); - } + com_addbyte(c, POP_BLOCK); + block_pop(c, SETUP_EXCEPT); + com_addfwref(c, JUMP_FORWARD, &else_anchor); + com_backpatch(c, except_anchor); + for (i = 3; + i < NCH(n) && TYPE(ch = CHILD(n, i)) == except_clause; + i += 3) { + /* except_clause: 'except' [expr [',' expr]] */ + if (except_anchor == 0) { + err_setstr(SyntaxError, + "default 'except:' must be last"); + c->c_errors++; + 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)); + com_addoparg(c, COMPARE_OP, EXC_MATCH); + com_addfwref(c, JUMP_IF_FALSE, &except_anchor); + com_addbyte(c, POP_TOP); + } + com_addbyte(c, POP_TOP); + if (NCH(ch) > 3) + com_assign(c, CHILD(ch, 3), 1/*assigning*/); + else com_addbyte(c, POP_TOP); - if (NCH(ch) > 3) - 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) { + com_backpatch(c, except_anchor); com_addbyte(c, POP_TOP); - com_node(c, CHILD(n, i+2)); - com_addfwref(c, JUMP_FORWARD, &end_anchor); - if (except_anchor) { - com_backpatch(c, except_anchor); - com_addbyte(c, POP_TOP); - } } - com_addbyte(c, END_FINALLY); - com_backpatch(c, end_anchor); - } - if (finally_anchor) { - node *ch; - com_addbyte(c, POP_BLOCK); - block_pop(c, SETUP_FINALLY); - block_push(c, END_FINALLY); - com_addoparg(c, LOAD_CONST, com_addconst(c, None)); - com_backpatch(c, finally_anchor); - ch = CHILD(n, NCH(n)-1); - com_addoparg(c, SET_LINENO, ch->n_lineno); - com_node(c, ch); - com_addbyte(c, END_FINALLY); - block_pop(c, END_FINALLY); } + com_addbyte(c, END_FINALLY); + com_backpatch(c, else_anchor); + if (i < NCH(n)) + com_node(c, CHILD(n, i+2)); + com_backpatch(c, end_anchor); +} + +static void +com_try_finally(c, n) + struct compiling *c; + node *n; +{ + int finally_anchor = 0; + node *ch; + + com_addfwref(c, SETUP_FINALLY, &finally_anchor); + block_push(c, SETUP_FINALLY); + com_node(c, CHILD(n, 2)); + com_addbyte(c, POP_BLOCK); + block_pop(c, SETUP_FINALLY); + block_push(c, END_FINALLY); + com_addoparg(c, LOAD_CONST, com_addconst(c, None)); + com_backpatch(c, finally_anchor); + ch = CHILD(n, NCH(n)-1); + com_addoparg(c, SET_LINENO, ch->n_lineno); + com_node(c, ch); + com_addbyte(c, END_FINALLY); + block_pop(c, END_FINALLY); +} + +static void +com_try_stmt(c, n) + struct compiling *c; + node *n; +{ + REQ(n, try_stmt); + /* 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite] + | 'try' ':' suite 'finally' ':' suite */ + if (TYPE(CHILD(n, 3)) != except_clause) + com_try_finally(c, n); + else + com_try_except(c, n); } static void @@ -1830,6 +1859,72 @@ com_continue_stmt(c, n) XXX if we could pop the exception still on the stack */ } +static int +com_argdefs(c, n, argcount_return) + struct compiling *c; + node *n; + int *argcount_return; +{ + int i, nch, nargs, ndefs, star; + if (TYPE(n) == lambdef) { + /* lambdef: 'lambda' [varargslist] ':' test */ + n = CHILD(n, 1); + } + else { + REQ(n, funcdef); /* funcdef: 'def' NAME parameters ... */ + n = CHILD(n, 2); + REQ(n, parameters); /* parameters: '(' [varargslist] ')' */ + n = CHILD(n, 1); + } + if (TYPE(n) != varargslist) + return -1; + /* varargslist: + (fpdef ['=' test] ',')* '*' NAME | + fpdef ['=' test] (',' fpdef ['=' test])* [','] */ + nch = NCH(n); + if (nch >= 2 && TYPE(CHILD(n, nch-2)) == STAR) { + star = 1; + nch -= 2; + } + else + star = 0; + nargs = 0; + ndefs = 0; + for (i = 0; i < nch; i++) { + int t; + nargs++; + i++; + if (i >= nch) + break; + t = TYPE(CHILD(n, i)); + if (t == EQUAL) { + i++; + ndefs++; + com_node(c, CHILD(n, i)); + i++; + if (i >= nch) + break; + t = TYPE(CHILD(n, i)); + } + else { + /* Treat "(a=1, b)" as "(a=1, b=None)" */ + if (ndefs) { + com_addoparg(c, LOAD_CONST, + com_addconst(c, None)); + ndefs++; + } + } + if (t != COMMA) + break; + } + if (star) + nargs ^= 0x4000; + *argcount_return = nargs; + if (ndefs > 0) + com_addoparg(c, BUILD_TUPLE, ndefs); + return ndefs; +} + static void com_funcdef(c, n) struct compiling *c; @@ -1842,8 +1937,12 @@ com_funcdef(c, n) c->c_errors++; else { int i = com_addconst(c, v); + int argcount; + int ndefs = com_argdefs(c, n, &argcount); com_addoparg(c, LOAD_CONST, i); com_addbyte(c, BUILD_FUNCTION); + if (ndefs > 0) + com_addoparg(c, SET_FUNC_ARGS, argcount); com_addopname(c, STORE_NAME, CHILD(n, 1)); DECREF(v); } @@ -2082,25 +2181,52 @@ com_arglist(c, n) struct compiling *c; node *n; { - int i, nargs, op; + int nch, op, nargs, i, t; REQ(n, varargslist); /* varargslist: - (fpdef ',')* '*' NAME | fpdef (',' fpdef)* [','] */ - op = UNPACK_ARG; - nargs = (NCH(n) + 1) / 2; - for (i = 0; i < NCH(n); i += 2) { - int t = TYPE(CHILD(n, i)); - if (t == STAR) { - op = UNPACK_VARARG; - nargs = i/2; + (fpdef ['=' test] ',')* '*' NAME | + fpdef ['=' test] (',' fpdef ['=' test])* [','] */ + nch = NCH(n); + if (nch >= 2 && TYPE(CHILD(n, nch-2)) == STAR) { + op = UNPACK_VARARG; + nch -= 2; + } + else + op = UNPACK_ARG; + nargs = 0; + for (i = 0; i < nch; i++) { + nargs++; + i++; + if (i >= nch) break; + t = TYPE(CHILD(n, i)); + if (t == EQUAL) { + i += 2; + if (i >= nch) + break; + t = TYPE(CHILD(n, i)); } + if (t != COMMA) + break; } com_addoparg(c, op, nargs); - for (i = 0; i < 2*nargs; i += 2) + for (i = 0; i < nch; i++) { com_fpdef(c, CHILD(n, i)); + i++; + if (i >= nch) + break; + t = TYPE(CHILD(n, i)); + if (t == EQUAL) { + i += 2; + if (i >= nch) + break; + t = TYPE(CHILD(n, i)); + } + if (t != COMMA) + break; + } if (op == UNPACK_VARARG) - com_addopname(c, STORE_NAME, CHILD(n, 2*nargs+1)); + com_addopname(c, STORE_NAME, CHILD(n, nch+1)); } static void @@ -2175,11 +2301,13 @@ compile_node(c, n) case single_input: /* One interactive command */ /* NEWLINE | simple_stmt | compound_stmt NEWLINE */ + c->c_interactive++; 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); + c->c_interactive--; break; case file_input: /* A whole file, or built-in function exec() */ @@ -2222,23 +2350,21 @@ compile_node(c, n) instructions that refer to local variables with LOAD_FAST etc. The latter instructions are much faster because they don't need to look up the variable name in a dictionary. - - To find all local variables, we check all STORE_NAME and IMPORT_FROM - instructions. This yields all local variables, including arguments, - function definitions, class definitions and import statements. - (We don't check DELETE_NAME instructions, since if there's no - STORE_NAME the DELETE_NAME will surely fail.) - - There is one problem: 'from foo import *' introduces local variables - that we can't know while compiling. If this is the case, wo don't - optimize at all (this rarely happens, since this form of import - statement is mostly used at the module level). - - Note that, because of this optimization, code like the following - won't work: - eval('x = 1') - print x - + + To find all local variables, we check all STORE_NAME, IMPORT_FROM and + DELETE_NAME instructions. This yields all local variables, including + arguments, function definitions, class definitions and import + statements. + + All remaining LOAD_NAME instructions must refer to non-local (global + or builtin) variables, so are replaced by LOAD_GLOBAL. + + There are two problems: 'from foo import *' and 'exec' may introduce + local variables that we can't know while compiling. If this is the + case, we don't optimize at all (this rarely happens, since exec is + rare, & this form of import statement is mostly used at the module + level). + NB: this modifies the string object co->co_code! */ @@ -2300,7 +2426,7 @@ optimize(c) } } - if (nlocals == 0 || dictlookup(locals, "*") != NULL) { + if (dictlookup(locals, "*") != NULL) { /* Don't optimize anything */ goto end; } @@ -2315,7 +2441,26 @@ optimize(c) if (HAS_ARG(opcode)) oparg = NEXTARG(); if (opcode == RESERVE_FAST) { - int i = com_addconst(c, locals); + int i; + object *localmap = newtupleobject(nlocals); + int pos; + object *key, *value; + if (localmap == NULL) { /* XXX mask error */ + err_clear(); + continue; + } + pos = 0; + while (mappinggetnext(locals, &pos, &key, &value)) { + int j; + if (!is_intobject(value)) + continue; + j = getintvalue(value); + if (0 <= j && j < nlocals) { + INCREF(key); + settupleitem(localmap, j, key); + } + } + i = com_addconst(c, localmap); cur_instr[1] = i & 0xff; cur_instr[2] = (i>>8) & 0xff; fast_reserved = 1; @@ -2332,6 +2477,8 @@ optimize(c) v = dict2lookup(locals, name); if (v == NULL) { err_clear(); + if (opcode == LOAD_NAME) + cur_instr[0] = LOAD_GLOBAL; continue; } i = getintvalue(v); |