Implement pattern compilation and freeing.
This commit is contained in:
parent
d8ddaa8b45
commit
ee40622ceb
288
src/pattern.c
288
src/pattern.c
|
@ -1,6 +1,9 @@
|
|||
#include "pattern.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pattern.h>
|
||||
#include "sprs.h"
|
||||
#include "ll.h"
|
||||
|
||||
void _pattern_node_clear(pattern_node* to_clear){
|
||||
to_clear->type = PNODE_CLEAR;
|
||||
|
@ -135,3 +138,288 @@ void _pattern_chain_append_chain(pattern_chain* append_to, pattern_chain* to_app
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
int _pattern_node_foreach_free(void* node, va_list args){
|
||||
free(node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _pattern_node_find_all(pattern_node* node, sprs* set){
|
||||
if(node && !sprs_contains(set, node->id)){
|
||||
sprs_put(set, node->id, node);
|
||||
if(node->type == PNODE_ANY) {
|
||||
_pattern_node_find_all(node->data_u.any_s.next, set);
|
||||
} else if(node->type == PNODE_CONNECT){
|
||||
_pattern_node_find_all(node->data_u.connect_s.next, set);
|
||||
} else if(node->type == PNODE_FORK){
|
||||
_pattern_node_find_all(node->data_u.fork_s.left, set);
|
||||
_pattern_node_find_all(node->data_u.fork_s.right, set);
|
||||
} else if(node->type == PNODE_RANGE){
|
||||
_pattern_node_find_all(node->data_u.range_s.next, set);
|
||||
} else if(node->type == PNODE_VALUE){
|
||||
_pattern_node_find_all(node->data_u.value_s.next, set);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
liblex_result _pattern_free(pattern_node* root, int size){
|
||||
sprs set;
|
||||
liblex_result result;
|
||||
sprs_init(&set);
|
||||
result = (sprs_setup(&set, size) == LIBDS_SUCCESS) ? LIBLEX_SUCCESS : LIBLEX_MALLOC;
|
||||
if(result == LIBLEX_SUCCESS){
|
||||
_pattern_node_find_all(root, &set);
|
||||
sprs_foreach(&set, NULL, compare_always, _pattern_node_foreach_free);
|
||||
}
|
||||
sprs_free(&set);
|
||||
return result;
|
||||
}
|
||||
|
||||
liblex_result _pattern_read_value(char* read_into, char* string, int* index){
|
||||
liblex_result result = LIBLEX_SUCCESS;
|
||||
if(string[*index] == '\\'){
|
||||
(*index)++;
|
||||
}
|
||||
if(string[*index]) {
|
||||
*read_into = string[*index];
|
||||
(*index)++;
|
||||
} else {
|
||||
result = LIBLEX_INVALID;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
liblex_result _pattern_build_or(pattern_chain** into, int* ids, char* string, int* index) {
|
||||
pattern_node *tail_node;
|
||||
liblex_result result = LIBLEX_SUCCESS;
|
||||
result = _pattern_node_create_connect(&tail_node, (*ids)++, NULL);
|
||||
if (result == LIBLEX_SUCCESS) {
|
||||
result = _pattern_chain_create(into, NULL, tail_node);
|
||||
}
|
||||
|
||||
while (string[*index] && string[*index] != ']' && result == LIBLEX_SUCCESS) {
|
||||
char from = '\0';
|
||||
char to = '\0';
|
||||
pattern_node *new_node = NULL;
|
||||
pattern_node *fork_node = NULL;
|
||||
pattern_node *add_node = NULL;
|
||||
result = _pattern_read_value(&from, string, index);
|
||||
if (result == LIBLEX_SUCCESS) {
|
||||
if (string[*index] == '-') {
|
||||
(*index)++;
|
||||
result = _pattern_read_value(&to, string, index);
|
||||
}
|
||||
}
|
||||
|
||||
if (result == LIBLEX_SUCCESS) {
|
||||
if (to) {
|
||||
result = _pattern_node_create_range(&new_node, (*ids)++, from, to, tail_node);
|
||||
} else {
|
||||
result = _pattern_node_create_value(&new_node, (*ids)++, from, tail_node);
|
||||
}
|
||||
add_node = new_node;
|
||||
}
|
||||
|
||||
if (result == LIBLEX_SUCCESS && (*into)->head) {
|
||||
result = _pattern_node_create_fork(&fork_node, (*ids)++, (*into)->head, new_node);
|
||||
if (result == LIBLEX_SUCCESS) {
|
||||
add_node = fork_node;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == LIBLEX_SUCCESS) {
|
||||
(*into)->head = add_node;
|
||||
} else {
|
||||
free(new_node);
|
||||
free(fork_node);
|
||||
}
|
||||
}
|
||||
|
||||
if (result != LIBLEX_SUCCESS) {
|
||||
if (*into && (*into)->head) {
|
||||
_pattern_free((*into)->head, *ids);
|
||||
} else {
|
||||
free(tail_node);
|
||||
}
|
||||
free(*into);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void _pattern_chain_append_chain_discard(pattern_chain* append_to, pattern_chain** to_append){
|
||||
_pattern_chain_append_chain(append_to, *to_append);
|
||||
free(*to_append);
|
||||
*to_append = NULL;
|
||||
}
|
||||
|
||||
liblex_result _pattern_build_chain(pattern_chain** into, int* ids, char* string, int* index){
|
||||
liblex_result result = LIBLEX_SUCCESS;
|
||||
ll or_stack;
|
||||
pattern_chain* current_chain = NULL;
|
||||
pattern_chain* sub_chain = NULL;
|
||||
int is_subchain = (*index > -1) && (string[*index] == '(');
|
||||
|
||||
ll_init(&or_stack);
|
||||
result = _pattern_chain_create(¤t_chain, NULL, NULL);
|
||||
if(result == LIBLEX_SUCCESS){
|
||||
(*index)++;
|
||||
}
|
||||
|
||||
while(string[*index] && string[*index] != ')' && result == LIBLEX_SUCCESS){
|
||||
if(string[*index] == '('){
|
||||
_pattern_chain_append_chain_discard(current_chain, &sub_chain);
|
||||
result = _pattern_build_chain(&sub_chain, ids, string, index);
|
||||
} else if(string[*index] == '['){
|
||||
_pattern_chain_append_chain_discard(current_chain, &sub_chain);
|
||||
result = _pattern_build_or(&sub_chain, ids, string, index);
|
||||
} else if(string[*index] == '?' || string[*index] == '*' || string[*index] == '+'){
|
||||
if(sub_chain != NULL && sub_chain->head){
|
||||
pattern_node* connection_node = NULL;
|
||||
pattern_node* fork_node = NULL;
|
||||
|
||||
result = _pattern_node_create_connect(&connection_node, (*ids)++, NULL);
|
||||
if(result == LIBLEX_SUCCESS){
|
||||
result = _pattern_node_create_fork(&fork_node, (*ids)++, sub_chain->head, connection_node);
|
||||
}
|
||||
|
||||
if(result == LIBLEX_SUCCESS){
|
||||
pattern_node** next_node = _pattern_node_get_next(sub_chain->tail);
|
||||
if(next_node){
|
||||
*next_node = (string[*index] == '?') ? connection_node : fork_node;
|
||||
sub_chain->head = (string[*index] == '+') ? sub_chain->head : fork_node;
|
||||
sub_chain->tail = connection_node;
|
||||
} else {
|
||||
result = LIBLEX_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
if(result == LIBLEX_SUCCESS){
|
||||
_pattern_chain_append_chain_discard(current_chain, &sub_chain);
|
||||
(*index)++;
|
||||
} else {
|
||||
free(connection_node);
|
||||
free(fork_node);
|
||||
}
|
||||
} else {
|
||||
result = LIBLEX_INVALID;
|
||||
}
|
||||
} else if(string[*index] == '|'){
|
||||
_pattern_chain_append_chain_discard(current_chain, &sub_chain);
|
||||
|
||||
if(current_chain->head){
|
||||
result = (ll_append(&or_stack, current_chain) == LIBDS_SUCCESS) ? LIBLEX_SUCCESS : LIBLEX_MALLOC;
|
||||
} else {
|
||||
result = LIBLEX_INVALID;
|
||||
}
|
||||
if(result == LIBLEX_SUCCESS){
|
||||
result = _pattern_chain_create(¤t_chain, NULL, NULL);
|
||||
(*index)++;
|
||||
}
|
||||
} else {
|
||||
char new_char = '\0';
|
||||
pattern_node* new_node = NULL;
|
||||
|
||||
_pattern_chain_append_chain_discard(current_chain, &sub_chain);
|
||||
result = _pattern_read_value(&new_char, string, index);
|
||||
if(result == LIBLEX_SUCCESS){
|
||||
result = _pattern_chain_create(&sub_chain, NULL, NULL);
|
||||
}
|
||||
if(result == LIBLEX_SUCCESS){
|
||||
result = _pattern_node_create_value(&new_node, (*ids)++, new_char, NULL);
|
||||
}
|
||||
if(result == LIBLEX_SUCCESS){
|
||||
sub_chain->head = sub_chain->tail = new_node;
|
||||
} else {
|
||||
free(new_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(is_subchain && result == LIBLEX_SUCCESS && string[*index] != ')'){
|
||||
result = LIBLEX_INVALID;
|
||||
}
|
||||
|
||||
if(result == LIBLEX_SUCCESS){
|
||||
_pattern_chain_append_chain_discard(current_chain, &sub_chain);
|
||||
}
|
||||
|
||||
if(result == LIBLEX_SUCCESS && or_stack.head){
|
||||
pattern_node* connect_node = NULL;
|
||||
|
||||
result = _pattern_node_create_connect(&connect_node, (*ids)++, NULL);
|
||||
if(result == LIBLEX_SUCCESS){
|
||||
_pattern_chain_append_node(current_chain, connect_node);
|
||||
}
|
||||
while(or_stack.head && result == LIBLEX_SUCCESS){
|
||||
pattern_node* fork = NULL;
|
||||
pattern_chain* new_chain = ll_pophead(&or_stack);
|
||||
|
||||
if(new_chain && new_chain->head){
|
||||
result = _pattern_node_create_fork(&fork, (*ids)++, current_chain->head, new_chain->head);
|
||||
if(result == LIBLEX_SUCCESS){
|
||||
_pattern_chain_append_node(new_chain, connect_node);
|
||||
current_chain->head = fork;
|
||||
} else {
|
||||
_pattern_free(new_chain->head, *ids);
|
||||
}
|
||||
free(new_chain);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(result != LIBLEX_SUCCESS){
|
||||
if(current_chain){
|
||||
_pattern_free(current_chain->head, *ids);
|
||||
}
|
||||
free(current_chain);
|
||||
if(sub_chain){
|
||||
_pattern_free(sub_chain->head, *ids);
|
||||
}
|
||||
free(sub_chain);
|
||||
while(or_stack.head){
|
||||
pattern_chain* new_chain = ll_pophead(&or_stack);
|
||||
if(new_chain){
|
||||
_pattern_free(new_chain->head, *ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(result == LIBLEX_SUCCESS){
|
||||
*into = current_chain;
|
||||
if(is_subchain) {
|
||||
(*index)++;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
liblex_result pattern_compile(pattern* ptrn, char* expression, int id){
|
||||
liblex_result result;
|
||||
pattern_node* end_node = NULL;
|
||||
pattern_chain* full_chain = NULL;
|
||||
int index = -1;
|
||||
int ids = 0;
|
||||
|
||||
result = _pattern_build_chain(&full_chain, &ids, expression, &index);
|
||||
if(result == LIBLEX_SUCCESS){
|
||||
result = _pattern_node_create_end(&end_node, ids, id);
|
||||
}
|
||||
if(result == LIBLEX_SUCCESS){
|
||||
_pattern_chain_append_node(full_chain, end_node);
|
||||
ptrn->head = full_chain->head;
|
||||
ptrn->size = ids + 1;
|
||||
free(full_chain);
|
||||
} else {
|
||||
if(full_chain){
|
||||
_pattern_free(full_chain->head, ids);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
liblex_result pattern_free(pattern* ptrn){
|
||||
return _pattern_free(ptrn->head, ptrn->size);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user