Implement pattern compilation and freeing.

This commit is contained in:
Danila Fedorin 2017-01-21 21:19:12 -08:00
parent d8ddaa8b45
commit ee40622ceb

View File

@ -1,6 +1,9 @@
#include "pattern.h" #include "pattern.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <pattern.h>
#include "sprs.h"
#include "ll.h"
void _pattern_node_clear(pattern_node* to_clear){ void _pattern_node_clear(pattern_node* to_clear){
to_clear->type = PNODE_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(&current_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(&current_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);
}