Support for three-token characters (**=, >>=, <<=) which was written by

Michael Hudson, and support in general for the augmented assignment syntax.
The graminit.c patch is large!
This commit is contained in:
Thomas Wouters 2000-08-24 20:11:32 +00:00
parent dd8dbdb717
commit 434d0828d8
7 changed files with 1401 additions and 890 deletions

View File

@ -38,8 +38,9 @@ stmt: simple_stmt | compound_stmt
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
#small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | access_stmt | exec_stmt
small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | exec_stmt | assert_stmt
expr_stmt: testlist ('=' testlist)*
# For assignments, additional restrictions enforced by the interpreter
expr_stmt: testlist (augassign testlist | ('=' testlist)*)
augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**='
# For normal assignments, additional restrictions enforced by the interpreter
print_stmt: 'print' ( [ test (',' test)* [','] ] | '>>' test [ (',' test)+ [','] ] )
del_stmt: 'del' exprlist
pass_stmt: 'pass'

View File

@ -211,6 +211,18 @@ translabel(grammar *g, label *lb)
printf("Unknown OP label %s\n",
lb->lb_str);
}
else if (lb->lb_str[2] && lb->lb_str[3] && lb->lb_str[4] == lb->lb_str[0]) {
int type = (int) PyToken_ThreeChars(lb->lb_str[1],
lb->lb_str[2],
lb->lb_str[3]);
if (type != OP) {
lb->lb_type = type;
lb->lb_str = NULL;
}
else
printf("Unknown OP label %s\n",
lb->lb_str);
}
else
printf("Can't translate STRING label %s\n",
lb->lb_str);

View File

