📄 compile.c
字号:
if (TYPE(CHILD(n, i-1)) == CIRCUMFLEX) {
op = BINARY_XOR;
}
else {
com_error(c, PyExc_SystemError,
"com_xor_expr: operator not ^");
op = 255;
}
com_addbyte(c, op);
com_pop(c, 1);
}
}
static void
com_expr(struct compiling *c, node *n)
{
int i;
int op;
REQ(n, expr);
com_xor_expr(c, CHILD(n, 0));
for (i = 2; i < NCH(n); i += 2) {
com_xor_expr(c, CHILD(n, i));
if (TYPE(CHILD(n, i-1)) == VBAR) {
op = BINARY_OR;
}
else {
com_error(c, PyExc_SystemError,
"com_expr: expr operator not |");
op = 255;
}
com_addbyte(c, op);
com_pop(c, 1);
}
}
static enum cmp_op
cmp_type(node *n)
{
REQ(n, comp_op);
/* comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
| 'in' | 'not' 'in' | 'is' | 'is' not' */
if (NCH(n) == 1) {
n = CHILD(n, 0);
switch (TYPE(n)) {
case LESS: return LT;
case GREATER: return GT;
case EQEQUAL: /* == */
case EQUAL: return EQ;
case LESSEQUAL: return LE;
case GREATEREQUAL: return GE;
case NOTEQUAL: return NE; /* <> or != */
case NAME: if (strcmp(STR(n), "in") == 0) return IN;
if (strcmp(STR(n), "is") == 0) return IS;
}
}
else if (NCH(n) == 2) {
switch (TYPE(CHILD(n, 0))) {
case NAME: if (strcmp(STR(CHILD(n, 1)), "in") == 0)
return NOT_IN;
if (strcmp(STR(CHILD(n, 0)), "is") == 0)
return IS_NOT;
}
}
return BAD;
}
static void
com_comparison(struct compiling *c, node *n)
{
int i;
enum cmp_op op;
int anchor;
REQ(n, comparison); /* comparison: expr (comp_op expr)* */
com_expr(c, CHILD(n, 0));
if (NCH(n) == 1)
return;
/****************************************************************
The following code is generated for all but the last
comparison in a chain:
label: on stack: opcode: jump to:
a <code to load b>
a, b DUP_TOP
a, b, b ROT_THREE
b, a, b COMPARE_OP
b, 0-or-1 JUMP_IF_FALSE L1
b, 1 POP_TOP
b
We are now ready to repeat this sequence for the next
comparison in the chain.
For the last we generate:
b <code to load c>
b, c COMPARE_OP
0-or-1
If there were any jumps to L1 (i.e., there was more than one
comparison), we generate:
0-or-1 JUMP_FORWARD L2
L1: b, 0 ROT_TWO
0, b POP_TOP
0
L2: 0-or-1
****************************************************************/
anchor = 0;
for (i = 2; i < NCH(n); i += 2) {
com_expr(c, CHILD(n, i));
if (i+2 < NCH(n)) {
com_addbyte(c, DUP_TOP);
com_push(c, 1);
com_addbyte(c, ROT_THREE);
}
op = cmp_type(CHILD(n, i-1));
if (op == BAD) {
com_error(c, PyExc_SystemError,
"com_comparison: unknown comparison op");
}
com_addoparg(c, COMPARE_OP, op);
com_pop(c, 1);
if (i+2 < NCH(n)) {
com_addfwref(c, JUMP_IF_FALSE, &anchor);
com_addbyte(c, POP_TOP);
com_pop(c, 1);
}
}
if (anchor) {
int anchor2 = 0;
com_addfwref(c, JUMP_FORWARD, &anchor2);
com_backpatch(c, anchor);
com_addbyte(c, ROT_TWO);
com_addbyte(c, POP_TOP);
com_backpatch(c, anchor2);
}
}
static void
com_not_test(struct compiling *c, node *n)
{
REQ(n, not_test); /* 'not' not_test | comparison */
if (NCH(n) == 1) {
com_comparison(c, CHILD(n, 0));
}
else {
com_not_test(c, CHILD(n, 1));
com_addbyte(c, UNARY_NOT);
}
}
static void
com_and_test(struct compiling *c, node *n)
{
int i;
int anchor;
REQ(n, and_test); /* not_test ('and' not_test)* */
anchor = 0;
i = 0;
for (;;) {
com_not_test(c, CHILD(n, i));
if ((i += 2) >= NCH(n))
break;
com_addfwref(c, JUMP_IF_FALSE, &anchor);
com_addbyte(c, POP_TOP);
com_pop(c, 1);
}
if (anchor)
com_backpatch(c, anchor);
}
static int
com_make_closure(struct compiling *c, PyCodeObject *co)
{
int i, free = PyCode_GetNumFree(co);
if (free == 0)
return 0;
for (i = 0; i < free; ++i) {
/* Bypass com_addop_varname because it will generate
LOAD_DEREF but LOAD_CLOSURE is needed.
*/
PyObject *name = PyTuple_GET_ITEM(co->co_freevars, i);
int arg, reftype;
/* Special case: If a class contains a method with a
free variable that has the same name as a method,
the name will be considered free *and* local in the
class. It should be handled by the closure, as
well as by the normal name loookup logic.
*/
reftype = get_ref_type(c, PyString_AS_STRING(name));
if (reftype == CELL)
arg = com_lookup_arg(c->c_cellvars, name);
else /* (reftype == FREE) */
arg = com_lookup_arg(c->c_freevars, name);
if (arg == -1) {
fprintf(stderr, "lookup %s in %s %d %d\n"
"freevars of %s: %s\n",
PyObject_REPR(name),
c->c_name,
reftype, arg,
PyString_AS_STRING(co->co_name),
PyObject_REPR(co->co_freevars));
Py_FatalError("com_make_closure()");
}
com_addoparg(c, LOAD_CLOSURE, arg);
}
com_push(c, free);
return 1;
}
static void
com_test(struct compiling *c, node *n)
{
REQ(n, test); /* and_test ('or' and_test)* | lambdef */
if (NCH(n) == 1 && TYPE(CHILD(n, 0)) == lambdef) {
PyCodeObject *co;
int i, closure;
int ndefs = com_argdefs(c, CHILD(n, 0));
symtable_enter_scope(c->c_symtable, "lambda", lambdef,
n->n_lineno);
co = icompile(CHILD(n, 0), c);
if (co == NULL) {
c->c_errors++;
return;
}
symtable_exit_scope(c->c_symtable);
i = com_addconst(c, (PyObject *)co);
closure = com_make_closure(c, co);
com_addoparg(c, LOAD_CONST, i);
com_push(c, 1);
if (closure) {
com_addoparg(c, MAKE_CLOSURE, ndefs);
com_pop(c, PyCode_GetNumFree(co));
} else
com_addoparg(c, MAKE_FUNCTION, ndefs);
Py_DECREF(co);
com_pop(c, ndefs);
}
else {
int anchor = 0;
int i = 0;
for (;;) {
com_and_test(c, CHILD(n, i));
if ((i += 2) >= NCH(n))
break;
com_addfwref(c, JUMP_IF_TRUE, &anchor);
com_addbyte(c, POP_TOP);
com_pop(c, 1);
}
if (anchor)
com_backpatch(c, anchor);
}
}
static void
com_list(struct compiling *c, node *n, int toplevel)
{
/* exprlist: expr (',' expr)* [',']; likewise for testlist */
if (NCH(n) == 1 && !toplevel) {
com_node(c, CHILD(n, 0));
}
else {
int i;
int len;
len = (NCH(n) + 1) / 2;
for (i = 0; i < NCH(n); i += 2)
com_node(c, CHILD(n, i));
com_addoparg(c, BUILD_TUPLE, len);
com_pop(c, len-1);
}
}
/* Begin of assignment compilation */
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_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)
{
com_addopname(c, assigning ? STORE_ATTR : DELETE_ATTR, n);
com_pop(c, assigning ? 2 : 1);
}
static void
com_assign_trailer(struct compiling *c, node *n, int assigning, node *augn)
{
REQ(n, trailer);
switch (TYPE(CHILD(n, 0))) {
case LPAR: /* '(' [exprlist] ')' */
com_error(c, PyExc_SyntaxError,
"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, augn);
break;
default:
com_error(c, PyExc_SystemError, "unknown trailer type");
}
}
static void
com_assign_sequence(struct compiling *c, node *n, int assigning)
{
int i;
if (TYPE(n) != testlist && TYPE(n) != listmaker)
REQ(n, exprlist);
if (assigning) {
i = (NCH(n)+1)/2;
com_addoparg(c, UNPACK_SEQUENCE, i);
com_push(c, i-1);
}
for (i = 0; i < NCH(n); i += 2)
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_addop_varname(c, VAR_LOAD, STR(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
com_assign_name(struct compiling *c, node *n, int assigning)
{
REQ(n, NAME);
com_addop_varname(c, assigning ? VAR_STORE : VAR_DELETE, STR(n));
if (assigning)
com_pop(c, 1);
}
static void
com_assign(struct compiling *c, node *n, int assigning, node *augn)
{
/* Loop to avoid trivial recursion */
for (;;) {
switch (TYPE(n)) {
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;
}
n = CHILD(n, 0);
break;
case test:
case and_test:
case not_test:
case comparison:
case expr:
case xor_expr:
case and_expr:
case shift_expr:
case arith_expr:
case term:
case factor:
if (NCH(n) > 1) {
com_error(c, PyExc_SyntaxError,
"can't assign to operator");
return;
}
n = CHILD(n, 0);
break;
case power: /* atom trailer* ('**' power)*
('+'|'-'|'~') factor | atom trailer* */
if (TYPE(CHILD(n, 0)) != atom) {
com_error(c, PyExc_SyntaxError,
"can't assign to operator");
return;
}
if (NCH(n) > 1) { /* trailer or exponent present */
int i;
com_node(c, CHILD(n, 0));
for (i = 1; i+1 < NCH(n); i++) {
if (TYPE(CHILD(n, i)) == DOUBLESTAR) {
com_error(c, PyExc_SyntaxError,
"can't assign to operator");
return;
}
com_apply_trailer(c, CHILD(n, i));
} /* NB i is still alive */
com_assign_trailer(c,
CHILD(n, i), assigning, augn);
return;
}
n = CHILD(n, 0);
break;
case atom:
switch (TYPE(CHILD(n, 0))) {
case LPAR:
n = CHILD(n, 1);
if (TYPE(n) == RPAR) {
/* XXX Should allow () = () ??? */
com_error(c, PyExc_SyntaxError,
"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);
if (TYPE(n) == RSQB) {
com_error(c, PyExc_SyntaxError,
"can't assign to []");
return;
}
if (assigning > OP_APPLY) {
com_error(c, PyExc_SyntaxError,
"augmented assign to list not possible");
return;
}
if (NCH(n) > 1
&& TYPE(CHILD(n, 1)) == list_for) {
com_error(c, PyExc_SyntaxError,
"can't assign to list comprehension");
return;
}
com_assign_sequence(c, n, assigning);
return;
case NAME:
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,
"can't assign to literal");
return;
}
break;
case lambdef:
com_error(c, PyExc_SyntaxError,
"can't assign to lambda");
return;
default:
com_error(c, PyExc_SystemError,
"com_assign: bad node");
return;
}
}
}
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 '/':
if (STR(CHILD(CHILD(n, 1), 0))[1] == '/')
opcode = INPLACE_FLOOR_DIVIDE;
else if (c->c_flags & CO_FUTURE_DIVISION)
opcode = INPLACE_TRUE_DIVIDE;
else
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 vo
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -