static int match(Reinst *pc, const char *sp, const char *bol, int flags, Resub *out, int depth)
{
	Resub scratch;
	int result;
	int i;
	Rune c;

	/* stack overflow */
	if (depth > REG_MAXREC)
		return -1;

	for (;;) {
		switch (pc->opcode) {
		case I_END:
			return 0;
		case I_JUMP:
			pc = pc->x;
			break;
		case I_SPLIT:
			scratch = *out;
			result = match(pc->x, sp, bol, flags, &scratch, depth+1);
			if (result == -1)
				return -1;
			if (result == 0) {
				*out = scratch;
				return 0;
			}
			pc = pc->y;
			break;

		case I_PLA:
			result = match(pc->x, sp, bol, flags, out, depth+1);
			if (result == -1)
				return -1;
			if (result == 1)
				return 1;
			pc = pc->y;
			break;
		case I_NLA:
			scratch = *out;
			result = match(pc->x, sp, bol, flags, &scratch, depth+1);
			if (result == -1)
				return -1;
			if (result == 0)
				return 1;
			pc = pc->y;
			break;

		case I_ANYNL:
			if (!*sp) return 1;
			sp += chartorune(&c, sp);
			pc = pc + 1;
			break;
		case I_ANY:
			if (!*sp) return 1;
			sp += chartorune(&c, sp);
			if (isnewline(c))
				return 1;
			pc = pc + 1;
			break;
		case I_CHAR:
			if (!*sp) return 1;
			sp += chartorune(&c, sp);
			if (flags & REG_ICASE)
				c = canon(c);
			if (c != pc->c)
				return 1;
			pc = pc + 1;
			break;
		case I_CCLASS:
			if (!*sp) return 1;
			sp += chartorune(&c, sp);
			if (flags & REG_ICASE) {
				if (!incclasscanon(pc->cc, canon(c)))
					return 1;
			} else {
				if (!incclass(pc->cc, c))
					return 1;
			}
			pc = pc + 1;
			break;
		case I_NCCLASS:
			if (!*sp) return 1;
			sp += chartorune(&c, sp);
			if (flags & REG_ICASE) {
				if (incclasscanon(pc->cc, canon(c)))
					return 1;
			} else {
				if (incclass(pc->cc, c))
					return 1;
			}
			pc = pc + 1;
			break;
		case I_REF:
			i = out->sub[pc->n].ep - out->sub[pc->n].sp;
			if (flags & REG_ICASE) {
				if (strncmpcanon(sp, out->sub[pc->n].sp, i))
					return 1;
			} else {
				if (strncmp(sp, out->sub[pc->n].sp, i))
					return 1;
			}
			if (i > 0)
				sp += i;
			pc = pc + 1;
			break;

		case I_BOL:
			if (sp == bol && !(flags & REG_NOTBOL)) {
				pc = pc + 1;
				break;
			}
			if (flags & REG_NEWLINE) {
				if (sp > bol && isnewline(sp[-1])) {
					pc = pc + 1;
					break;
				}
			}
			return 1;
		case I_EOL:
			if (*sp == 0) {
				pc = pc + 1;
				break;
			}
			if (flags & REG_NEWLINE) {
				if (isnewline(*sp)) {
					pc = pc + 1;
					break;
				}
			}
			return 1;
		case I_WORD:
			i = sp > bol && iswordchar(sp[-1]);
			i ^= iswordchar(sp[0]);
			if (!i)
				return 1;
			pc = pc + 1;
			break;
		case I_NWORD:
			i = sp > bol && iswordchar(sp[-1]);
			i ^= iswordchar(sp[0]);
			if (i)
				return 1;
			pc = pc + 1;
			break;

		case I_LPAR:
			out->sub[pc->n].sp = sp;
			pc = pc + 1;
			break;
		case I_RPAR:
			out->sub[pc->n].ep = sp;
			pc = pc + 1;
			break;
		default:
			return 1;
		}
	}
}
static int match(Reinst *pc, const char *sp, const char *bol, int flags, Resub *out, int depth)
{
	Resub scratch;
	int result;
	int i;
	Rune c;

	 
	if (depth > REG_MAXREC)
		return -1;

	for (;;) {
		switch (pc->opcode) {
		case I_END:
			return 0;
		case I_JUMP:
			pc = pc->x;
			break;
		case I_SPLIT:
			scratch = *out;
			result = match(pc->x, sp, bol, flags, &scratch, depth+1);
			if (result == -1)
				return -1;
			if (result == 0) {
				*out = scratch;
				return 0;
			}
			pc = pc->y;
			break;

		case I_PLA:
			result = match(pc->x, sp, bol, flags, out, depth+1);
			if (result == -1)
				return -1;
			if (result == 1)
				return 1;
			pc = pc->y;
			break;
		case I_NLA:
			scratch = *out;
			result = match(pc->x, sp, bol, flags, &scratch, depth+1);
			if (result == -1)
				return -1;
			if (result == 0)
				return 1;
			pc = pc->y;
			break;

		case I_ANYNL:
			if (!*sp) return 1;
			sp += chartorune(&c, sp);
			pc = pc + 1;
			break;
		case I_ANY:
			if (!*sp) return 1;
			sp += chartorune(&c, sp);
			if (isnewline(c))
				return 1;
			pc = pc + 1;
			break;
		case I_CHAR:
			if (!*sp) return 1;
			sp += chartorune(&c, sp);
			if (flags & REG_ICASE)
				c = canon(c);
			if (c != pc->c)
				return 1;
			pc = pc + 1;
			break;
		case I_CCLASS:
			if (!*sp) return 1;
			sp += chartorune(&c, sp);
			if (flags & REG_ICASE) {
				if (!incclasscanon(pc->cc, canon(c)))
					return 1;
			} else {
				if (!incclass(pc->cc, c))
					return 1;
			}
			pc = pc + 1;
			break;
		case I_NCCLASS:
			if (!*sp) return 1;
			sp += chartorune(&c, sp);
			if (flags & REG_ICASE) {
				if (incclasscanon(pc->cc, canon(c)))
					return 1;
			} else {
				if (incclass(pc->cc, c))
					return 1;
			}
			pc = pc + 1;
			break;
		case I_REF:
			i = out->sub[pc->n].ep - out->sub[pc->n].sp;
			if (flags & REG_ICASE) {
				if (strncmpcanon(sp, out->sub[pc->n].sp, i))
					return 1;
			} else {
				if (strncmp(sp, out->sub[pc->n].sp, i))
					return 1;
			}
			if (i > 0)
				sp += i;
			pc = pc + 1;
			break;

		case I_BOL:
			if (sp == bol && !(flags & REG_NOTBOL)) {
				pc = pc + 1;
				break;
			}
			if (flags & REG_NEWLINE) {
				if (sp > bol && isnewline(sp[-1])) {
					pc = pc + 1;
					break;
				}
			}
			return 1;
		case I_EOL:
			if (*sp == 0) {
				pc = pc + 1;
				break;
			}
			if (flags & REG_NEWLINE) {
				if (isnewline(*sp)) {
					pc = pc + 1;
					break;
				}
			}
			return 1;
		case I_WORD:
			i = sp > bol && iswordchar(sp[-1]);
			i ^= iswordchar(sp[0]);
			if (!i)
				return 1;
			pc = pc + 1;
			break;
		case I_NWORD:
			i = sp > bol && iswordchar(sp[-1]);
			i ^= iswordchar(sp[0]);
			if (i)
				return 1;
			pc = pc + 1;
			break;

		case I_LPAR:
			out->sub[pc->n].sp = sp;
			pc = pc + 1;
			break;
		case I_RPAR:
			out->sub[pc->n].ep = sp;
			pc = pc + 1;
			break;
		default:
			return 1;
		}
	}
}