jsregexp.c

来自「一个基于alice开发的机器人」· C语言 代码 · 共 1,779 行 · 第 1/5 页

C
1,779
字号
        if ((((RENode *)(result->kid))->op == REOP_FLAT)
                && (((RENode *)(result->u.kid2))->op == REOP_FLAT)
                && ((state->flags & JSREG_FOLD) == 0) ) {
            result->op = REOP_ALTPREREQ;
            result->u.altprereq.ch1 
                = ((RENode *)(result->kid))->u.flat.chr;
            result->u.altprereq.ch2 
                = ((RENode *)(result->u.kid2))->u.flat.chr;
            /* ALTPREREQ, <end>, uch1, uch2, <next>, ..., 
                                            JUMP, <end> ... ENDALT */
            state->progLength += 13;
        }
        else
        if ((((RENode *)(result->kid))->op == REOP_CLASS)
                && (((RENode *)(result->kid))->u.ucclass.index < 256)
                && (((RENode *)(result->u.kid2))->op == REOP_FLAT)
                && ((state->flags & JSREG_FOLD) == 0) ) {
            result->op = REOP_ALTPREREQ2;
            result->u.altprereq.ch1 
                = ((RENode *)(result->u.kid2))->u.flat.chr;
            result->u.altprereq.ch2 
                = ((RENode *)(result->kid))->u.ucclass.index;
            /* ALTPREREQ2, <end>, uch1, uch2, <next>, ..., 
                                            JUMP, <end> ... ENDALT */
            state->progLength += 13;
        }
        else
        if ((((RENode *)(result->kid))->op == REOP_FLAT)
                && (((RENode *)(result->u.kid2))->op == REOP_CLASS)
                && (((RENode *)(result->u.kid2))->u.ucclass.index < 256)
                && ((state->flags & JSREG_FOLD) == 0) ) {
            result->op = REOP_ALTPREREQ2;
            result->u.altprereq.ch1 
                = ((RENode *)(result->kid))->u.flat.chr;
            result->u.altprereq.ch2 
                = ((RENode *)(result->u.kid2))->u.ucclass.index;
            /* ALTPREREQ2, <end>, uch1, uch2, <next>, ..., 
                                          JUMP, <end> ... ENDALT */
            state->progLength += 13;
        }
        else
            /* ALT, <next>, ..., JUMP, <end> ... ENDALT */
            state->progLength += 7;
        break;
    case REOP_CONCAT:
        result = operandStack[operandSP - 2];
        while (result->next)
            result = result->next;
        result->next = operandStack[operandSP - 1];
        break;
    case REOP_ASSERT:
    case REOP_ASSERT_NOT:
    case REOP_LPARENNON:
    case REOP_LPAREN:
        /* These should have been processed by a close paren. */
        js_ReportCompileErrorNumber(state->context, state->tokenStream,
                                    NULL, JSREPORT_ERROR,
                                    JSMSG_MISSING_PAREN, opData->errPos);
        return JS_FALSE;
    default:;
    }
    return JS_TRUE;
}

/*
 * Parser forward declarations.
 */
static JSBool parseTerm(CompilerState *state);
static JSBool parseQuantifier(CompilerState *state);

/*
 * 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.
 */

