268 lines
8.2 KiB
C
268 lines
8.2 KiB
C
#include "eval.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#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;
|
|
}
|