예제 #1
0
/**
 * Remove unuseful failure links to skip using an invalid transition
 *
 * @param ac_tree the matcher that holds the patterns
 * @param state the state where it should start (it's used recursively)
 *
 */
static void ib_ac_unlink_unuseful(ib_ac_t *ac_tree,
                               ib_ac_state_t *state)
{
    IB_FTRACE_INIT();
    ib_ac_state_t *child = NULL;
    ib_ac_state_t *fail_state = NULL;
    ib_ac_state_t *found = NULL;

    for (child = state->child;
         child != NULL;
         child = child->sibling)
    {
        if (child->fail == NULL ||
            child->fail->child == NULL ||
            child->child == NULL)
        {
            continue;
        }

        for (fail_state = child->fail->child;
             fail_state != ac_tree->root && fail_state != NULL;
             fail_state = fail_state->sibling)
        {
            found = ib_ac_child_for_code(child, fail_state->letter);
            if (found == NULL) {
                break;
            }
        }

        if (found != NULL) {
            /* There's no transition in the fail state that will
             * success, since the fail state doesn't have any letter not
             * present at the goto() of the main state. So let's
             * change the fail state to parent. Consider that this is
             * different to the output links (they'll still valid) */
             child->fail = ac_tree->root;

             /* printf("Removing invalid fails\n"); */
        }
    }

    for (child = state->child;
         child != NULL;
         child = child->sibling)
    {
        if (child->child != NULL) {
            ib_ac_unlink_unuseful(ac_tree, child);
        }
    }

    IB_FTRACE_RET_VOID();
}
예제 #2
0
/**
 * Constructs fail links of branches (the failure transition function)
 *
 * @param ac_tree the ac tree matcher
 *
 * @return ib_status_t status of the operation
 */
static ib_status_t ib_ac_link_fail_states(ib_ac_t *ac_tree)
{
    ib_status_t rc;

    ib_ac_state_t *child = NULL;
    ib_ac_state_t *state = NULL;
    ib_ac_state_t *goto_state = NULL;

    ib_list_t *iter_queue = NULL;

    if (ac_tree->flags & IB_AC_FLAG_PARSER_COMPILED) {
        return IB_OK;
    }

    ac_tree->root->pattern = 0;

    rc = ib_list_create(&iter_queue, ac_tree->mp);
    if (rc != IB_OK) {
        return rc;
    }

    ac_tree->root->fail = ac_tree->root;

    /* All first-level children will fail back to root state */
    for (child = ac_tree->root->child;
         child != NULL;
         child = child->sibling)
    {
        child->fail = ac_tree->root;
        rc = ib_list_enqueue(iter_queue, (void *) child);
        if (rc != IB_OK) {
            return rc;
        }
    }

    while (ib_list_elements(iter_queue) > 0) {
        rc = ib_list_dequeue(iter_queue, (void *) &state);
        if (rc != IB_OK) {
            return rc;
        }

        state->fail = ac_tree->root;

        if (state->parent != ac_tree->root) {
            goto_state = ib_ac_child_for_code(state->parent->fail,
                                             state->letter);
            if (goto_state != NULL) {
                state->fail = goto_state;
            }
        }

        for (child = state->child;
             child != NULL;
             child = child->sibling)
        {
            rc = ib_list_enqueue(iter_queue, (void *) child);
            if (rc != IB_OK) {
                return rc;
            }
        }
    }

    /* Link common outputs of subpatterns present in the branch*/
    ib_ac_link_outputs(ac_tree, ac_tree->root);

    /* Unlink invalid fail transitions. This guarantees that there will
     * be at least one letter with transition in each fail state*/
    ib_ac_unlink_unuseful(ac_tree, ac_tree->root);

    if (ac_tree->root->child != NULL) {
        ib_ac_build_bintree(ac_tree, ac_tree->root);
    }

    ac_tree->flags |= IB_AC_FLAG_PARSER_COMPILED;

    return IB_OK;
}