@ -78,6 +78,17 @@ char *_PyParser_TokenNames[] = {
"LEFTSHIFT",
"RIGHTSHIFT",
"DOUBLESTAR",
"PLUSEQUAL",
"MINEQUAL",
"STAREQUAL",
"SLASHEQUAL",
"PERCENTEQUAL",
"AMPEREQUAL",
"VBAREQUAL",
"CIRCUMFLEXEQUAL",
"LEFTSHIFTEQUAL",
"RIGHTSHIFTEQUAL",
"DOUBLESTAREQUAL",
/* This table must match the #defines in token.h! */
"OP",
"<ERRORTOKEN>",
@ -388,15 +399,91 @@ PyToken_TwoChars(int c1, int c2)
case '>': return RIGHTSHIFT;
}
break;
case '+':
switch (c2) {
case '=': return PLUSEQUAL;
}
break;
case '-':
switch (c2) {
case '=': return MINEQUAL;
}
break;
case '*':
switch (c2) {
case '*': return DOUBLESTAR;
case '=': return STAREQUAL;
}
break;
case '/':
switch (c2) {
case '=': return SLASHEQUAL;
}
break;
case '|':
switch (c2) {
case '=': return VBAREQUAL;
}
break;
case '%':
switch (c2) {
case '=': return PERCENTEQUAL;
}
break;
case '&':
switch (c2) {
case '=': return AMPEREQUAL;
}
break;
case '^':
switch (c2) {
case '=': return CIRCUMFLEXEQUAL;
}
break;
}
return OP;
}
int
PyToken_ThreeChars(int c1, int c2, int c3)
{
switch (c1) {
case '<':
switch (c2) {
case '<':
switch (c3) {
case '=':
return LEFTSHIFTEQUAL;
break;
}
break;
}
break;
case '>':
switch (c2) {
case '>':
switch (c3) {
case '=':
return RIGHTSHIFTEQUAL;
break;
}
break;
}
break;
case '*':
switch (c2) {
case '*':
switch (c3) {
case '=':
return DOUBLESTAREQUAL;
break;
}
break;
}
break;
}
return OP;
}
static int
indenterror(struct tok_state *tok)
@ -770,6 +857,13 @@ PyTokenizer_Get(register struct tok_state *tok, char **p_start,
int c2 = tok_nextc(tok);
int token = PyToken_TwoChars(c, c2);
if (token != OP) {
int c3 = tok_nextc(tok);
int token3 = PyToken_ThreeChars(c, c2, c3);
if (token3 != OP) {
token = token3;
} else {
tok_backup(tok, c3);
}
*p_start = tok->start;
*p_end = tok->cur;
return token;

View File

@ -669,12 +669,69 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
PUSH(w);
continue;
case ROT_FOUR:
u = POP();
v = POP();
w = POP();
x = POP();
PUSH(u);
PUSH(x);
PUSH(w);
PUSH(v);
continue;
case DUP_TOP:
v = TOP();
Py_INCREF(v);
PUSH(v);
continue;
case DUP_TOPX:
switch (oparg) {
case 5:
case 4:
case 3:
case 2:
case 1:
x = POP();
if (oparg == 1) break;
w = POP();
if (oparg == 2) break;
v = POP();
if (oparg == 3) break;
u = POP();
if (oparg == 4) break;
t = POP();
break;
default:
fprintf(stderr, "Invalid argument to DUP_TOPX: %d!\n", oparg);
PyErr_SetString(PyExc_SystemError,
"invalid argument to DUP_TOPX");
x = NULL;
}
if (x == NULL)
break;
switch (oparg) {
case 5: PUSH(t);
Py_INCREF(t); /* Fallthrough */
case 4: PUSH(u);
Py_INCREF(u); /* Fallthrough */
case 3: PUSH(v);
Py_INCREF(v); /* Fallthrough */
case 2: PUSH(w);
Py_INCREF(w); /* Fallthrough */
case 1: PUSH(x);
Py_INCREF(x); /* Fallthrough */
}
switch (oparg) {
case 5: PUSH(t); /* Fallthrough */
case 4: PUSH(u); /* Fallthrough */
case 3: PUSH(v); /* Fallthrough */
case 2: PUSH(w); /* Fallthrough */
case 1: PUSH(x); /* Fallthrough */
}
continue;
case UNARY_POSITIVE:
v = POP();
x = PyNumber_Positive(v);
@ -891,6 +948,146 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
if (x != NULL) continue;
break;
case INPLACE_POWER:
w = POP();
v = POP();
x = PyNumber_InPlacePower(v, w, Py_None);
Py_DECREF(v);
Py_DECREF(w);
PUSH(x);
if (x != NULL) continue;
break;
case INPLACE_MULTIPLY:
w = POP();
v = POP();
x = PyNumber_InPlaceMultiply(v, w);
Py_DECREF(v);
Py_DECREF(w);
PUSH(x);
if (x != NULL) continue;
break;
case INPLACE_DIVIDE:
w = POP();
v = POP();
x = PyNumber_InPlaceDivide(v, w);
Py_DECREF(v);
Py_DECREF(w);
PUSH(x);
if (x != NULL) continue;
break;
case INPLACE_MODULO:
w = POP();
v = POP();
x = PyNumber_InPlaceRemainder(v, w);
Py_DECREF(v);
Py_DECREF(w);
PUSH(x);
if (x != NULL) continue;
break;
case INPLACE_ADD:
w = POP();
v = POP();
if (PyInt_Check(v) && PyInt_Check(w)) {
/* INLINE: int + int */
register long a, b, i;
a = PyInt_AS_LONG(v);
b = PyInt_AS_LONG(w);
i = a + b;
if ((i^a) < 0 && (i^b) < 0) {
PyErr_SetString(PyExc_OverflowError,
"integer addition");
x = NULL;
}
else
x = PyInt_FromLong(i);
}
else
x = PyNumber_InPlaceAdd(v, w);
Py_DECREF(v);
Py_DECREF(w);
PUSH(x);
if (x != NULL) continue;
break;
case INPLACE_SUBTRACT:
w = POP();
v = POP();
if (PyInt_Check(v) && PyInt_Check(w)) {
/* INLINE: int - int */
register long a, b, i;
a = PyInt_AS_LONG(v);
b = PyInt_AS_LONG(w);
i = a - b;
if ((i^a) < 0 && (i^~b) < 0) {
PyErr_SetString(PyExc_OverflowError,
"integer subtraction");
x = NULL;
}
else
x = PyInt_FromLong(i);
}
else
x = PyNumber_InPlaceSubtract(v, w);
Py_DECREF(v);
Py_DECREF(w);
PUSH(x);
if (x != NULL) continue;
break;
case INPLACE_LSHIFT:
w = POP();
v = POP();
x = PyNumber_InPlaceLshift(v, w);
Py_DECREF(v);
Py_DECREF(w);
PUSH(x);
if (x != NULL) continue;
break;
case INPLACE_RSHIFT:
w = POP();
v = POP();
x = PyNumber_InPlaceRshift(v, w);
Py_DECREF(v);
Py_DECREF(w);
PUSH(x);
if (x != NULL) continue;
break;
case INPLACE_AND:
w = POP();
v = POP();
x = PyNumber_InPlaceAnd(v, w);
Py_DECREF(v);
Py_DECREF(w);
PUSH(x);
if (x != NULL) continue;
break;
case INPLACE_XOR:
w = POP();
v = POP();
x = PyNumber_InPlaceXor(v, w);
Py_DECREF(v);
Py_DECREF(w);
PUSH(x);
if (x != NULL) continue;
break;
case INPLACE_OR:
w = POP();
v = POP();
x = PyNumber_InPlaceOr(v, w);
Py_DECREF(v);
Py_DECREF(w);
PUSH(x);
if (x != NULL) continue;
break;
case SLICE+0:
case SLICE+1:
case SLICE+2:
@ -1063,6 +1260,10 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
stream = NULL;
break;
#ifdef CASE_TOO_BIG
default: switch (opcode) {
#endif
case BREAK_LOOP:
why = WHY_BREAK;
break;
@ -1180,10 +1381,6 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
PyErr_SetObject(PyExc_NameError, w);
break;
#ifdef CASE_TOO_BIG
default: switch (opcode) {
#endif
case UNPACK_SEQUENCE:
v = POP();
if (PyTuple_Check(v)) {

View File

@ -391,12 +391,14 @@ static void com_list(struct compiling *, node *, int);
static void com_list_iter(struct compiling *, node *, node *, char *);
static int com_argdefs(struct compiling *, node *);
static int com_newlocal(struct compiling *, char *);
static void com_assign(struct compiling *, node *, int);
static void com_assign(struct compiling *, node *, int, node *);
static void com_assign_name(struct compiling *, node *, int);
static PyCodeObject *icompile(struct _node *, struct compiling *);
static PyCodeObject *jcompile(struct _node *, char *,
struct compiling *);
static PyObject *parsestrplus(node *);
static PyObject *parsestr(char *);
static node *get_rawdocstring(node *);
static int
com_init(struct compiling *c, char *filename)
@ -995,7 +997,7 @@ com_list_for(struct compiling *c, node *n, node *e, char *t)
com_addoparg(c, SET_LINENO, n->n_lineno);
com_addfwref(c, FOR_LOOP, &anchor);
com_push(c, 1);
com_assign(c, CHILD(n, 1), OP_ASSIGN);
com_assign(c, CHILD(n, 1), OP_ASSIGN, NULL);
c->c_loops++;
com_list_iter(c, n, e, t);
c->c_loops--;
@ -1202,6 +1204,59 @@ com_slice(struct compiling *c, node *n, int op)
}
}
static void
com_augassign_slice(struct compiling *c, node *n, int opcode, node *augn)
{
if (NCH(n) == 1) {
com_addbyte(c, DUP_TOP);
com_push(c, 1);
com_addbyte(c, SLICE);
com_node(c, augn);
com_addbyte(c, opcode);
com_pop(c, 1);
com_addbyte(c, ROT_TWO);
com_addbyte(c, STORE_SLICE);
com_pop(c, 2);
} else if (NCH(n) == 2 && TYPE(CHILD(n, 0)) != COLON) {
com_node(c, CHILD(n, 0));
com_addoparg(c, DUP_TOPX, 2);
com_push(c, 2);
com_addbyte(c, SLICE+1);
com_pop(c, 1);
com_node(c, augn);
com_addbyte(c, opcode);
com_pop(c, 1);
com_addbyte(c, ROT_THREE);
com_addbyte(c, STORE_SLICE+1);
com_pop(c, 3);
} else if (NCH(n) == 2) {
com_node(c, CHILD(n, 1));
com_addoparg(c, DUP_TOPX, 2);
com_push(c, 2);
com_addbyte(c, SLICE+2);
com_pop(c, 1);
com_node(c, augn);
com_addbyte(c, opcode);
com_pop(c, 1);
com_addbyte(c, ROT_THREE);
com_addbyte(c, STORE_SLICE+2);
com_pop(c, 3);
} else {
com_node(c, CHILD(n, 0));
com_node(c, CHILD(n, 2));
com_addoparg(c, DUP_TOPX, 3);
com_push(c, 3);
com_addbyte(c, SLICE+3);
com_pop(c, 2);
com_node(c, augn);
com_addbyte(c, opcode);
com_pop(c, 1);
com_addbyte(c, ROT_FOUR);
com_addbyte(c, STORE_SLICE+3);
com_pop(c, 4);
}
}
static void
com_argument(struct compiling *c, node *n, PyObject **pkeywords)
{
@ -1376,7 +1431,7 @@ com_subscript(struct compiling *c, node *n)
}
static void
com_subscriptlist(struct compiling *c, node *n, int assigning)
com_subscriptlist(struct compiling *c, node *n, int assigning, node *augn)
{
int i, op;
REQ(n, subscriptlist);
@ -1388,11 +1443,20 @@ com_subscriptlist(struct compiling *c, node *n, int assigning)
|| (NCH(sub) > 1 && TYPE(CHILD(sub, 1)) == COLON))
&& (TYPE(CHILD(sub,NCH(sub)-1)) != sliceop))
{
if (assigning == OP_APPLY)
switch (assigning) {
case OP_DELETE:
op = DELETE_SLICE;
break;
case OP_ASSIGN:
op = STORE_SLICE;
break;
case OP_APPLY:
op = SLICE;
else
op = ((assigning == OP_ASSIGN) ?
STORE_SLICE : DELETE_SLICE);
break;
default:
com_augassign_slice(c, sub, assigning, augn);
return;
}
com_slice(c, sub, op);
if (op == STORE_SLICE)
com_pop(c, 2);
@ -1410,17 +1474,30 @@ com_subscriptlist(struct compiling *c, node *n, int assigning)
com_addoparg(c, BUILD_TUPLE, i);
com_pop(c, i-1);
}
if (assigning == OP_APPLY) {
op = BINARY_SUBSCR;
i = 1;
}
else if (assigning == OP_ASSIGN) {
op = STORE_SUBSCR;
i = 3;
}
else {
switch (assigning) {
case OP_DELETE:
op = DELETE_SUBSCR;
i = 2;
break;
default:
case OP_ASSIGN:
op = STORE_SUBSCR;
i = 3;
break;
case OP_APPLY:
op = BINARY_SUBSCR;
i = 1;
break;
}
if (assigning > OP_APPLY) {
com_addoparg(c, DUP_TOPX, 2);
com_push(c, 2);
com_addbyte(c, BINARY_SUBSCR);
com_pop(c, 1);
com_node(c, augn);
com_addbyte(c, assigning);
com_pop(c, 1);
com_addbyte(c, ROT_THREE);
}
com_addbyte(c, op);
com_pop(c, i);
@ -1438,7 +1515,7 @@ com_apply_trailer(struct compiling *c, node *n)
com_select_member(c, CHILD(n, 1));
break;
case LSQB:
com_subscriptlist(c, CHILD(n, 1), OP_APPLY);
com_subscriptlist(c, CHILD(n, 1), OP_APPLY, NULL);
break;
default:
com_error(c, PyExc_SystemError,
@ -1832,8 +1909,21 @@ com_list(struct compiling *c, node *n, int toplevel)
/* Begin of assignment compilation */
static void com_assign_name(struct compiling *, node *, int);
static void com_assign(struct compiling *, node *, int);
static void
com_augassign_attr(struct compiling *c, node *n, int opcode, node *augn)
{
com_addbyte(c, DUP_TOP);
com_push(c, 1);
com_addopname(c, LOAD_ATTR, n);
com_pop(c, 1);
com_node(c, augn);
com_addbyte(c, opcode);
com_pop(c, 1);
com_addbyte(c, ROT_TWO);
com_addopname(c, STORE_ATTR, n);
com_pop(c, 2);
}
static void
com_assign_attr(struct compiling *c, node *n, int assigning)
@ -1843,7 +1933,7 @@ com_assign_attr(struct compiling *c, node *n, int assigning)
}
static void
com_assign_trailer(struct compiling *c, node *n, int assigning)
com_assign_trailer(struct compiling *c, node *n, int assigning, node *augn)
{
REQ(n, trailer);
switch (TYPE(CHILD(n, 0))) {
@ -1852,10 +1942,13 @@ com_assign_trailer(struct compiling *c, node *n, int assigning)
"can't assign to function call");
break;
case DOT: /* '.' NAME */
if (assigning > OP_APPLY)
com_augassign_attr(c, CHILD(n, 1), assigning, augn);
else
com_assign_attr(c, CHILD(n, 1), assigning);
break;
case LSQB: /* '[' subscriptlist ']' */
com_subscriptlist(c, CHILD(n, 1), assigning);
com_subscriptlist(c, CHILD(n, 1), assigning, augn);
break;
default:
com_error(c, PyExc_SystemError, "unknown trailer type");
@ -1874,7 +1967,19 @@ com_assign_sequence(struct compiling *c, node *n, int assigning)
com_push(c, i-1);
}
for (i = 0; i < NCH(n); i += 2)
com_assign(c, CHILD(n, i), assigning);
com_assign(c, CHILD(n, i), assigning, NULL);
}
static void
com_augassign_name(struct compiling *c, node *n, int opcode, node *augn)
{
REQ(n, NAME);
com_addopname(c, LOAD_NAME, n);
com_push(c, 1);
com_node(c, augn);
com_addbyte(c, opcode);
com_pop(c, 1);
com_assign_name(c, n, OP_ASSIGN);
}
static void
@ -1887,7 +1992,7 @@ com_assign_name(struct compiling *c, node *n, int assigning)
}
static void
com_assign(struct compiling *c, node *n, int assigning)
com_assign(struct compiling *c, node *n, int assigning, node *augn)
{
/* Loop to avoid trivial recursion */
for (;;) {
@ -1896,6 +2001,11 @@ com_assign(struct compiling *c, node *n, int assigning)
case exprlist:
case testlist:
if (NCH(n) > 1) {
if (assigning > OP_APPLY) {
com_error(c, PyExc_SyntaxError,
"augmented assign to tuple not possible");
return;
}
com_assign_sequence(c, n, assigning);
return;
}
@ -1940,7 +2050,7 @@ com_assign(struct compiling *c, node *n, int assigning)
com_apply_trailer(c, CHILD(n, i));
} /* NB i is still alive */
com_assign_trailer(c,
CHILD(n, i), assigning);
CHILD(n, i), assigning, augn);
return;
}
n = CHILD(n, 0);
@ -1956,6 +2066,11 @@ com_assign(struct compiling *c, node *n, int assigning)
"can't assign to ()");
return;
}
if (assigning > OP_APPLY) {
com_error(c, PyExc_SyntaxError,
"augmented assign to tuple not possible");
return;
}
break;
case LSQB:
n = CHILD(n, 1);
@ -1964,10 +2079,20 @@ com_assign(struct compiling *c, node *n, int assigning)
"can't assign to []");
return;
}
if (assigning > OP_APPLY) {
com_error(c, PyExc_SyntaxError,
"augmented assign to list not possible");
return;
}
com_assign_sequence(c, n, assigning);
return;
case NAME:
com_assign_name(c, CHILD(n, 0), assigning);
if (assigning > OP_APPLY)
com_augassign_name(c, CHILD(n, 0),
assigning, augn);
else
com_assign_name(c, CHILD(n, 0),
assigning);
return;
default:
com_error(c, PyExc_SyntaxError,
@ -1991,31 +2116,61 @@ com_assign(struct compiling *c, node *n, int assigning)
}
}
/* Forward */ static node *get_rawdocstring(node *);
static void
com_augassign(struct compiling *c, node *n)
{
int opcode;
switch (STR(CHILD(CHILD(n, 1), 0))[0]) {
case '+': opcode = INPLACE_ADD; break;
case '-': opcode = INPLACE_SUBTRACT; break;
case '/': opcode = INPLACE_DIVIDE; break;
case '%': opcode = INPLACE_MODULO; break;
case '<': opcode = INPLACE_LSHIFT; break;
case '>': opcode = INPLACE_RSHIFT; break;
case '&': opcode = INPLACE_AND; break;
case '^': opcode = INPLACE_XOR; break;
case '|': opcode = INPLACE_OR; break;
case '*':
if (STR(CHILD(CHILD(n, 1), 0))[1] == '*')
opcode = INPLACE_POWER;
else
opcode = INPLACE_MULTIPLY;
break;
default:
com_error(c, PyExc_SystemError, "com_augassign: bad operator");
return;
}
com_assign(c, CHILD(n, 0), opcode, CHILD(n, 2));
}
static void
com_expr_stmt(struct compiling *c, node *n)
{
REQ(n, expr_stmt); /* testlist ('=' testlist)* */
REQ(n, expr_stmt);
/* testlist (('=' testlist)* | augassign testlist) */
/* Forget it if we have just a doc string here */
if (!c->c_interactive && NCH(n) == 1 && get_rawdocstring(n) != NULL)
return;
com_node(c, CHILD(n, NCH(n)-1));
if (NCH(n) == 1) {
com_node(c, CHILD(n, NCH(n)-1));
if (c->c_interactive)
com_addbyte(c, PRINT_EXPR);
else
com_addbyte(c, POP_TOP);
com_pop(c, 1);
}
else if (TYPE(CHILD(n,1)) == augassign)
com_augassign(c, n);
else {
int i;
com_node(c, CHILD(n, NCH(n)-1));
for (i = 0; i < NCH(n)-2; i+=2) {
if (i+2 < NCH(n)-2) {
com_addbyte(c, DUP_TOP);
com_push(c, 1);
}
com_assign(c, CHILD(n, i), OP_ASSIGN);
com_assign(c, CHILD(n, i), OP_ASSIGN, NULL);
}
}
}
@ -2472,7 +2627,7 @@ com_for_stmt(struct compiling *c, node *n)
com_addoparg(c, SET_LINENO, n->n_lineno);
com_addfwref(c, FOR_LOOP, &anchor);
com_push(c, 1);
com_assign(c, CHILD(n, 1), OP_ASSIGN);
com_assign(c, CHILD(n, 1), OP_ASSIGN, NULL);
c->c_loops++;
com_node(c, CHILD(n, 5));
c->c_loops--;
@ -2594,7 +2749,7 @@ com_try_except(struct compiling *c, node *n)
com_addbyte(c, POP_TOP);
com_pop(c, 1);
if (NCH(ch) > 3)
com_assign(c, CHILD(ch, 3), OP_ASSIGN);
com_assign(c, CHILD(ch, 3), OP_ASSIGN, NULL);
else {
com_addbyte(c, POP_TOP);
com_pop(c, 1);
@ -2940,7 +3095,7 @@ com_node(struct compiling *c, node *n)
com_print_stmt(c, n);
break;
case del_stmt: /* 'del' exprlist */
com_assign(c, CHILD(n, 1), OP_DELETE);
com_assign(c, CHILD(n, 1), OP_DELETE, NULL);
break;
case pass_stmt:
break;

File diff suppressed because it is too large Load Diff

View File

@ -66,7 +66,7 @@ extern time_t PyOS_GetLastModificationTime(char *, FILE *);
/* XXX Perhaps the magic number should be frozen and a version field
added to the .pyc file header? */
/* New way to come up with the magic number: (YEAR-1995), MONTH, DAY */
#define MAGIC (50821 | ((long)'\r'<<16) | ((long)'\n'<<24))
#define MAGIC (50822 | ((long)'\r'<<16) | ((long)'\n'<<24))
/* Magic word as global; note that _PyImport_Init() can change the
value of this global to accommodate for alterations of how the