Exemplo n.º 1
0
PyObject *
PyNumber_Multiply(PyObject *v, PyObject *w)
{
	PyTypeObject *tp = v->ob_type;
	PySequenceMethods *m;

	BINOP(v, w, "__mul__", "__rmul__", PyNumber_Multiply);
	if (tp->tp_as_number != NULL &&
	    w->ob_type->tp_as_sequence != NULL &&
	    !PyInstance_Check(v)) {
		/* number*sequence -- swap v and w */
		PyObject *tmp = v;
		v = w;
		w = tmp;
		tp = v->ob_type;
	}
	if (tp->tp_as_number != NULL) {
		PyObject *x = NULL;
		PyObject * (*f)(PyObject *, PyObject *);
		if (PyInstance_Check(v)) {
			/* Instances of user-defined classes get their
			   other argument uncoerced, so they may
			   implement sequence*number as well as
			   number*number. */
			Py_INCREF(v);
			Py_INCREF(w);
		}
		else if (PyNumber_Coerce(&v, &w) != 0)
			return NULL;
		if ((f = v->ob_type->tp_as_number->nb_multiply) != NULL)
			x = (*f)(v, w);
		Py_DECREF(v);
		Py_DECREF(w);
		if (f != NULL)
			return x;
	}
	m = tp->tp_as_sequence;
	if (m && m->sq_repeat) {
		long mul_value;

		if (PyInt_Check(w)) {
			mul_value = PyInt_AsLong(w);
		}
		else if (PyLong_Check(w)) {
			mul_value = PyLong_AsLong(w);
			if (mul_value == -1 && PyErr_Occurred())
                                return NULL; 
		}
		else {
			return type_error(
				"can't multiply sequence with non-int");
		}
		return (*m->sq_repeat)(v, (int)mul_value);
	}
	return type_error("bad operand type(s) for *");
}
Exemplo n.º 2
0
PyObject *
PyNumber_Divmod(PyObject *v, PyObject *w)
{
	BINOP(v, w, "__divmod__", "__rdivmod__", PyNumber_Divmod);
	if (v->ob_type->tp_as_number != NULL) {
		PyObject *x = NULL;
		PyObject * (*f)(PyObject *, PyObject *);
		if (PyNumber_Coerce(&v, &w) != 0)
			return NULL;
		if ((f = v->ob_type->tp_as_number->nb_divmod) != NULL)
			x = (*f)(v, w);
		Py_DECREF(v);
		Py_DECREF(w);
		if (f != NULL)
			return x;
	}
	return type_error("bad operand type(s) for divmod()");
}
Exemplo n.º 3
0
static PyObject *
do_pow(PyObject *v, PyObject *w)
{
	PyObject *res;
	PyObject * (*f)(PyObject *, PyObject *, PyObject *);
	BINOP(v, w, "__pow__", "__rpow__", do_pow);
	if (v->ob_type->tp_as_number == NULL ||
	    w->ob_type->tp_as_number == NULL) {
		PyErr_SetString(PyExc_TypeError,
				"pow(x, y) requires numeric arguments");
		return NULL;
	}
	if (PyNumber_Coerce(&v, &w) != 0)
		return NULL;
	if ((f = v->ob_type->tp_as_number->nb_power) != NULL)
		res = (*f)(v, w, Py_None);
	else
		res = type_error("pow(x, y) not defined for these operands");
	Py_DECREF(v);
	Py_DECREF(w);
	return res;
}
Exemplo n.º 4
0
PyObject *
PyNumber_Remainder(PyObject *v, PyObject *w)
{
	if (PyString_Check(v))
		return PyString_Format(v, w);
	else if (PyUnicode_Check(v))
		return PyUnicode_Format(v, w);
	BINOP(v, w, "__mod__", "__rmod__", PyNumber_Remainder);
	if (v->ob_type->tp_as_number != NULL) {
		PyObject *x = NULL;
		PyObject * (*f)(PyObject *, PyObject *);
		if (PyNumber_Coerce(&v, &w) != 0)
			return NULL;
		if ((f = v->ob_type->tp_as_number->nb_remainder) != NULL)
			x = (*f)(v, w);
		Py_DECREF(v);
		Py_DECREF(w);
		if (f != NULL)
			return x;
	}
	return type_error("bad operand type(s) for %");
}
Exemplo n.º 5
0
PyObject *
PyNumber_Add(PyObject *v, PyObject *w)
{
	PySequenceMethods *m;

	BINOP(v, w, "__add__", "__radd__", PyNumber_Add);
	m = v->ob_type->tp_as_sequence;
	if (m && m->sq_concat)
		return (*m->sq_concat)(v, w);
	else if (v->ob_type->tp_as_number != NULL) {
		PyObject *x = NULL;
		PyObject * (*f)(PyObject *, PyObject *);
		if (PyNumber_Coerce(&v, &w) != 0)
			return NULL;
		if ((f = v->ob_type->tp_as_number->nb_add) != NULL)
			x = (*f)(v, w);
		Py_DECREF(v);
		Py_DECREF(w);
		if (f != NULL)
			return x;
	}
	return type_error("bad operand type(s) for +");
}
Exemplo n.º 6
0
void GMachine::execute(GEnvironment& environment)
{
	const std::vector<GInstruction>& code = environment.combinator->instructions;
	StackFrame<Address>& stack = environment.stack;

	for (size_t index = 0; index < code.size(); index++)
	{
		const GInstruction& instruction = code[index];
		switch (instruction.op)
		{
		case GOP::ALLOC:
			{
				for (int i = 0; i < instruction.value; i++)
				{
					heap.push_back(Node(nullptr));
					environment.stack.push(Address::indirection(&heap.back()));
				}
			}
			break;
		case GOP::EVAL:
			{
				static SuperCombinator unwind { "__uniwnd", Type(), 0, std::vector<GInstruction>{ GInstruction(GOP::UNWIND) } };
				GEnvironment child = environment.child(&unwind);
				child.stack.push(environment.stack.top());
				execute(child);
				environment.stack.top() = child.stack.top();
			}
			break;
		case GOP::MKAP:
			{
				Address func = environment.stack.top();
				environment.stack.pop();
				Address arg = environment.stack.top();
				heap.push_back(Node(func, arg));
				environment.stack.top() = Address::application(&heap.back());
			}
			break;
		case GOP::PACK:
			{
				int tag = instruction.value & (0xFFFF);//Low two bytes
				int arity = instruction.value >> 16;//High two bytes
				heap.push_back(Node(tag, new Address[arity+1]));
				Node& ctor = heap.back();
				for (int ii = 0; ii < arity; ii++)
				{
					ctor.constructor.arguments[ii] = stack.pop();
				}
				ctor.constructor.arguments[arity + 1] = Address::indirection(nullptr);//Use as end of this constructor
				stack.push(Address::constructor(&ctor));
			}
			break;
		case GOP::SPLIT:
			{
				Address top = stack.pop();
				assert(top.getType() == CONSTRUCTOR);
				ConstructorNode& ctor = top.getNode()->constructor;
				for (int ii = 0; ii < instruction.value; ii++)
				{
					assert(ctor.arguments[ii].getType() != NodeType::INDIRECTION || ctor.arguments[ii].getNode() != nullptr);
					stack.push(ctor.arguments[ii]);
				}
			}
			break;
		case GOP::CASEJUMP:
			{
				Address top = stack.top();
				assert(top.getType() == CONSTRUCTOR);
				ConstructorNode& ctor = top.getNode()->constructor;
				if (ctor.tag != instruction.value)
					index++;//Skip the next instruction which is the jump instruction
			}
			break;
		case GOP::JUMP:
			index = instruction.value - 1;
			break;
		case GOP::POP:
			for (int i = 0; i < instruction.value; i++)
			{
				environment.stack.pop();
			}
			break;
		case GOP::PUSH:
			{
				Address addr = environment.stack[instruction.value];
				environment.stack.push(addr);
			}
			break;
		case GOP::PUSH_DICTIONARY_MEMBER:
			{
				assert(stack.base().getType() == NodeType::CONSTRUCTOR);//Must be instance dictionary
				ConstructorNode& ctor = stack.base().getNode()->constructor;
				Address& func = ctor.arguments[instruction.value];
				stack.push(func);
			}
			break;
		case GOP::PUSH_GLOBAL:
			{
				Address addr = globals.at(instruction.value);
				environment.stack.push(addr);
			}
			break;
		case GOP::PUSH_INT:
			{
				heap.push_back(Node(instruction.value));
				environment.stack.push(Address::number(&heap.back()));
			}
			break;
		case GOP::PUSH_DOUBLE:
			{
				heap.push_back(Node(instruction.doubleValue));
				environment.stack.push(Address::numberDouble(&heap.back()));
			}
			break;
		case GOP::SLIDE:
			{
				slide(environment, instruction);
			}
			break;
		case GOP::UNWIND:
			{
				Address top = environment.stack.top();
				switch (top.getType())
				{
				case NUMBER:
					break;
				case APPLICATION:
					{
						Node& n = *top.getNode();
						environment.stack.push(n.apply.func);
						--index;//Redo the unwind instruction
					}
					break;
				case FUNCTION_POINTER:
					{
						int arity = top.getNode()->function.args;
						if (stack.stackSize() - 1 < size_t(arity))
						{
							while (stack.stackSize() > 1)
							{
								stack.pop();
							}
						}
						else
						{
							size_t ii = environment.stack.stackSize() - arity - 1;
							for (; ii < environment.stack.stackSize() - 1; ii++)
							{
								Address& addr = environment.stack[ii];
								assert(addr.getType() == APPLICATION);
								addr = addr.getNode()->apply.arg;
							}
							t_ffi_func func = top.getNode()->function.ptr;
							assert(func != nullptr);
							StackFrame<Address> newStack = stack.makeChildFrame(arity + 1);
							func(this, &newStack);
							Address result = newStack.top();
							for (int i = 0; i < arity; i++)
								environment.stack.pop();
							environment.stack.push(result);
						}
					}
					break;
				case GLOBAL:
					{
						SuperCombinator* comb = top.getNode()->global;
						if (environment.stack.stackSize() - 1 < size_t(comb->arity))
						{
							while (stack.stackSize() > 1)
							{
								stack.pop();
							}
						}
						else
						{
							//Before calling the function, replace all applications on the stack with the actual arguments
							//This gives faster access to a functions arguments when using PUSH
							size_t ii = environment.stack.stackSize() - comb->arity - 1;
							for (; ii < environment.stack.stackSize() - 1; ii++)
							{
								Address& addr = environment.stack[ii];
								assert(addr.getType() == APPLICATION);
								addr = addr.getNode()->apply.arg;
							}

							GEnvironment child = environment.child(comb);
							if (debug)
							{
								std::cerr << "Executing function '" << comb->name << "'" << std::endl;
								std::cerr << "Arguments { ";
								for (size_t i = 0; i < child.stack.stackSize(); i++)
								{
									std::cerr << child.stack[i];
								}
								std::cerr << " }" << std::endl;
							}
							execute(child);
							Address result = child.stack.top();
							for (int i = 0; i < comb->arity; i++)
								environment.stack.pop();
							environment.stack.push(result);
						}
					}
					break;
				case INDIRECTION:
					{
						environment.stack.top() = top.getNode()->indirection;
						--index;//Redo the unwind instruction
					}
					break;
				default:
					break;
				}
			}
			break;
		case GOP::UPDATE:
			{
				Address top = environment.stack.top();
				heap.push_back(Node(top));
				environment.stack[instruction.value] = Address::indirection(&heap.back());
			}
			break;
#define BINOP2(op, opname) \
		case GOP:: opname:\
			{\
			Address rhs = environment.stack.pop(); \
			Address lhs = environment.stack.top(); \
			int result = lhs.getNode()->number op rhs.getNode()->number; \
			heap.push_back(Node(result)); \
			environment.stack.top() = Address::number(&heap.back()); \
			}\
            break;
#define BINOP(f, name) case GOP:: name: binopInt<f>(environment, heap); break;

			BINOP(add<int>, ADD)
			BINOP(subtract<int>, SUBTRACT)
			BINOP(multiply<int>, MULTIPLY)
			BINOP(divide<int>, DIVIDE)
			BINOP(remainder<int>, REMAINDER)
			
#define BINOP_DOUBLE(f, name) case GOP:: name: binopDouble<f>(environment, heap); break;

			BINOP_DOUBLE(add<double>, ADD_DOUBLE)
			BINOP_DOUBLE(subtract<double>, SUBTRACT_DOUBLE)
			BINOP_DOUBLE(multiply<double>, MULTIPLY_DOUBLE)
			BINOP_DOUBLE(divide<double>, DIVIDE_DOUBLE)

#undef BINOP_DOUBLE
		case GOP::NEGATE:
			{
				Address x = environment.stack.top();
				heap.push_back(Node(-x.getNode()->number));
				environment.stack.top() = Address::number(&heap.back());
			}
			break;

			BINOP2(== , COMPARE_EQ)
			BINOP2(!= , COMPARE_NEQ)
			BINOP2(> , COMPARE_GT)
			BINOP2(>=, COMPARE_GE)
			BINOP2(< , COMPARE_LT)
			BINOP2(<=, COMPARE_LE)

#undef BINOP
#undef BINOP2

		default:
			std::cout << "Unimplemented instruction " << int(code[index].op) << std::endl;
			break;
		}
	}
	if (debug)
	{
		std::cerr << "Returning '" << stack.top() << "' from '" << environment.combinator->name << "'" << std::endl;
	}
}
Exemplo n.º 7
0
/* Build various compound expressions, and verify that they have sane debug
   strings.  */
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
  /* Make a singly-linked list type:
      struct node
      {
       struct node *next;
       int value;
      };
  */
  gcc_jit_type *t_int =
    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
  gcc_jit_struct *t_node =
    gcc_jit_context_new_opaque_struct (ctxt, NULL, "node");
  gcc_jit_type *t_node_ptr =
    gcc_jit_type_get_pointer (gcc_jit_struct_as_type (t_node));
  gcc_jit_field *f_next =
    gcc_jit_context_new_field (ctxt, NULL, t_node_ptr, "next");
  gcc_jit_field *f_value =
    gcc_jit_context_new_field (ctxt, NULL, t_int, "value");
  gcc_jit_field *fields[] = {f_next, f_value};
  gcc_jit_struct_set_fields (t_node, NULL, 2, fields);

  /* Create a dummy function so that we have locals/params to build
     expressions with.  */
  gcc_jit_type *t_void =
    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
  gcc_jit_function *fn =
    gcc_jit_context_new_function (ctxt, NULL,
				  GCC_JIT_FUNCTION_EXPORTED,
				  t_void,
				  "test_debug_strings",
				  0, NULL, 0);
  gcc_jit_rvalue *ptr =
    gcc_jit_lvalue_as_rvalue (
      gcc_jit_function_new_local (fn,
				  NULL,
				  t_node_ptr,
				  "ptr"));
  gcc_jit_rvalue *a =
    gcc_jit_lvalue_as_rvalue (
      gcc_jit_function_new_local (fn, NULL, t_int, "a"));
  gcc_jit_rvalue *b =
    gcc_jit_lvalue_as_rvalue (
      gcc_jit_function_new_local (fn, NULL, t_int, "b"));
  gcc_jit_rvalue *c =
    gcc_jit_lvalue_as_rvalue (
      gcc_jit_function_new_local (fn, NULL, t_int, "c"));
  gcc_jit_rvalue *d =
    gcc_jit_lvalue_as_rvalue (
      gcc_jit_function_new_local (fn, NULL, t_int, "d"));