#define INITIAL_STACK_SIZE (128)
static JSBool 
parseRegExp(CompilerState *state)
{
    uint16 parenIndex;
    RENode *operand;
    REOpData *operatorStack;
    RENode **operandStack;
    REOp op;
    intN i;
    JSBool result = JS_FALSE;

    intN operatorSP = 0, operatorStackSize = INITIAL_STACK_SIZE;
    intN operandSP = 0, operandStackSize = INITIAL_STACK_SIZE;

    /* Watch out for empty regexp */
    if (state->cp == state->cpend) {
        state->result = NewRENode(state, REOP_EMPTY);
        return (state->result != NULL);
    }

    operatorStack = (REOpData *)JS_malloc(state->context, 
                                          sizeof(REOpData) * operatorStackSize);
    if (!operatorStack)
        return JS_FALSE;

    operandStack = (RENode **)JS_malloc(state->context,
                                        sizeof(RENode *) * operandStackSize);
    if (!operandStack)
        goto out;


    while (JS_TRUE) {
        if (state->cp == state->cpend) {
            /*
             * If we are at the end of the regexp and we're short an operand,
             * the regexp must have the form /x|/ or some such.
             */
            if (operatorSP == operandSP) {
                operand = NewRENode(state, REOP_EMPTY);
                if (!operand)
                    goto out;
                goto pushOperand;
            }
        } else {
            switch (*state->cp) {
                /* balance '(' */
            case '(':           /* balance ')' */
                ++state->cp;
                if ((state->cp < state->cpend) && (*state->cp == '?')
                        && ( (state->cp[1] == '=')
                                || (state->cp[1] == '!')
                                || (state->cp[1] == ':') )) {
                    ++state->cp;
                    if (state->cp == state->cpend) {
                        js_ReportCompileErrorNumber(state->context, 
                                                    state->tokenStream,
                                                    NULL, JSREPORT_ERROR,
                                                    JSMSG_MISSING_PAREN);
                        goto out;
                    }
                    switch (*state->cp++) {
                    case '=':
                        op = REOP_ASSERT;
                        /* ASSERT, <next>, ... ASSERTTEST */
                        state->progLength += 4;    
                        break;
                    case '!':
                        op = REOP_ASSERT_NOT;
                        /* ASSERTNOT, <next>, ... ASSERTNOTTEST */
                        state->progLength += 4;
                        break;
                    case ':':
                        op = REOP_LPARENNON;
                        break;
                    }
                    parenIndex = state->parenCount;
                }
                else {
                    op = REOP_LPAREN;
                    /* LPAREN, <index>, ... RPAREN, <index> */
                    state->progLength += 6;
                    parenIndex = state->parenCount++;
                    if (state->parenCount == 65535) {
                        js_ReportCompileErrorNumber(state->context, 
                                                    state->tokenStream,
                                                    NULL, JSREPORT_ERROR,
                                                    JSMSG_TOO_MANY_PARENS);
                        goto out;
                    }
                }
                goto pushOperator;
            case ')':
                /* If there's not a stacked open parenthesis, throw
                 * a syntax error.
                 */
                for (i = operatorSP - 1; i >= 0; i--)
                    if ((operatorStack[i].op == REOP_ASSERT)
                            || (operatorStack[i].op == REOP_ASSERT_NOT)
                            || (operatorStack[i].op == REOP_LPARENNON)
                            || (operatorStack[i].op == REOP_LPAREN))
                        break;
                if (i == -1) {
                    js_ReportCompileErrorNumber(state->context, 
                                                state->tokenStream,
                                                NULL, JSREPORT_ERROR,
                                                JSMSG_UNMATCHED_RIGHT_PAREN);
                    goto out;
                }
                /* fall thru... */
            case '|':
                /* Expected an operand before these, so make an empty one */
                operand = NewRENode(state, REOP_EMPTY);
                if (!operand)
                    goto out;
                goto pushOperand;
            default:
                if (!parseTerm(state))
                    goto out;
                operand = state->result;
pushOperand:
                if (operandSP == operandStackSize) {
                    operandStackSize += operandStackSize;
                    operandStack = 
                      (RENode **)JS_realloc(state->context, operandStack,
                                            sizeof(RENode *) * operandStackSize);
                    if (!operandStack)
                        goto out;
                }
                operandStack[operandSP++] = operand;
                break;
            }
        }
            /* At the end; process remaining operators */
restartOperator:
        if (state->cp == state->cpend) {
            while (operatorSP) {
                --operatorSP;
                if (!processOp(state, &operatorStack[operatorSP], 
                               operandStack, operandSP))
                    goto out;
                --operandSP;
            }
            JS_ASSERT(operandSP == 1);
            state->result = operandStack[0];
            result = JS_TRUE;
            goto out;
        }
        switch (*state->cp) {
        case '|': 
            /* Process any stacked 'concat' operators */
            ++state->cp;
            while (operatorSP 
                    && (operatorStack[operatorSP - 1].op == REOP_CONCAT)) {
                --operatorSP;
                if (!processOp(state, &operatorStack[operatorSP], 
                               operandStack, operandSP))
                    goto out;
                --operandSP;
            }
            op = REOP_ALT;
            goto pushOperator;

        case ')':
            /* If there's not a stacked open parenthesis,we
             * accept the close as a flat.
             */
            for (i = operatorSP - 1; i >= 0; i--)
                if ((operatorStack[i].op == REOP_ASSERT)
                        || (operatorStack[i].op == REOP_ASSERT_NOT)
                        || (operatorStack[i].op == REOP_LPARENNON)
                        || (operatorStack[i].op == REOP_LPAREN))
                    break;
            if (i == -1) {
                js_ReportCompileErrorNumber(state->context, 
                                            state->tokenStream,
                                            NULL, JSREPORT_ERROR,
                                            JSMSG_UNMATCHED_RIGHT_PAREN);
                goto out;
            }
            ++state->cp;
            /* process everything on the stack until the open */
            while (JS_TRUE) {
                JS_ASSERT(operatorSP);                    
                --operatorSP;
                switch (operatorStack[operatorSP].op) {
                case REOP_ASSERT:
                case REOP_ASSERT_NOT:
                case REOP_LPAREN:
                    operand = NewRENode(state, operatorStack[operatorSP].op);
                    if (!operand)
                        goto out;
                    operand->u.parenIndex 
                                    = operatorStack[operatorSP].parenIndex;
                    JS_ASSERT(operandSP);
                    operand->kid = operandStack[operandSP - 1];
                    operandStack[operandSP - 1] = operand;
                    ++state->treeDepth;
                    /* fall thru... */
                case REOP_LPARENNON:
                    state->result = operandStack[operandSP - 1];
                    if (!parseQuantifier(state))
                        goto out;
                    operandStack[operandSP - 1] = state->result;
                    goto restartOperator;
                default:
                    if (!processOp(state, &operatorStack[operatorSP], 
                                   operandStack, operandSP))
                        goto out;
                    --operandSP;
                    break;
                }
            }
            break;
        default:
            /* Anything else is the start of the next term */
            op = REOP_CONCAT;
pushOperator:
            if (operatorSP == operatorStackSize) {
                operatorStackSize += operatorStackSize;
                operatorStack = 
                    (REOpData *)JS_realloc(state->context, operatorStack,
                                           sizeof(REOpData) * operatorStackSize);
                if (!operatorStack)
                    goto out;
            }
            operatorStack[operatorSP].op = op;
            operatorStack[operatorSP].errPos = state->cp;
            operatorStack[operatorSP++].parenIndex = parenIndex;
            break;
        }
    }
out:
    if (operatorStack)
        JS_free(state->context, operatorStack);
    if (operandStack)
        JS_free(state->context, operandStack);
    return result;
}

/*
 * Extract and return a decimal value at state->cp, the
 * initial character 'c' has already been read.
 */
static intN 
getDecimalValue(jschar c, CompilerState *state)
{
    intN value = JS7_UNDEC(c);
    while (state->cp < state->cpend) {
        c = *state->cp; 
        if (!JS7_ISDEC(c))
            break;
        value = (10 * value) + JS7_UNDEC(c);
        ++state->cp;
    }
    return value;
}

/*
 * Calculate the total size of the bitmap required for a class expression.
 */
static JSBool 
calculateBitmapSize(CompilerState *state, RENode *target, const jschar *src,
                    const jschar *end)
{
    jschar rangeStart, c;
    uintN n, digit, nDigits, i;
    uintN max = 0;
    JSBool inRange = JS_FALSE;

    target->u.ucclass.bmsize = 0;
    target->u.ucclass.sense = JS_TRUE;

    if (src == end)
        return JS_TRUE;

    if (*src == '^') {
        ++src;
        target->u.ucclass.sense = JS_FALSE;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?