summaryrefslogtreecommitdiffstats
path: root/Python/compile.c
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1991-04-04 10:42:56 (GMT)
committerGuido van Rossum <guido@python.org>1991-04-04 10:42:56 (GMT)
commit282914b7b063e278b133aba58ef4876f6210a67a (patch)
tree69845ccee5bce1ba432bd14f24b7aad0c9cdbc2c /Python/compile.c
parent572fd57b5a016060ce864646a97d7ef01a34cf54 (diff)
downloadcpython-282914b7b063e278b133aba58ef4876f6210a67a.zip
cpython-282914b7b063e278b133aba58ef4876f6210a67a.tar.gz
cpython-282914b7b063e278b133aba58ef4876f6210a67a.tar.bz2
Added error checking for numeric constants; added local/global variable
optimization.
Diffstat (limited to 'Python/compile.c')
-rw-r--r--Python/compile.c116
1 files changed, 112 insertions, 4 deletions
diff --git a/Python/compile.c b/Python/compile.c
index b61658e..9567190 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -41,6 +41,8 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <ctype.h>
+extern int errno;
+
#define OFF(x) offsetof(codeobject, x)
static struct memberlist code_memberlist[] = {
@@ -349,14 +351,28 @@ parsenumber(s)
char *s;
{
extern long strtol();
- extern double atof();
+ extern double strtod();
char *end = s;
long x;
+ double xx;
+ errno = 0;
x = strtol(s, &end, 0);
- if (*end == '\0')
+ if (*end == '\0') {
+ if (errno != 0) {
+ err_setstr(RuntimeError, "integer constant too large");
+ return NULL;
+ }
return newintobject(x);
- if (*end == '.' || *end == 'e' || *end == 'E')
- return newfloatobject(atof(s));
+ }
+ errno = 0;
+ xx = strtod(s, &end);
+ if (*end == '\0') {
+ if (errno != 0) {
+ err_setstr(RuntimeError, "float constant too large");
+ return NULL;
+ }
+ return newfloatobject(xx);
+ }
err_setstr(RuntimeError, "bad number syntax");
return NULL;
}
@@ -1752,6 +1768,96 @@ compile_node(c, n)
}
}
+/* Optimization for local and global variables.
+
+ Attempt to replace all LOAD_NAME instructions that refer to a local
+ variable with LOAD_LOCAL instructions, and all that refer to a global
+ variable with LOAD_GLOBAL instructions.
+
+ 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.
+
+ There is one leak: 'from foo import *' introduces local variables
+ that we can't know while compiling. If this is the case, LOAD_GLOBAL
+ instructions are not generated -- LOAD_NAME is left in place for
+ globals, since it first checks for globals (LOAD_LOCAL is still used
+ for recognized locals, since it doesn't hurt).
+
+ This optimization means that using the same name as a global and
+ as a local variable within the same scope is now illegal, which
+ is a change to the language! Also using eval() to introduce new
+ local variables won't work. But both were bad practice at best.
+
+ The optimization doesn't save much: basically, it saves one
+ unsuccessful dictionary lookup per global (or built-in) variable
+ reference. On the (slow!) Mac Plus, with 4 local variables,
+ this saving was measured to be about 0.18 ms. We might save more
+ by using a different data structure to hold local variables, like
+ an array indexed by variable number.
+
+ NB: this modifies the string object co->co_code!
+*/
+
+static void
+optimizer(co)
+ codeobject *co;
+{
+ char *next_instr, *cur_instr;
+ object *locals;
+ int opcode;
+ int oparg;
+ object *name;
+ int star_used;
+
+#define NEXTOP() (*next_instr++)
+#define NEXTARG() (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2])
+#define GETITEM(v, i) (getlistitem((v), (i)))
+#define GETNAMEOBJ(i) (GETITEM(co->co_names, (i)))
+
+ locals = newdictobject();
+ if (locals == NULL) {
+ err_clear();
+ return; /* For now, this is OK */
+ }
+
+ next_instr = GETSTRINGVALUE(co->co_code);
+ for (;;) {
+ opcode = NEXTOP();
+ if (opcode == STOP_CODE)
+ break;
+ if (HAS_ARG(opcode))
+ oparg = NEXTARG();
+ if (opcode == STORE_NAME || opcode == IMPORT_FROM) {
+ name = GETNAMEOBJ(oparg);
+ if (dict2insert(locals, name, None) != 0) {
+ DECREF(locals);
+ return; /* Sorry */
+ }
+ }
+ }
+
+ star_used = (dictlookup(locals, "*") != NULL);
+ next_instr = GETSTRINGVALUE(co->co_code);
+ for (;;) {
+ cur_instr = next_instr;
+ opcode = NEXTOP();
+ if (opcode == STOP_CODE)
+ break;
+ if (HAS_ARG(opcode))
+ oparg = NEXTARG();
+ if (opcode == LOAD_NAME) {
+ name = GETNAMEOBJ(oparg);
+ if (dictlookup(locals, getstringvalue(name)) != NULL)
+ *cur_instr = LOAD_LOCAL;
+ else if (!star_used)
+ *cur_instr = LOAD_GLOBAL;
+ }
+ }
+
+ DECREF(locals);
+}
+
codeobject *
compile(n, filename)
node *n;
@@ -1768,5 +1874,7 @@ compile(n, filename)
else
co = NULL;
com_free(&sc);
+ if (co != NULL)
+ optimizer(co);
return co;
}