state->try_depth--;
DECR_TRY_DEPTH(state);
generate_expr(Expr * expr, State * state){    switch (expr->kind) {    case EXPR_VAR:	{	    Var v;	    v = expr->e.var;	    if (v.type == TYPE_INT && IN_OPTIM_NUM_RANGE(v.v.num))		emit_byte(OPTIM_NUM_TO_OPCODE(v.v.num), state);	    else {		emit_byte(OP_IMM, state);		add_literal(v, state);	    }	    push_stack(1, state);	}	break;    case EXPR_ID:	emit_var_op(OP_PUSH, expr->e.id, state);	push_stack(1, state);	break;    case EXPR_AND:    case EXPR_OR:	{	    int end_label;	    generate_expr(expr->e.bin.lhs, state);	    emit_byte(expr->kind == EXPR_AND ? OP_AND : OP_OR, state);	    end_label = add_label(state);	    pop_stack(1, state);	    generate_expr(expr->e.bin.rhs, state);	    define_label(end_label, state);	}	break;    case EXPR_NEGATE:    case EXPR_NOT:	generate_expr(expr->e.expr, state);	emit_byte(expr->kind == EXPR_NOT ? OP_NOT : OP_UNARY_MINUS, state);	break;    case EXPR_EQ:    case EXPR_NE:    case EXPR_GE:    case EXPR_GT:    case EXPR_LE:    case EXPR_LT:    case EXPR_IN:    case EXPR_PLUS:    case EXPR_MINUS:    case EXPR_TIMES:    case EXPR_DIVIDE:    case EXPR_MOD:    case EXPR_PROP:	{	    Opcode op = OP_ADD;	/* initialize to silence warning */	    generate_expr(expr->e.bin.lhs, state);	    generate_expr(expr->e.bin.rhs, state);	    switch (expr->kind) {	    case EXPR_EQ:		op = OP_EQ;		break;	    case EXPR_NE:		op = OP_NE;		break;	    case EXPR_GE:		op = OP_GE;		break;	    case EXPR_GT:		op = OP_GT;		break;	    case EXPR_LE:		op = OP_LE;		break;	    case EXPR_LT:		op = OP_LT;		break;	    case EXPR_IN:		op = OP_IN;		break;	    case EXPR_PLUS:		op = OP_ADD;		break;	    case EXPR_MINUS:		op = OP_MINUS;		break;	    case EXPR_TIMES:		op = OP_MULT;		break;	    case EXPR_DIVIDE:		op = OP_DIV;		break;	    case EXPR_MOD:		op = OP_MOD;		break;	    case EXPR_PROP:		op = OP_GET_PROP;		break;	    case EXPR_INDEX:		op = OP_REF;		break;	    default:		panic("Not a binary operator in GENERATE_EXPR()");	    }	    emit_byte(op, state);	    pop_stack(1, state);	}	break;    case EXPR_EXP:	generate_expr(expr->e.bin.lhs, state);	generate_expr(expr->e.bin.rhs, state);	emit_extended_byte(EOP_EXP, state);	pop_stack(1, state);	break;    case EXPR_INDEX:	{	    unsigned old;	    generate_expr(expr->e.bin.lhs, state);	    old = save_stack_top(state);	    generate_expr(expr->e.bin.rhs, state);	    restore_stack_top(old, state);	    emit_byte(OP_REF, state);	    pop_stack(1, state);	}	break;    case EXPR_RANGE:	{	    unsigned old;	    generate_expr(expr->e.range.base, state);	    old = save_stack_top(state);	    generate_expr(expr->e.range.from, state);	    generate_expr(expr->e.range.to, state);	    restore_stack_top(old, state);	    emit_byte(OP_RANGE_REF, state);	    pop_stack(2, state);	}	break;    case EXPR_LENGTH:	{	    unsigned saved = saved_stack_top(state);	    if (saved != UINT_MAX) {		emit_extended_byte(EOP_LENGTH, state);		add_stack_ref(saved, state);		push_stack(1, state);	    } else		panic("Missing saved stack for `$' in GENERATE_EXPR()");	}	break;    case EXPR_LIST:	generate_arg_list(expr->e.list, state);	break;    case EXPR_CALL:	generate_arg_list(expr->e.call.args, state);	emit_byte(OP_BI_FUNC_CALL, state);	emit_byte(expr->e.call.func, state);	break;    case EXPR_VERB:	generate_expr(expr->e.verb.obj, state);	generate_expr(expr->e.verb.verb, state);	generate_arg_list(expr->e.verb.args, state);	emit_byte(OP_CALL_VERB, state);	pop_stack(2, state);	break;    case EXPR_COND:	{	    int else_label, end_label;	    generate_expr(expr->e.cond.condition, state);	    emit_byte(OP_IF_QUES, state);	    else_label = add_label(state);	    pop_stack(1, state);	    generate_expr(expr->e.cond.consequent, state);	    emit_byte(OP_JUMP, state);	    end_label = add_label(state);	    pop_stack(1, state);	    define_label(else_label, state);	    generate_expr(expr->e.cond.alternate, state);	    define_label(end_label, state);	}	break;    case EXPR_ASGN:	{	    Expr *e = expr->e.bin.lhs;	    if (e->kind == EXPR_SCATTER) {		int nargs = 0, nreq = 0, rest = -1;		unsigned done;		Scatter *sc;		generate_expr(expr->e.bin.rhs, state);		for (sc = e->e.scatter; sc; sc = sc->next) {		    nargs++;		    if (sc->kind == SCAT_REQUIRED)			nreq++;		    else if (sc->kind == SCAT_REST)			rest = nargs;		}		if (rest == -1)		    rest = nargs + 1;		emit_extended_byte(EOP_SCATTER, state);		emit_byte(nargs, state);		emit_byte(nreq, state);		emit_byte(rest, state);		for (sc = e->e.scatter; sc; sc = sc->next) {		    add_var_ref(sc->id, state);		    if (sc->kind != SCAT_OPTIONAL)			add_pseudo_label(0, state);		    else if (!sc->expr)			add_pseudo_label(1, state);		    else			sc->label = add_label(state);		}		done = add_label(state);		for (sc = e->e.scatter; sc; sc = sc->next)		    if (sc->kind == SCAT_OPTIONAL && sc->expr) {			define_label(sc->label, state);			generate_expr(sc->expr, state);			emit_var_op(OP_PUT, sc->id, state);			emit_byte(OP_POP, state);			pop_stack(1, state);		    }		define_label(done, state);	    } else {		int is_indexed = 0;		push_lvalue(e, 0, state);		generate_expr(expr->e.bin.rhs, state);		if (e->kind == EXPR_RANGE || e->kind == EXPR_INDEX)		    emit_byte(OP_PUT_TEMP, state);		while (1) {		    switch (e->kind) {		    case EXPR_RANGE:			emit_extended_byte(EOP_RANGESET, state);			pop_stack(3, state);			e = e->e.range.base;			is_indexed = 1;			continue;		    case EXPR_INDEX:			emit_byte(OP_INDEXSET, state);			pop_stack(2, state);			e = e->e.bin.lhs;			is_indexed = 1;			continue;		    case EXPR_ID:			emit_var_op(OP_PUT, e->e.id, state);			break;		    case EXPR_PROP:			emit_byte(OP_PUT_PROP, state);			pop_stack(2, state);			break;		    default:			panic("Bad lvalue in GENERATE_EXPR()");		    }		    break;		}		if (is_indexed) {		    emit_byte(OP_POP, state);		    emit_byte(OP_PUSH_TEMP, state);		}	    }	}	break;    case EXPR_CATCH:	{	    int handler_label, end_label;	    generate_codes(expr->e.catch.codes, state);	    emit_extended_byte(EOP_PUSH_LABEL, state);	    handler_label = add_label(state);	    push_stack(1, state);	    emit_extended_byte(EOP_CATCH, state);	    push_stack(1, state);	    state->try_depth++;	    generate_expr(expr->e.expr, state);	    state->try_depth--;	    emit_extended_byte(EOP_END_CATCH, state);	    end_label = add_label(state);	    pop_stack(3, state);	/* codes, label, catch */	    define_label(handler_label, state);	    /* After this label, we still have a value on the stack, but now,	     * instead of it being the value of the main expression, we have	     * the exception tuple pushed before entering the handler.	     */	    if (expr->e.catch.except) {		emit_byte(OP_POP, state);		pop_stack(1, state);		generate_expr(expr->e.catch.except, state);	    } else {		/* Select code from tuple */		emit_byte(OPTIM_NUM_TO_OPCODE(1), state);		emit_byte(OP_REF, state);	    }	    define_label(end_label, state);	}	break;    default:	panic("Can't happen in GENERATE_EXPR()");    }}