FM-SBLEX-3.0: src/lib/trie_lib.c
/*
A Trie ADT for insertion and traversal.
Copyright (C) 2004 Author: Markus Forsberg
Please send bug reports to: markus@cs.chalmers.se
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more deails.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <math.h>
#include "trie_lib.h"
#include <string.h>
/************************ Defines **************************************/
#define MAXLINE 1000
#define ACCEPT_ZERO 1
#define DELIMITER ':'
#define DOT 10000
/*******************************************************/
Trie global_trie = NULL;
Values global_value= NULL;
int global_count = 0;
int global_uniq_count = 0;
// int global_transitions = 0;
time_t global_t1 ;
bool global_reversed = false ;
bool global_countable = true ;
/*******************************************************/
/* LOCAL */
Values addValue(Values val, const char* s){
Values n_val = (Values) malloc(sizeof(Values)) ;
n_val -> string = s ;
n_val -> next = val ;
return n_val ;
}
/* EXPORT */
int getNumber(const char* str){
int pos;
for(pos = 0 ; pos < strlen(str); pos++){
if(str[pos] == '\"' && isdigit (str[pos+1]))
break;
}
size_t size = strspn(&str[pos+1],"1234567890") ;
char* number = malloc(sizeof(char)*size);
memcpy(number,&str[pos+1],size);
return atoi(number);
}
/*
int getNumber(const char* str){
char* tmp;
strcpy(tmp,str);
tmp = strreverse(tmp) ;
tmp = strchr(tmp,'\"');
size_t size = strspn(++tmp,"1234567890");
char* tmp2 = malloc(sizeof(char)*size);
memcpy(tmp2, tmp, size);
tmp = strreverse(tmp2) ;
return atoi(tmp2);
}
*/
/* public domain by Bob Stout */
char *strreverse(char *str)
{
char *p1, *p2;
if (! str || ! *str)
return str;
for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
{
*p1 ^= *p2;
*p2 ^= *p1;
*p1 ^= *p2;
}
return str;
}
/* EXPORT */
char* next(){
char* result ;
if(more()) {
result = (char*) global_value -> string ;
global_value = global_value -> next ;
return result ;
}
else return "";
}
/* EXPORT */
bool more(){
return global_value != NULL;
}
/***************** List functions *************************************/
/* LOCAL */
List addList(List list, Trie trie, char c){
List new = malloc(sizeof(List));
new -> c = c;
new -> trie = trie;
new -> next = list;
return new;
}
/* LOCAL */
Trie lookupList(List list, char cl){
List list_traversal = list;
while(1){
if(list_traversal == NULL){
return NULL;
}
else{
if((list_traversal -> c) == cl)
return list_traversal -> trie;
else
list_traversal = list_traversal -> next;
}
}
}
/***************** Trie functions *************************************/
/* LOCAL */
Trie newTrie(){
Trie trie;
trie = (Trie) malloc(sizeof(Trie));
trie -> list = NULL;
trie -> value = NULL;
return trie;
}
/* LOCAL */
Trie add(Trie trie, char c){
List l;
Trie t = lookupList(trie -> list,c);
if (t != NULL) return t;
else{
// global_transitions++ ;
t = newTrie();
l = addList(trie -> list,t,c);
trie -> list = l;
return t;
}
}
/* LOCAL */
Trie move(Trie trie, char c){
return lookupList(trie -> list,c);
}
void reversed(){
global_reversed = true ;
}
void no_count(){
global_countable = false ;
}
/* LOCAL */
void insert(Trie trie, const char *word,const char* result){
Trie traversal_ptr;
char *result_copy;
int index;
bool b = false;
result_copy = malloc(sizeof(char)*(strlen(result)+1));
strcpy(result_copy,result);
traversal_ptr = trie;
if(global_reversed){
for(index=strlen(word) ; index >= 0 ; index--){
traversal_ptr = add(traversal_ptr,word[index]);
}
}
else{
for(index=0 ; index < strlen(word) ; index++){
traversal_ptr = add(traversal_ptr,word[index]);
}
}
if (traversal_ptr -> value == NULL) /* no previous value at node */
if(global_countable)
global_uniq_count++;
traversal_ptr -> value = addValue(traversal_ptr -> value,result_copy);
if(global_countable)
global_count++ ;
if(global_count % DOT == 0)
fprintf(stderr,".");
}
/* GLOBAL */
void insert_t(const char *word, const char* result){
insert(global_trie, word, result) ;
}
/* LOCAL */
Values accept(Trie trie, const char *word){
Trie traversal_ptr = trie;
int index;
/* Traverse the word */
if(global_reversed){
for(index=strlen(word) ; index >= 0 ; index--){
traversal_ptr = move(traversal_ptr, word[index]);
if(traversal_ptr == NULL)
return NULL;
}
}
else{
for(index=0 ; index < strlen(word) ; index++){
traversal_ptr = move(traversal_ptr, word[index]);
if(traversal_ptr == NULL)
return NULL;
}
}
/* Final state reached */
return traversal_ptr -> value;
}
/************* File operations ************************************/
/* LOCAL: Splits a line into two, with the delimiter DELIMITER */
int split(const char *line, char *fst, char *snd){
int i;
char*tmp;
tmp = strchr(line,DELIMITER);
tmp++;
strcpy(snd,tmp);
for(i=0; i <= MAXLINE ; i++){
if(line[i] != DELIMITER)
fst[i] = line[i];
else
if(line[i+1] == '{')
{
fst[i] = '\0';
return 1;
}
}
return 0;
}
/* EXPORT */
void empty(){
global_trie = newTrie();
}
void start(){
// if(global_reversed)
// fprintf(stderr, "reversed ");
fprintf(stderr, "computing ['.': 10k word forms]: ");
time(&global_t1);
}
void stop(){
time_t t2;
time(&t2);
if(global_count < 1000000){
fprintf(stderr,"\n\n%dk word forms ", global_count/1000);
}
else{
fprintf(stderr,"\n\n%.2fM word forms ", global_count/1000000.0);
}
fprintf(stderr,"[c: %d, u: %d]\n", global_count,global_uniq_count);
// fprintf(stderr,"Trie size (transitions): %.2e\n", (double)global_transitions);
fprintf(stderr,"compile time: %.2f seconds\n", difftime(t2,global_t1));
}
/* EXPORT */
void build(const char *filename){
FILE *file_ptr;
char line[MAXLINE];
char fst[MAXLINE];
char snd[MAXLINE];
char* status;
char* p;
start();
// fprintf(stderr,"Lexicon file: %s\n", filename);
global_trie = newTrie();
file_ptr = fopen(filename,"r");
while(1){
status = fgets(line, MAXLINE,file_ptr);
if(status == NULL)
break;
if ((p = strchr(line, '\n')) != NULL)
*p = '\0';
if(split(line,fst,snd))
if(strlen(snd) > 0 || ACCEPT_ZERO)
insert(global_trie,fst,snd) ;
}
stop();
}
/* EXPORT */
void lookup_t(const char* word){
global_value = accept(global_trie,word);
}
/* EXPORT */
bool in_t(const char* word){
Values val;
val = accept(global_trie,word);
return val != NULL;
}
/* UNALLOCATE Memory */
/* LOCAL */
void freeValues(Values val){
if(val == NULL)
return;
freeValues(val -> next);
free(val);
}
void freeTrie(Trie trie) ;
/* LOCAL */
void freeList(List list){
if(list == NULL)
return;
freeTrie(list -> trie);
freeList(list -> next);
}
/* LOCAL */
void freeTrie(Trie trie){
if(trie == NULL)
return;
freeValues(trie -> value);
freeList(trie -> list);
free(trie);
}
/* EXPORT */
void free_trie(){
freeTrie(global_trie);
freeValues(global_value);
}