231 lines
6.9 KiB
C
231 lines
6.9 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, char* ptrn, int pattern_id){
|
|
liblex_result result;
|
|
pattern* new_pattern = malloc(sizeof(*new_pattern));
|
|
if(new_pattern){
|
|
result = pattern_compile(new_pattern, ptrn, pattern_id);
|
|
if(result == LIBLEX_SUCCESS){
|
|
result = (ll_append(&config->states, new_pattern) == LIBDS_SUCCESS) ?
|
|
LIBLEX_SUCCESS : LIBLEX_MALLOC;
|
|
}
|
|
if(result != LIBLEX_SUCCESS){
|
|
pattern_free(new_pattern);
|
|
free(new_pattern);
|
|
}
|
|
} else {
|
|
result = LIBLEX_MALLOC;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int _eval_config_foreach_free(void *data, va_list args){
|
|
pattern* ptrn = data;
|
|
int result = pattern_free(ptrn) == LIBLEX_SUCCESS ? 0 : EVAL_FOREACH_MALLOC;
|
|
free(ptrn);
|
|
return result;
|
|
}
|
|
|
|
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 == LIBDS_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){
|
|
pattern* new_pattern = data;
|
|
ht* pairmap = va_arg(args, ht*);
|
|
pattern_node* pattern_head = new_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 return_code = 0;
|
|
pattern_node* node = data;
|
|
eval* evl = va_arg(args, eval*);
|
|
if(_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) == LIBLEX_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;
|
|
eval->matched = 0;
|
|
liblex_result 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(char* string, int 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 = -1;
|
|
mtch->to = -1;
|
|
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(char* string, int 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;
|
|
}
|