NULL,
static REParser ParseQuantAtom;static REParser ParseAtom;/* * Top-down regular expression grammar, based closely on Perl4. * *  regexp:     altern                  A regular expression is one or more *              altern '|' regexp       alternatives separated by vertical bar. */static RENode *ParseRegExp(CompilerState *state){    RENode *ren, *kid, *ren1, *ren2;    const jschar *cp;    ren = ParseAltern(state);    if (!ren)	return NULL;    cp = state->cp;    if ((cp < state->cpend) && (*cp == '|')) {	kid = ren;	ren = NewRENode(state, REOP_ALT, kid);	if (!ren)	    return NULL;	ren->flags = kid->flags & (RENODE_ANCHORED | RENODE_NONEMPTY);	ren1 = ren;	do {	    /* (balance: */	    state->cp = ++cp;	    if (*cp == '|' || *cp == ')') {		kid = NewRENode(state, REOP_EMPTY, NULL);	    } else {		kid = ParseAltern(state);		cp = state->cp;	    }	    if (!kid)		return NULL;	    ren2 = NewRENode(state, REOP_ALT, kid);	    if (!ren2)		return NULL;	    ren1->next = ren2;	    ren1->flags |= RENODE_GOODNEXT;	    ren2->flags = (kid->flags & (RENODE_ANCHORED | RENODE_NONEMPTY))			  | RENODE_ISNEXT;	    ren1 = ren2;	} while ((cp < state->cpend) && (*cp == '|'));    }    return ren;}/* *  altern:     item                    An alternative is one or more items, *              item altern             concatenated together. */static RENode *ParseAltern(CompilerState *state){    RENode *ren, *ren1, *ren2;    uintN flags;    const jschar *cp;    jschar c;    ren = ren1 = ParseItem(state);    if (!ren)	return NULL;    flags = 0;    cp = state->cp;    /* (balance: */    while ((cp < state->cpend) && (c = *cp) != '|' && c != ')') {	ren2 = ParseItem(state);	if (!ren2)	    return NULL;	if (!SetNext(state, ren1, ren2))	    return NULL;	flags |= ren2->flags;	ren1 = ren2;	cp = state->cp;    }    /*     * Propagate NONEMPTY to the front of a concatenation list, so that the     * first alternative in (^a|b) is considered non-empty.  The first node     * in a list may match the empty string (as ^ does), but if the list is     * non-empty, then the first node's NONEMPTY flag must be set.     */    ren->flags |= flags & RENODE_NONEMPTY;    return ren;}/* *  item:       assertion               An item is either an assertion or *              quantatom               a quantified atom. * *  assertion:  '^'                     Assertions match beginning of string *                                      (or line if the class static property *                                      RegExp.multiline is true). *              '$'                     End of string (or line if the class *                                      static property RegExp.multiline is *                                      true). *              '\b'                    Word boundary (between \w and \W). *              '\B'                    Word non-boundary. */static RENode *ParseItem(CompilerState *state){    const jschar *cp;    RENode *ren;    REOp op;    cp = state->cp;    if (cp < state->cpend)        switch (*cp) {          case '^':	    state->cp = cp + 1;	    ren = NewRENode(state, REOP_BOL, NULL);	    if (ren)	        ren->flags |= RENODE_ANCHORED;	    return ren;          case '$':	    state->cp = cp + 1;	    return NewRENode(state,			     (cp == state->cpbegin ||			      ((cp[-1] == '(' || cp[-1] == '|') && /*balance)*/			       (cp - 1 == state->cpbegin || cp[-2] != '\\')))			     ? REOP_EOLONLY			     : REOP_EOL,			     NULL);          case '\\':	    switch (*++cp) {	      case 'b':	        op = REOP_WBDRY;	        break;	      case 'B':	        op = REOP_WNONBDRY;	        break;	      default:	        return ParseQuantAtom(state);	    }	    /*	     * Word boundaries and non-boundaries are flagged as non-empty so they	     * will be prefixed by an anchoring node.	     */	    state->cp = cp + 1;	    ren = NewRENode(state, op, NULL);	    if (ren)	        ren->flags |= RENODE_NONEMPTY;	    return ren;          default:;        }    return ParseQuantAtom(state);}/* *  quantatom:  atom                    An unquantified atom. *              quantatom '{' n ',' m '}' *                                      Atom must occur between n and m times. *              quantatom '{' n ',' '}' Atom must occur at least n times. *              quantatom '{' n '}'     Atom must occur exactly n times. *              quantatom '*'           Zero or more times (same as {0,}). *              quantatom '+'           One or more times (same as {1,}). *              quantatom '?'           Zero or one time (same as {0,1}).  * *              any of which can be optionally followed by '?' for ungreedy*/static RENode *ParseQuantAtom(CompilerState *state){    RENode *ren, *ren2;    const jschar *cp, *up;    jschar c;    uint32 min, max;    ren = ParseAtom(state);    if (!ren)	return NULL;    cp = state->cp;loop:    if (cp < state->cpend)        switch (*cp) {          case '{':	    c = *++cp;	    if (!JS7_ISDEC(c)) {                js_ReportCompileErrorNumber(state->context, state->tokenStream,                                            NULL, JSREPORT_ERROR,                                            JSMSG_BAD_QUANTIFIER, state->cp);	        return NULL;	    }	    min = (uint32)JS7_UNDEC(c);	    for (c = *++cp; JS7_ISDEC(c); c = *++cp) {	        min = 10 * min + (uint32)JS7_UNDEC(c);	        if (min >> 16) {                    js_ReportCompileErrorNumber(state->context,                                                state->tokenStream, NULL,                                                JSREPORT_ERROR,                                                JSMSG_MIN_TOO_BIG, state->cp);		    return NULL;	        }	    }	    if (*cp == ',') {	        up = ++cp;	        if (JS7_ISDEC(*cp)) {		    max = (uint32)JS7_UNDEC(*cp);		    for (c = *++cp; JS7_ISDEC(c); c = *++cp) {		        max = 10 * max + (uint32)JS7_UNDEC(c);		        if (max >> 16) {                            js_ReportCompileErrorNumber(state->context,                                                        state->tokenStream,                                                        NULL,                                                        JSREPORT_ERROR,                                                        JSMSG_MAX_TOO_BIG, up);			    return NULL;		        }		    }		    if (max == 0)		        goto zero_quant;		    if (min > max) {                        js_ReportCompileErrorNumber(state->context,                                                    state->tokenStream,                                                    NULL,                                                    JSREPORT_ERROR,                                                    JSMSG_OUT_OF_ORDER, up);		        return NULL;		    }	        } else {		    /* 0 means no upper bound. */		    max = 0;	        }	    } else {	        /* Exactly n times. */	        if (min == 0) {          zero_quant:                    js_ReportCompileErrorNumber(state->context,                                                state->tokenStream,                                                NULL,                                                JSREPORT_ERROR,                                                JSMSG_ZERO_QUANTIFIER,                                                state->cp);		    return NULL;	        }	        max = min;	    }	    if (*cp != '}') {                js_ReportCompileErrorNumber(state->context,                                            state->tokenStream,                                            NULL,                                            JSREPORT_ERROR,                                            JSMSG_UNTERM_QUANTIFIER, state->cp);	        return NULL;	    }	    cp++;	    ren2 = NewRENode(state, REOP_QUANT, ren);	    if (!ren2)	        return NULL;	    if (min > 0 && (ren->flags & RENODE_NONEMPTY))	        ren2->flags |= RENODE_NONEMPTY;	    ren2->u.range.min = (uint16)min;	    ren2->u.range.max = (uint16)max;	    ren = ren2;            goto parseMinimalFlag;          case '*':	    cp++; 	    ren = NewRENode(state, REOP_STAR, ren);    parseMinimalFlag :            if (*cp == '?') {                ren->flags |= RENODE_MINIMAL;                cp++;            }	    goto loop;          case '+':	    cp++;	    ren2 = NewRENode(state, REOP_PLUS, ren);	    if (!ren2)	        return NULL;	    if (ren->flags & RENODE_NONEMPTY)	        ren2->flags |= RENODE_NONEMPTY;	    ren = ren2;	    goto parseMinimalFlag;          case '?':	    cp++;	    ren = NewRENode(state, REOP_OPT, ren);	    goto parseMinimalFlag;        }    state->cp = cp;    return ren;}