#define CHECK_RVALUE_DEBUG_STRING(RVALUE, EXPECTED) \
  CHECK_STRING_VALUE ( \
    gcc_jit_object_get_debug_string (gcc_jit_rvalue_as_object (RVALUE)), \
    (EXPECTED))

#define CHECK_LVALUE_DEBUG_STRING(LVALUE, EXPECTED) \
  CHECK_STRING_VALUE ( \
    gcc_jit_object_get_debug_string (gcc_jit_lvalue_as_object (LVALUE)), \
    (EXPECTED))

  /* Verify various simple compound expressions.  */
  {
    CHECK_RVALUE_DEBUG_STRING (ptr, "ptr");

    gcc_jit_lvalue *deref =
      gcc_jit_rvalue_dereference_field (ptr,
					NULL,
					f_value);
    CHECK_LVALUE_DEBUG_STRING (deref, "ptr->value");

    gcc_jit_rvalue *deref_as_rvalue = gcc_jit_lvalue_as_rvalue (deref);

#define BINOP(OP, A, B) \
    gcc_jit_context_new_binary_op (ctxt, NULL, \
				   GCC_JIT_BINARY_OP_##OP, t_int, (A), (B))
#define COMPARISON(OP, A, B) \
    gcc_jit_context_new_comparison (ctxt, NULL, \
				    GCC_JIT_COMPARISON_##OP,(A), (B))

    CHECK_RVALUE_DEBUG_STRING (
      BINOP (PLUS, deref_as_rvalue, deref_as_rvalue),
      "ptr->value + ptr->value");
    CHECK_RVALUE_DEBUG_STRING (
      BINOP (MULT, deref_as_rvalue, deref_as_rvalue),
      "ptr->value * ptr->value");

   /* Multiplication has higher precedence in C than addition, so this
       dump shouldn't contain parentheses.  */
    CHECK_RVALUE_DEBUG_STRING (
      BINOP (PLUS,
	     BINOP (MULT, a, b),
	     BINOP (MULT, c, d)),
      "a * b + c * d");

    /* ...but this one should.  */
    CHECK_RVALUE_DEBUG_STRING (
      BINOP (MULT,
	     BINOP (PLUS, a, b),
	     BINOP (PLUS, c, d)),
      "(a + b) * (c + d)");

    /* Equal precedences don't need parentheses.  */
    CHECK_RVALUE_DEBUG_STRING (
      BINOP (MULT,
	     BINOP (MULT, a, b),
	     BINOP (MULT, c, d)),
      "a * b * c * d");

    /* Comparisons and logical ops.  */
    CHECK_RVALUE_DEBUG_STRING (
      COMPARISON (LT, a, b),
      "a < b");

    CHECK_RVALUE_DEBUG_STRING (
      BINOP (LOGICAL_AND,
	     COMPARISON (LT, a, b),
	     COMPARISON (GT, c, d)),
      "a < b && c > d");

    CHECK_RVALUE_DEBUG_STRING (
      BINOP (LOGICAL_AND,
	     BINOP (LOGICAL_OR,
		    COMPARISON (LT, a, b),
		    COMPARISON (LT, a, c)),
	     BINOP (LOGICAL_OR,
		    COMPARISON (GT, d, b),
		    COMPARISON (GT, d, c))),
      "(a < b || a < c) && (d > b || d > c)");

    CHECK_RVALUE_DEBUG_STRING (
      BINOP (LOGICAL_OR,
	     BINOP (LOGICAL_AND,
		    COMPARISON (LT, a, b),
		    COMPARISON (LT, a, c)),
	     BINOP (LOGICAL_AND,
		    COMPARISON (GT, d, b),
		    COMPARISON (GT, d, c))),
      "a < b && a < c || d > b && d > c");

#undef BINOP
#undef COMPARISON
  }

  /* PR jit/66539 "Missing parentheses in jit dumps".
     Construct the equivalent of
       ((cast)ptr->next)->next
     and verify that the appropriate parentheses appear in the debug
     string.   */
  {
    /* "ptr->next". */
    gcc_jit_lvalue *inner_deref =
      gcc_jit_rvalue_dereference_field (ptr,
					NULL,
					f_next);
    /* "((node *)ptr->next)"; the cast is redundant, purely
       to exercise dumping.  */
    gcc_jit_rvalue *test_cast =
      gcc_jit_context_new_cast (ctxt, NULL,
				gcc_jit_lvalue_as_rvalue (inner_deref),
				t_node_ptr);
    /* "((node *)ptr->next)->next".  */
    gcc_jit_lvalue *outer_deref =
      gcc_jit_rvalue_dereference_field (test_cast, /* gcc_jit_rvalue *ptr */
					NULL, /* gcc_jit_location *loc */
					f_next); /* gcc_jit_field *field */
    CHECK_LVALUE_DEBUG_STRING (outer_deref,
			       "((struct node *)ptr->next)->next");
  }

#undef CHECK_LVALUE_DEBUG_STRING
}
Exemplo n.º 8
0
/* The actual interpreter loop */
void interp(state_t *st) {
    while (1) {
        obj_t *x, *y, *z;
        char *p, c;
        int i;
        unsigned long u;
        /* fprintf(stderr, "Executing '%c'\n", *st->pc); */
        switch (c = *st->pc++) {
        case '\0':
            return;
        case '\r':
        case '\n':
        case '\t':
        case ' ': /* nop */
            break;
        case '!': /* call */
            POP(x);
            if (x->type != function) {
                error("Not a function.\n");
            } else {
                CALL(x);
                decref(x);
            }
            break;
        case '"': /* output string */
            p = skip_string(st->pc);
            c = *p; /* Save old character */
            *p = '\0'; /* Change it to NUL */
            fputs(st->pc, stdout); /* Print the string */
            *p = c; /* Replace original character */
            st->pc = p + 1; /* Set the PC to one past the closing quote*/
            break;
        case '#': /* over */
            POP(y); POP(x);
            PUS(x); PUS(y); PUSH(x);
            break;
        case '$': /* dup */
            POP(x);
            PUS(x); PUSH(x);
            break;
        case '%': /* mod */
            BINOP(mpz_mod);
            break;
        case '&': /* && */
            BINBOOL(NONZERO(x) && NONZERO(y));
            break;
        case '\'': /* Set multi */
            for (p = st->pc; *p && *p != '\''; p++);
            st->pc = p + 1;
            for (p--; *p != '\''; p--) {
                if (*p >= 'a' && *p <= 'z') {
                    /* local */
                    POP(x);
                    i = *p - 'a';
                    if ((y = st->frame->vars[i]) != NULL) decref(y);
                    st->frame->vars[i] = x;
                } else if (*p >= 'A' && *p <= 'Z') {
                    /* global */
                    POP(x);
                    i = *p - 'A';
                    if ((y = st->vars[i]) != NULL) decref(y);
                    st->vars[i] = x;
                } else if (*p != '\n' && *p != '\t' && *p != ' ') {
                    error("Not a variable: '%c'", *p);
                }
            }
            break;
        case '(': /* Comment; can't be nested */
            st->pc = skip_comment(st->pc);
            break;
        case '*': /* mul */
            BINOP(mpz_mul);
            break;
        case '+': /* add */
            BINOP(mpz_add);
            break;
        case ',': /* print character */
            POP(x);
            u = to_ulong(x);
            putchar(u);
            decref(x);
            break;
        case '-': /* sub */
            BINOP(mpz_sub);
            break;
        case '.': /* print */
            POP(x);
            print_obj(stdout, x);
            decref(x);
            break;
        case '/': /* div */
            BINOP(mpz_fdiv_q);
            break;
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
            p = st->pc;
            /* Skip to the first non-digit */
            while ((c = *p) >= '0' && c <= '9') p++;
            *p = '\0'; /* Temporarily put a NUL there */
            PUS(num_new_from_str(st->pc-1));
            *p = c; /* Replace original character */
            st->pc = p;
            break;
        case ':': /* Set variable */
            POP(x);
            c = *st->pc++;
            if (c >= 'A' && c <= 'Z') {
                /* global */
                i = c - 'A';
                if ((y = st->vars[i]) != NULL) decref(y);
                st->vars[i] = x;
            } else if (c >= 'a' && c <= 'z') {
                /* local */
                i = c - 'a';
                if ((y = st->frame->vars[i]) != NULL) decref(y);
                st->frame->vars[i] = x;
            } else {
                error("Not a variable: '%c'\n", *st->pc);
            }
            break;
        /* case ';': */
        /*     break; */
        case '<': /* less than */
            BINBOOL(mpz_cmp(*to_mpz(x), *to_mpz(y)) < 0);
            break;
        case '=': /* equal to */
            BINBOOL(mpz_cmp(*to_mpz(x), *to_mpz(y)) == 0);
            break;
        case '>': /* greater than */
            BINBOOL(mpz_cmp(*to_mpz(x), *to_mpz(y)) > 0);
            break;
        case '?': /* if */
            POP(z); POP(y); POP(x);
            if (x->type != number || y->type != function || z->type != function)
                error("Wrong argument type.");
            CALL(NONZERO(x) ? y : z);
            decref(z); decref(y); decref(x);
            break;
        case '@': /* rot */
            POP(z); POP(y); POP(x);
            PUS(y); PUS(z); PUS(x);
            break;
            /* global variables */
        case 'A':
        case 'B':
        case 'C':
        case 'D':
        case 'E':
        case 'F':
        case 'G':
        case 'H':
        case 'I':
        case 'J':
        case 'K':
        case 'L':
        case 'M':
        case 'N':
        case 'O':
        case 'P':
        case 'Q':
        case 'R':
        case 'S':
        case 'T':
        case 'U':
        case 'V':
        case 'W':
        case 'X':
        case 'Y':
        case 'Z':
            /* global variables */
            i = c - 'A';
            if ((x = st->vars[i]) == NULL) {
                error("Uninitialized variable '%c'\n", c);
            }
            if (x->type == function) {
                CALL(x);
            } else {
                PUSH(x);
            }
            break;
        case '[':
            PUS(fun_new(st->pc));
            i = 1;
            while (*st->pc) {
                switch (*st->pc++) {
                case '"':
                    st->pc = skip_string(st->pc) + 1;
                    break;
                case '(':
                    st->pc = skip_comment(st->pc) + 1;
                    break;
                case '[':
                    i++;
                    break;
                case ']':
                    if (--i <= 0) goto done;
                    break;
                }
            }
        done:
            break;
        case '\\': /* swap */
            POP(y); POP(x);
            PUS(y); PUS(x);
            break;
        case ']':
            POPRET();
            break;
        case '^': /* trace */
            print_trace(st);
            break;
        /* case '^': /\* pow *\/ */
        /*     POP(y); POP(x); */
        /*     z = num_new(); */
        /*     mpz_pow_ui(z->data.mpz, *to_mpz(x), to_ulong(y)); */
        /*     PUSH(z); */
        /*     decref(y); decref(x); */
        /*     break; *\/ */
        case '_': /* neg */
            POP(x);
            mpz_neg(*to_mpz(x), x->data.mpz);
            PUS(x);
            break;
        case '`': /* drop */
            POP(x);
            decref(x);
            break;
        case 'a':
        case 'b':
        case 'c':
        case 'd':
        case 'e':
        case 'f':
        case 'g':
        case 'h':
        case 'i':
        case 'j':
        case 'k':
        case 'l':
        case 'm':
        case 'n':
        case 'o':
        case 'p':
        case 'q':
        case 'r':
        case 's':
        case 't':
        case 'u':
        case 'v':
        case 'w':
        case 'x':
        case 'y':
        case 'z':
            /* local variables */
            i = c - 'a';
            if ((x = st->frame->vars[i]) == NULL) {
                error("Uninitialized variable '%c'\n", c);
            }
            if (x->type == function) {
                CALL(x);
            } else {
                PUSH(x);
            }
            break;
        /* case '{': */
        /*     break; */
        case '|': /* or */
            BINBOOL(NONZERO(x) || NONZERO(y));
            break;
        /* case '}': */
        /*     break; */
        case '~': /* not */
            POP(x);
            PUSH(ZERO(x) ? one : zero);
            decref(x);
            break;
        default:
            error("Undefined token '%c'\n", c);
        }
    }
}