📄 jsregexp.c
字号:
case 't': c = 0x9; goto doFlat; case 'v': c = 0xB; goto doFlat; /* Control letter */ case 'c': if (state->cp + 1 < state->cpend && RE_IS_LETTER(state->cp[1])) { c = (jschar) (*state->cp++ & 0x1F); } else { /* back off to accepting the original '\' as a literal */ --state->cp; c = '\\'; } goto doFlat; /* HexEscapeSequence */ case 'x': nDigits = 2; goto lexHex; /* UnicodeEscapeSequence */ case 'u': nDigits = 4;lexHex: n = 0; for (i = 0; i < nDigits && state->cp < state->cpend; i++) { uintN digit; c = *state->cp++; if (!isASCIIHexDigit(c, &digit)) { /* * back off to accepting the original * 'u' or 'x' as a literal */ state->cp -= i + 2; n = *state->cp++; break; } n = (n << 4) | digit; } c = (jschar) n; goto doFlat; /* Character class escapes */ case 'd': state->result = NewRENode(state, REOP_DIGIT);doSimple: if (!state->result) return JS_FALSE; state->progLength++; break; case 'D': state->result = NewRENode(state, REOP_NONDIGIT); goto doSimple; case 's': state->result = NewRENode(state, REOP_SPACE); goto doSimple; case 'S': state->result = NewRENode(state, REOP_NONSPACE); goto doSimple; case 'w': state->result = NewRENode(state, REOP_ALNUM); goto doSimple; case 'W': state->result = NewRENode(state, REOP_NONALNUM); goto doSimple; /* IdentityEscape */ default: state->result = NewRENode(state, REOP_FLAT); if (!state->result) return JS_FALSE; state->result->u.flat.chr = c; state->result->u.flat.length = 1; state->result->kid = (void *) (state->cp - 1); state->progLength += 3; break; } break; case '[': state->result = NewRENode(state, REOP_CLASS); if (!state->result) return JS_FALSE; termStart = state->cp; state->result->u.ucclass.startIndex = termStart - state->cpbegin; while (JS_TRUE) { if (state->cp == state->cpend) { js_ReportCompileErrorNumber(state->context, state->tokenStream, NULL, JSREPORT_ERROR, JSMSG_UNTERM_CLASS, termStart); return JS_FALSE; } if (*state->cp == '\\') { state->cp++; } else { if (*state->cp == ']') { state->result->u.ucclass.kidlen = state->cp - termStart; break; } } state->cp++; } for (i = 0; i < CLASS_CACHE_SIZE; i++) { if (!state->classCache[i].start) { state->classCache[i].start = termStart; state->classCache[i].length = state->result->u.ucclass.kidlen; state->classCache[i].index = state->classCount; break; } if (state->classCache[i].length == state->result->u.ucclass.kidlen) { for (n = 0; ; n++) { if (n == state->classCache[i].length) { state->result->u.ucclass.index = state->classCache[i].index; goto claim; } if (state->classCache[i].start[n] != termStart[n]) break; } } } state->result->u.ucclass.index = state->classCount++; claim: /* * Call CalculateBitmapSize now as we want any errors it finds * to be reported during the parse phase, not at execution. */ if (!CalculateBitmapSize(state, state->result, termStart, state->cp++)) return JS_FALSE; state->progLength += 3; /* CLASS, <index> */ break; case '.': state->result = NewRENode(state, REOP_DOT); goto doSimple; case '*': case '+': case '?': js_ReportCompileErrorNumber(state->context, state->tokenStream, NULL, JSREPORT_ERROR, JSMSG_BAD_QUANTIFIER, state->cp - 1); return JS_FALSE; default: state->result = NewRENode(state, REOP_FLAT); if (!state->result) return JS_FALSE; state->result->u.flat.chr = c; state->result->u.flat.length = 1; state->result->kid = (void *) (state->cp - 1); state->progLength += 3; break; } return ParseQuantifier(state);}static JSBoolParseQuantifier(CompilerState *state){ RENode *term; term = state->result; if (state->cp < state->cpend) { switch (*state->cp) { case '+': state->result = NewRENode(state, REOP_QUANT); if (!state->result) return JS_FALSE; state->result->u.range.min = 1; state->result->u.range.max = (uint16)-1; /* <PLUS>, <next> ... <ENDCHILD> */ state->progLength += 4; goto quantifier; case '*': state->result = NewRENode(state, REOP_QUANT); if (!state->result) return JS_FALSE; state->result->u.range.min = 0; state->result->u.range.max = (uint16)-1; /* <STAR>, <next> ... <ENDCHILD> */ state->progLength += 4; goto quantifier; case '?': state->result = NewRENode(state, REOP_QUANT); if (!state->result) return JS_FALSE; state->result->u.range.min = 0; state->result->u.range.max = 1; /* <OPT>, <next> ... <ENDCHILD> */ state->progLength += 4; goto quantifier; case '{': /* balance '}' */ { intN err; uintN min, max; jschar c; const jschar *errp = state->cp++; c = *state->cp; if (JS7_ISDEC(c)) { ++state->cp; min = GetDecimalValue(c, 0xFFFF, NULL, state); c = *state->cp; if (min == OVERFLOW_VALUE) { err = JSMSG_MIN_TOO_BIG; goto quantError; } if (c == ',') { c = *++state->cp; if (JS7_ISDEC(c)) { ++state->cp; max = GetDecimalValue(c, 0xFFFF, NULL, state); c = *state->cp; if (max == OVERFLOW_VALUE) { err = JSMSG_MAX_TOO_BIG; goto quantError; } if (min > max) { err = JSMSG_OUT_OF_ORDER; goto quantError; } } else { max = (uintN)-1; } } else { max = min; } if (c == '}') { state->result = NewRENode(state, REOP_QUANT); if (!state->result) return JS_FALSE; state->result->u.range.min = min; state->result->u.range.max = max; /* QUANT, <min>, <max>, <next> ... <ENDCHILD> */ state->progLength += 8; goto quantifier; } } state->cp = errp; return JS_TRUE;quantError: js_ReportCompileErrorNumber(state->context, state->tokenStream, NULL, JSREPORT_ERROR, err, errp); return JS_FALSE; } } } return JS_TRUE;quantifier: ++state->treeDepth; ++state->cp; state->result->kid = term; if (state->cp < state->cpend && *state->cp == '?') { ++state->cp; state->result->u.range.greedy = JS_FALSE; } else state->result->u.range.greedy = JS_TRUE; return JS_TRUE;}#define CHECK_OFFSET(diff) (JS_ASSERT(((diff) >= -32768) && ((diff) <= 32767)))#define SET_OFFSET(pc,off) ((pc)[0] = JUMP_OFFSET_HI(off), \ (pc)[1] = JUMP_OFFSET_LO(off))#define GET_OFFSET(pc) ((int16)(((pc)[0] << 8) | (pc)[1]))#define OFFSET_LEN (2)#define GET_ARG(pc) GET_OFFSET(pc)#define SET_ARG(pc,arg) SET_OFFSET(pc,arg)#define ARG_LEN OFFSET_LEN/* * Recursively generate bytecode for the tree rooted at t. Iteratively. */typedef struct { RENode *nextAlt; jsbytecode *nextAltFixup, *nextTermFixup, *endTermFixup; RENode *continueNode; REOp continueOp;} EmitStateStackEntry;static jsbytecode *EmitREBytecode(CompilerState *state, JSRegExp *re, intN treeDepth, jsbytecode *pc, RENode *t){ ptrdiff_t diff; RECharSet *charSet; EmitStateStackEntry *emitStateSP, *emitStateStack = NULL; REOp op; if (treeDepth) { emitStateStack = (EmitStateStackEntry *)JS_malloc(state->context, sizeof(EmitStateStackEntry) * treeDepth); if (!emitStateStack) return NULL; } emitStateSP = emitStateStack; op = t->op; while (JS_TRUE) { *pc++ = op; switch (op) { case REOP_EMPTY: --pc; break; case REOP_ALTPREREQ2: case REOP_ALTPREREQ: JS_ASSERT(emitStateSP); emitStateSP->endTermFixup = pc; pc += OFFSET_LEN; SET_ARG(pc, t->u.altprereq.ch1); pc += ARG_LEN; SET_ARG(pc, t->u.altprereq.ch2); pc += ARG_LEN; emitStateSP->nextAltFixup = pc; /* address of next alternate */ pc += OFFSET_LEN; emitStateSP->continueNode = t; emitStateSP->continueOp = REOP_JUMP; ++emitStateSP; JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth); t = (RENode *) t->kid; op = t->op; continue; case REOP_JUMP: emitStateSP->nextTermFixup = pc; /* address of following term */ pc += OFFSET_LEN; diff = pc - emitStateSP->nextAltFixup; CHECK_OFFSET(diff); SET_OFFSET(emitStateSP->nextAltFixup, diff); emitStateSP->continueOp = REOP_ENDALT; ++emitStateSP; JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth); t = (RENode *) t->u.kid2; op = t->op; continue; case REOP_ENDALT: diff = pc - emitStateSP->nextTermFixup; CHECK_OFFSET(diff); SET_OFFSET(emitStateSP->nextTermFixup, diff); if (t->op != REOP_ALT) { diff = pc - emitStateSP->endTermFixup; CHECK_OFFSET(diff); SET_OFFSET(emitStateSP->endTermFixup, diff); } break; case REOP_ALT: JS_ASSERT(emitStateSP); emitStateSP->nextAltFixup = pc; /* address of pointer to next alternate */ pc += OFFSET_LEN; emitStateSP->continueNode = t; emitStateSP->continueOp = REOP_JUMP; ++emitStateSP; JS_ASSERT((emitStateSP - emitStateStack) <= treeDepth); t = (RENode *) t->kid; op = t->op; continue; case REOP_FLAT: /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -