#include "eval.h" #include #include #include "pattern.h" #include "pairmap.h" #define EVAL_FOREACH_MALLOC 1 static liblex_result foreach_errors[2] = { LIBLEX_SUCCESS, LIBLEX_MALLOC }; void eval_config_init(eval_config* config){ ll_init(&config->states); } liblex_result eval_config_add(eval_config* config, const char* ptrn, int pattern_id){ liblex_result result; pattern* new_pattern; eval_state* new_state; new_pattern = malloc(sizeof(*new_pattern)); new_state = malloc(sizeof(*new_pattern)); if(new_pattern && new_state){ result = pattern_compile(new_pattern, ptrn, pattern_id); if(result == LIBLEX_SUCCESS){ new_state->source = ptrn; new_state->pattern = new_pattern; result = (ll_append(&config->states, new_state) == LIBDS_SUCCESS) ? LIBLEX_SUCCESS : LIBLEX_MALLOC; } if(result != LIBLEX_SUCCESS){ pattern_free(new_pattern); } } else { result = LIBLEX_MALLOC; } if(result != LIBLEX_SUCCESS) { free(new_pattern); free(new_state); } return result; } liblex_result _eval_config_free_state(eval_state* state) { liblex_result result = pattern_free(state->pattern); free(state->pattern); free(state); return result; } liblex_result eval_config_remove(eval_config* config, const char* pattern, int pattern_id) { liblex_result result = LIBLEX_SUCCESS; ll_node* head = config->states.head; while(head && result == LIBLEX_SUCCESS) { eval_state* current_state = head->data; if(strcmp(current_state->source, pattern) == 0 && current_state->pattern->head->pattern_id == pattern_id) { ll_node* to_delete = head; head = head->next; *(to_delete->prev ? &to_delete->prev->next : &(config->states.head)) = to_delete->next; *(to_delete->next ? &to_delete->next->prev : &(config->states.tail)) = to_delete->prev; free(to_delete); result = _eval_config_free_state(current_state); } else { head = head->next; } } return result; } int _eval_config_foreach_free(void* data, va_list args){ return _eval_config_free_state(data) == LIBLEX_SUCCESS ? 0 : EVAL_FOREACH_MALLOC; } liblex_result eval_config_free(eval_config* config){ liblex_result result = foreach_errors[ll_foreach(&config->states, NULL, compare_always, _eval_config_foreach_free)]; ll_free(&config->states); return result; } pattern_node* _eval_pattern_node_get_next(pattern_node *node){ pattern_node* to_return = NULL; if(node->type == PNODE_VALUE){ to_return = node->data_u.value_s.next; } else if(node->type == PNODE_ANY){ to_return = node->data_u.any_s.next; } else if(node->type == PNODE_RANGE){ to_return = node->data_u.range_s.next; } else if(node->type == PNODE_CONNECT){ to_return = node->data_u.connect_s.next; } return to_return; } liblex_result _eval_pairmap_add_node(ht *table, pattern_node *node){ liblex_result result = LIBLEX_SUCCESS; if(node->type == PNODE_ANY || node->type == PNODE_VALUE || node->type == PNODE_RANGE || node->type == PNODE_END){ pairmap_key tmp_key; result = PAIRMAP_PUT(table, &tmp_key, node->pattern_id, node->id, node) == LIBDS_SUCCESS ? LIBLEX_SUCCESS : LIBLEX_MALLOC; } else if(node->type == PNODE_CONNECT){ result = _eval_pairmap_add_node(table, _eval_pattern_node_get_next(node)); } else if(node->type == PNODE_FORK){ result = _eval_pairmap_add_node(table, node->data_u.fork_s.left); if(result == LIBLEX_SUCCESS){ result = _eval_pairmap_add_node(table, node->data_u.fork_s.right); } } return result; } int _eval_foreach_add_node(void *data, va_list args){ eval_state* state = data; ht* pairmap = va_arg(args, ht*); pattern_node* pattern_head = state->pattern->head; return _eval_pairmap_add_node(pairmap, pattern_head) == LIBLEX_SUCCESS? 0 : EVAL_FOREACH_MALLOC; } int _eval_node_matches(pattern_node *node, eval *eval){ int matches = 0; char value = eval->string[eval->index]; if(node->type == PNODE_ANY){ matches = value != '\0'; } else if(node->type == PNODE_VALUE){ matches = value == node->data_u.value_s.value; } else if(node->type == PNODE_RANGE) { matches = value >= node->data_u.range_s.from && value <= node->data_u.range_s.to; } return matches; } int _eval_foreach_check_node(void *data, va_list args){ int inverted_matches = 1; int return_code = 0; pattern_node* node = data; eval* evl = va_arg(args, eval*); while(node && node->invert && inverted_matches) { inverted_matches &= !_eval_node_matches(node, evl); node = _eval_pattern_node_get_next(node); } if(inverted_matches && _eval_node_matches(node, evl)){ return_code = _eval_pairmap_add_node(evl->set_next, _eval_pattern_node_get_next(node)) == LIBLEX_SUCCESS ? 0 : EVAL_FOREACH_MALLOC; if(return_code == 0){ evl->matched++; } } else if(node->type == PNODE_END){ match* new_match = malloc(sizeof(*new_match)); if(new_match){ new_match->from = evl->begin; new_match->to = evl->index; new_match->pattern = node->pattern_id; return_code = ll_append(&evl->matches, new_match) == LIBDS_SUCCESS ? 0 : EVAL_FOREACH_MALLOC; if(return_code){ free(new_match); } } else { return_code = EVAL_FOREACH_MALLOC; } } return return_code; } liblex_result _eval_step(eval *eval){ ht* tmp; liblex_result result; eval->matched = 0; result = foreach_errors[ht_foreach(eval->set_current, NULL, compare_always, _eval_foreach_check_node, eval)]; tmp = eval->set_current; eval->set_current = eval->set_next; eval->set_next = tmp; if(eval->matched){ eval->index++; } ht_free(eval->set_next); pairmap_init_ht(eval->set_next); return result; } int _eval_foreach_find_match(void *data, va_list args){ match* current_match = data; int* max_match_id = va_arg(args, int*); match* fill_match = va_arg(args, match*); if(*max_match_id < current_match->pattern || current_match->to > fill_match->to){ *max_match_id = current_match->pattern; memcpy(fill_match, current_match, sizeof(*current_match)); } return 0; } liblex_result eval_word(const char* string, size_t index, eval_config* config, match* mtch){ liblex_result result = LIBLEX_SUCCESS; eval evl; evl.index = evl.begin = index; evl.string = string; evl.matched = 0; pairmap_init_ht(&evl.set_a); pairmap_init_ht(&evl.set_b); ll_init(&evl.matches); evl.set_current = &evl.set_a; evl.set_next = &evl.set_b; result = foreach_errors[ll_foreach(&config->states, NULL, compare_always, _eval_foreach_add_node, evl.set_current)]; if(result == LIBLEX_SUCCESS){ do { result = _eval_step(&evl); } while(result == LIBLEX_SUCCESS && evl.matched && *(evl.string)); } if(result == LIBLEX_SUCCESS && evl.matches.tail){ int largest_id = -1; ll_foreach(&evl.matches, NULL, compare_always, _eval_foreach_find_match, &largest_id, mtch); } else { mtch->from = 0; mtch->to = 0; mtch->pattern = -1; } ll_foreach(&evl.matches, NULL, compare_always, eval_foreach_match_free); ll_free(&evl.matches); ht_free(&evl.set_a); ht_free(&evl.set_b); return result; } liblex_result eval_all(const char* string, size_t index, eval_config* config, ll* matches){ liblex_result result = LIBLEX_SUCCESS; match* new_match = NULL; int done = 0; do { new_match = malloc(sizeof(*new_match)); if(new_match){ result = eval_word(string, index, config, new_match); if(result == LIBLEX_SUCCESS){ if(new_match->pattern < 0 || new_match->from - new_match->to == 0){ done = 1; free(new_match); if(string[index]){ result = LIBLEX_UNRECOGNIZED; } } else { result = ll_append(matches, new_match) == LIBDS_SUCCESS ? LIBLEX_SUCCESS : LIBLEX_MALLOC; } } if(result == LIBLEX_SUCCESS && string[index] != '\0'){ index += new_match->to - new_match->from; } } else { result = LIBLEX_MALLOC; } } while (result == LIBLEX_SUCCESS && done == 0); if(result != LIBLEX_SUCCESS){ ll_foreach(matches, NULL, compare_always, eval_foreach_match_free); ll_clear(matches); } return result; } int eval_foreach_match_free(void *data, va_list args){ free(data); return 0; }