diff --git a/.gitignore b/.gitignore index 1c9b0d0..c3da5a2 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ src/tests/#CMakeLists.txt# src/tests/tests build/ *.vst -*.so \ No newline at end of file +*.so +*.so.* diff --git a/CMakeLists.txt b/CMakeLists.txt index c29fa16..83e4bef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,9 +4,12 @@ cmake_minimum_required (VERSION 2.6) project(varnam) set(VARNAM_LIBRARY_NAME "varnam") -set(SEXPR_LIBRARY_NAME "sexpr") set(FOREIGN_LIBRARY_NAME "foreign-functions") +set(VARNAM_VERSION_MAJOR 1) +set(VARNAM_VERSION_MINOR 0) +set(VARNAM_VERSION_PATCH 1) + IF(CMAKE_COMPILER_IS_GNUCC) set(CMAKE_C_FLAGS "-g -Wall -ansi -pedantic -Wconversion -Wformat=2 -Wshadow -Wcast-qual -Wwrite-strings") ENDIF() @@ -21,32 +24,41 @@ add_definitions(-DHAVE_SNPRINTF -DPREFER_PORTABLE_SNPRINTF) # Append the source files here list (APPEND VARNAM_SOURCES - compile.c - util.c - trie.c - strbuf.c - lex.c - parser.c - vstgen.c - tl.c + varnam-util.c + varnam-trie.c + varnam-strbuf.c + varnam-tl.c varnam.c ) +# Append the header files here. this will get copied to include directory +list (APPEND VARNAM_INCLUDE_FILES + varnam.h + varnam-result-codes.h + varnam-trie.h + varnam-types.h + varnam-util.h + ) + # Build foreign functions add_subdirectory(foreign) + +# Create a shared library libvarnam +add_library (${VARNAM_LIBRARY_NAME} SHARED ${VARNAM_SOURCES}) -# Build the sexpr library -add_subdirectory(sexpr) +SET_TARGET_PROPERTIES(${VARNAM_LIBRARY_NAME} PROPERTIES + VERSION ${VARNAM_VERSION_MAJOR}.${VARNAM_VERSION_MINOR}.${VARNAM_VERSION_PATCH} + SOVERSION ${VARNAM_VERSION_MAJOR}) -# Create a shared library libvarnam -add_library (${VARNAM_LIBRARY_NAME} SHARED ${VARNAM_SOURCES}) +INSTALL ( TARGETS ${VARNAM_LIBRARY_NAME} DESTINATION lib) +INSTALL ( FILES ${VARNAM_INCLUDE_FILES} DESTINATION include/lib${VARNAM_LIBRARY_NAME}) IF(CMAKE_COMPILER_IS_GNUCC) # sqlite requires pthread and dl - target_link_libraries(${VARNAM_LIBRARY_NAME} ${SEXPR_LIBRARY_NAME} ${FOREIGN_LIBRARY_NAME} pthread dl) + target_link_libraries(${VARNAM_LIBRARY_NAME} ${FOREIGN_LIBRARY_NAME} pthread dl) ENDIF() IF(MSVC) - target_link_libraries(${VARNAM_LIBRARY_NAME} ${SEXPR_LIBRARY_NAME} ${FOREIGN_LIBRARY_NAME}) + target_link_libraries(${VARNAM_LIBRARY_NAME} ${FOREIGN_LIBRARY_NAME}) ENDIF() diff --git a/compile.c b/compile.c deleted file mode 100644 index b6e6f08..0000000 --- a/compile.c +++ /dev/null @@ -1,143 +0,0 @@ -/* compile.c - * - * Copyright (C) 2010 Navaneeth.K.N - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - - * This library 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 - * Lesser General Public License for more details. - - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - - -#include -#include "util.h" -#include "sexpr/sexp.h" -#include "parser.h" -#include "trie.h" -#include "varnam.h" -#include "varnam-result-codes.h" - -const char compile_usage[] = - "compile: varnam compile [--help] [output_directory]\n"; - -extern int varnam_generate_symbols(const char *output_file_path, struct trie *result, char **error_message); - -struct compile_parameters { - const char *scheme_file; - const char *output_directory; -}; - -static void exp_tostring(sexp_t *exp, struct strbuf *string) -{ - sexp_t *e; - assert(exp); - - if(exp->ty == SEXP_VALUE) - { - strbuf_add(string, exp->val); - strbuf_add(string, " "); - } - else - { - strbuf_add(string, " ("); - for(e = exp->list; e != NULL; e = e->next) { - exp_tostring(e, string); - } - strbuf_add(string, ")"); - } -} - -static void handle_error(struct parser_result *pr) -{ - unsigned int error_count = 0; - struct parser_error *err; - struct exp_list *expression; - struct strbuf *string; - - string = strbuf_init(100); - - for(err = pr->err; err != NULL; err = err->next) { - ++error_count; - varnam_error(":: %d) %s", error_count, err->message); - for(expression = err->call_stack; expression != NULL; expression = expression->next) { - strbuf_clear(string); - exp_tostring( expression->exp, string ); - varnam_error(":: in : %s", string->buffer); - } - varnam_error("::"); - } - - strbuf_destroy(string); - - varnam_error(":: %d errors. Compilation aborted.", error_count); -} - -static int compile_scheme_file(varnam *handle, const char *scheme_file, const char *output_directory) -{ - char output_file_path[MAX_PATH_LENGTH], *error_message = NULL; - struct parser_result *pr = NULL; - int status; - - struct path_info *pinfo = splitpath(scheme_file); - const char *directory = output_directory ? output_directory : pinfo->directory; - const char *extension = ".vst"; - - if(pinfo->filename == 0 || strcmp(pinfo->filename, "") == 0) { - varnam_error("compile: invalid scheme file specified. aborting."); - return VARNAM_ERROR; - } - - strncpy(output_file_path, directory, MAX_PATH_LENGTH); - strcat(output_file_path, pinfo->filename); - strcat(output_file_path, extension); - - status = parser_init(scheme_file); - if(status != VARNAM_SUCCESS) { - varnam_error(":: Compilation failed for '%s'", scheme_file); - xfree( pinfo ); - return status; - } - - pr = parser_parse(); - if(pr->err != NULL) { - handle_error( pr ); - xfree( pinfo ); - parser_destroy( pr ); - return VARNAM_ERROR; - } - - status = varnam_generate_symbols(output_file_path, pr->result, &error_message); - if(status != VARNAM_SUCCESS) { - varnam_error(":: Compilation failed for %s", scheme_file); - xfree( pinfo ); - parser_destroy( pr ); - return status; - } - - varnam_info("::"); - varnam_info(":: Successfully compiled '%s'", scheme_file); - varnam_info(":: Created %s", output_file_path); - - xfree( pinfo ); - parser_destroy( pr ); - - return VARNAM_SUCCESS; -} - -int varnam_compile(varnam *handle, const char *scheme_file, const char *output_directory) -{ - if(handle == NULL || scheme_file == NULL) - return VARNAM_MISUSE; - - return compile_scheme_file(handle, scheme_file, output_directory); -} - - diff --git a/lex.c b/lex.c deleted file mode 100644 index 9f099bc..0000000 --- a/lex.c +++ /dev/null @@ -1,277 +0,0 @@ - -/* lex.c - a lexical tokenizer - * - * Copyright (C) Navaneeth.K.N - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - - * This library 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 - * Lesser General Public License for more details. - - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - - -#include -#include "util.h" -#include "sexpr/sexp.h" -#include "lex.h" -#include "varnam-result-codes.h" - -#define PAGE_SIZE 4096 -#define READ_ONLY_MODE "r" -#define SIZEOF_ELEMENT_TO_READ 1 - -struct lexmetadata { - - /* file descriptor */ - FILE *fd; - - /* buffer that will hold data read from file */ - char buffer[PAGE_SIZE + 1]; - - /* current status of the lexer */ - lex_statuscodes lex_status; - - /* the continuation used by the s-expr library */ - pcont_t *continuation; - - /* event handlers used to form the partial expression */ - parser_event_handlers_t event_handlers; - - /* error message set by the lexer */ - const char *message; - - /* this will have the text seen by the lex. - * this will be cleared when we find a valid expression - */ - struct strbuf *partial_exp; -}; - -static struct lexmetadata *data = NULL; - -static void start_sexpr() -{ - strbuf_add(data->partial_exp, "("); -} - -static void end_sexpr() -{ - strbuf_add(data->partial_exp, ")"); -} - -static void atom_found(const char *atom_data, size_t length, atom_t atom) -{ - switch(atom) - { - case SEXP_BASIC: - strbuf_add(data->partial_exp, atom_data); - break; - case SEXP_SQUOTE: - strbuf_add(data->partial_exp, "'"); - strbuf_add(data->partial_exp, atom_data); - break; - case SEXP_DQUOTE: - strbuf_add(data->partial_exp, "\""); - strbuf_add(data->partial_exp, atom_data); - strbuf_add(data->partial_exp, "\""); - break; - default: - /* should not have got here */ - strbuf_add(data->partial_exp, atom_data); - break; - } - - /** - * this may induce extra spaces, but we have no way to find out space was there on the - * real expression. - */ - strbuf_add(data->partial_exp, " "); -} - -static void change_status(lex_statuscodes newstatus, const char *message) -{ - data->lex_status = newstatus; - data->message = message; -} - -static struct lexmetadata *create_metadata() -{ - data = (struct lexmetadata*) xmalloc(sizeof (struct lexmetadata)); - data->fd = NULL; - data->buffer[0] = '\0'; - data->lex_status = LEX_OK; - data->continuation = NULL; - data->message = NULL; - data->partial_exp = strbuf_init(4096); - - data->event_handlers.start_sexpr = start_sexpr; - data->event_handlers.end_sexpr = end_sexpr; - data->event_handlers.characters = atom_found; - - return data; -} - -static size_t fill_buffer_from_disk() -{ - size_t elements_read = 0; - - assert(data->fd != NULL); - - elements_read = fread(data->buffer, SIZEOF_ELEMENT_TO_READ, PAGE_SIZE, data->fd); - if(elements_read != PAGE_SIZE) { - if(feof(data->fd)) { - change_status(LEX_EOF, ""); - } - else { - change_status(LEX_ERRORED, "unable to read the input file"); - return VARNAM_ERROR; - } - fclose(data->fd); - data->fd = NULL; - } - data->buffer[elements_read + 1] = '\0'; - return elements_read; -} - -/* - * will be called when iparse_sexp returns NULL. - * this will return boolean value indicating whether we can continue parsing - */ -static int handle_null_expression() -{ - if(sexp_errno == SEXP_ERR_INCOMPLETE) - { - /** - * if lexer is at EOF and we have nothing in partial expression string we consider it as a smooth run and - * lexer is done with it's job - */ - if(data->lex_status == LEX_EOF && strbuf_is_blank_string(data->partial_exp)) { - change_status(LEX_DONE, ""); - } - else if(data->lex_status == LEX_EOF) { - /* - * found an incomplete expression and we are at EOF! - * this is an error condition and not attempting for panic mode recovery. - */ - change_status(LEX_ERRORED, "Invalid expression found!"); - return VARNAM_ERROR; - } - else { - if(!fill_buffer_from_disk()) { - return VARNAM_ERROR; /* fill_buffer_from_disk sets the error parameter */ - } - } - } - else if(sexp_errno == SEXP_ERR_BADFORM || sexp_errno == SEXP_ERR_BADCONTENT) - { - change_status(LEX_ERRORED, - "Badly formed expression found. This can happen when you have misplaced paranthesis."); - return VARNAM_ERROR; - } - else - { - change_status(LEX_ERRORED, "Unknown error! unable to continue"); - return VARNAM_ERROR; - } - - return VARNAM_SUCCESS; -} - -lex_statuscodes lex_status() -{ - if(data == NULL) return LEX_OK; - return data->lex_status; -} - -const char* lex_message() -{ - if(data == NULL) return NULL; - return data->message; -} - -const char* lex_partial_expression() -{ - if(data == NULL) return NULL; - return data->partial_exp->buffer; -} - -int lex_init(const char *filename) -{ - data = create_metadata(); - data->fd = fopen(filename, READ_ONLY_MODE); - if(data->fd == NULL) { - change_status(LEX_ERRORED, "error opening input file"); - return VARNAM_ERROR; - } - return VARNAM_SUCCESS; -} - -/* - * seek to next s-expression. Return NULL if operation is not success - * and sets the error variable. This function reads data from the file and keeps it in a buffer. - * So there is no guarantee that each call to this function will lead into a disk read. If all data - * in the buffer is processed, there will be a disk read. - * - * Currently all lexical errors are considered as fatal. no attempt for panic mode recovery is performed. - * on error, lexer enters into errored state and won't perform any operations further. - * - * TODO : use the event handlers provided by the s-exp library to keep track of expression that we saw. - * this will help in better error reporting - */ - -sexp_t *lex_nextexp() -{ - sexp_t *sx = NULL; - - assert(data != NULL); - - if(data->lex_status == LEX_DONE || data->lex_status == LEX_ERRORED) return NULL; - - if(data->continuation == NULL) - { - if(!fill_buffer_from_disk()) { - return NULL; - } - data->continuation = init_continuation(data->buffer); - data->continuation->event_handlers = &data->event_handlers; - } - - for(; ;) - { - sx = iparse_sexp(data->buffer, PAGE_SIZE, data->continuation); - if(sx == NULL) - { - if(!handle_null_expression() || data->lex_status == LEX_DONE) { - break; - } - } - else { - strbuf_clear(data->partial_exp); - break; - } - } - - return sx; -} - -void lex_destroy_expression(sexp_t *expression) -{ - destroy_sexp(expression); -} - -void lex_destroy() -{ - if(data != NULL) { - strbuf_destroy(data->partial_exp); - destroy_continuation(data->continuation); - xfree(data); - } - sexp_cleanup(); -} diff --git a/parser.c b/parser.c deleted file mode 100644 index 8132e30..0000000 --- a/parser.c +++ /dev/null @@ -1,839 +0,0 @@ -/* parser.c - implements parser to parse the s-expression - * - * Copyright (C) Navaneeth.K.N - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - - * This library 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 - * Lesser General Public License for more details. - - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "util.h" -#include "lex.h" -#include "trie.h" -#include "sexpr/sexp.h" -#include "parser.h" -#include "varnam-result-codes.h" -#include -#include - -#define PARSER_HASH_SIZE 101 -#define PARSER_STACK_SIZE 1024 - -#define PARSER_SET_FN "set" -#define PARSER_CO_FN "co" -#define PARSER_CC_FN "cc" -#define PARSER_NU_FN "nu" -#define PARSER_VO_FN "vo" -#define PARSER_SY_FN "sy" -#define PARSER_OT_FN "ot" - -enum symbol_type { - SYMBOL_FUNCTION, - SYMBOL_VARIABLE -}; - -struct execution_context { - /* argument stack which is shared across functions. */ - /* const char *arg_stack[PARSER_STACK_SIZE]; */ - const char **arg_stack; - - /* 0 indexed stack pointer */ - int sp; - - /** - * eval_exp() adds each expression it evaluates to this list. If the evaluation is successful, - * it will remove the entry from here. This is used to report the expression trace when - * evaluation fails. - **/ - struct exp_list *call_stack; - - /* contains the error message written by the evaluation routines */ - char *error_message; - - struct trie *result; -}; - -/** - * Represents a symbol. This will be the value in - * symbol table - **/ -struct symbol { - enum symbol_type type; - - /* symbol name. this is used to identify the symbol */ - char name[PARSER_SYMBOL_MAX]; - - /* for variables, this field holds the value */ - char value[PARSER_SYMBOL_MAX]; - - /* true if this symbol is in reserved category */ - unsigned int reserved; - - /* for SYMBOL_FUNCTION, this holds the pointer to the function to be executed */ - /* it takes a context and number of arguments found. this function will be responsible for argument count matching */ - const char* (*function)(struct execution_context*, unsigned int); - - /* for reserved symbols, this field contains the routine that can process the command */ - int (*handler)(struct execution_context *context, sexp_t *sexp, struct symbol *s); - - struct symbol *next; -}; - -/* symbol table */ -struct symbol *st[PARSER_HASH_SIZE]; - -static void push_arg(struct execution_context *context, const char *item) -{ - assert(context != NULL); - if(context->sp == PARSER_STACK_SIZE - 1) { - varnam_error("Error: Stack overflow!"); - exit(100); /* TODO: standarize this error code */ - return; - } - context->arg_stack[++context->sp] = item; -} - -static const char *pop_arg(struct execution_context *context) -{ - assert(context != NULL); - assert(context->sp >= 0); - return context->arg_stack[context->sp--]; -} - -static const char *top_arg(struct execution_context *context) -{ - assert(context != NULL); - if(context->sp < 0) return NULL; - return context->arg_stack[context->sp]; -} - -static void free_token(void *tok) -{ - assert( tok ); - xfree( tok ); -} - -static void push_exp(struct execution_context *context, sexp_t *exp) -{ - struct exp_list *item = NULL; - - item = (struct exp_list *) xmalloc (sizeof (struct exp_list)); - assert(item); - - item->exp = exp; - item->next = context->call_stack; - context->call_stack = item; -} - -static void pop_exp(struct execution_context *context) -{ - struct exp_list *head = NULL; - assert(context->call_stack != NULL); - - if(context->call_stack->next == NULL) { - xfree( context->call_stack ); - context->call_stack = NULL; - } - else { - head = context->call_stack; - context->call_stack = context->call_stack->next; - xfree( head ); - } -} - -/** - * given a null terminated string, returns the hash value of it. - * this will be used as the key for table lookup. - **/ -static unsigned int hash(const char *s) -{ - unsigned int hashval; - assert(s); - for (hashval = 0; *s != '\0'; s++) - hashval = (unsigned char) *s + 31 * hashval; - return hashval % PARSER_HASH_SIZE; -} - -static struct symbol *lookup(const char *s) -{ - struct symbol *sym; - assert(s); - for (sym = st[hash(s)]; sym != NULL; sym = sym->next) - if (strcmp(s, sym->name) == 0) - return sym; - return NULL; -} - -static int install_symbol(struct symbol *sym) -{ - const char *name; - struct symbol *temp; - unsigned int hashval; - - assert(sym != NULL); - assert(sym->name != NULL); - - name = sym->name; - - if ((temp = lookup(name)) == NULL) { - hashval = hash(name); - sym->next = st[hashval]; - st[hashval] = sym; - } - else { - return VARNAM_ERROR; - } - return VARNAM_SUCCESS; -} - -static struct symbol *make_symbol(const char *name, - const char *value, - enum symbol_type type, - unsigned int reserved) -{ - struct symbol *s; - s = (struct symbol *) xmalloc(sizeof (struct symbol)); - assert(s); - - strncpy(s->name, name, PARSER_SYMBOL_MAX); - strncpy(s->value, value, PARSER_SYMBOL_MAX); - s->type = type; - s->reserved = reserved; - s->function = NULL; - s->handler = NULL; - s->next = NULL; - return s; -} - -static int argcount_ok(struct execution_context *context, - unsigned int expected, - unsigned int actual, - const char *function_name) -{ - if(expected != actual) { - snprintf(context->error_message, - PARSER_ERROR_MESSAGE_MAX, - "'%s' expects %d arguments but found %d", function_name, expected, actual); - return VARNAM_ERROR; - } - return VARNAM_SUCCESS; -} - -static struct token *create_token(const char *pattern, - const char *value1, - const char *value2, - enum token_type type) - -{ - struct token *tok = NULL; - assert(pattern); assert(value1); assert(value2); - - tok = (struct token *) xmalloc(sizeof (struct token)); - assert(tok); - - tok->type = type; - strncpy(tok->pattern, pattern, PARSER_SYMBOL_MAX); - strncpy(tok->value1, value1, PARSER_SYMBOL_MAX); - strncpy(tok->value2, value2, PARSER_SYMBOL_MAX); - - return tok; -} - -static int pattern_valid(struct execution_context *context, - const char *pattern, - const char *function_name) -{ - if(strlen (pattern) <= 0) { - snprintf(context->error_message, - PARSER_ERROR_MESSAGE_MAX, - "Empty patterns are not allowed in function '%s", function_name); - return VARNAM_ERROR; - } - return VARNAM_SUCCESS; -} - -static int value_valid(struct execution_context *context, - const char *value, - const char *function_name) -{ - if(strlen (value) <= 0) { - snprintf(context->error_message, - PARSER_ERROR_MESSAGE_MAX, - "Empty values are not allowed in function '%s", function_name); - return VARNAM_ERROR; - } - return VARNAM_SUCCESS; -} - -static int symbol_length_ok(struct execution_context *context, const char *sym) -{ - if(sym == NULL) return VARNAM_SUCCESS; - - if(strlen(sym) >= PARSER_SYMBOL_MAX) { - snprintf(context->error_message, - PARSER_ERROR_MESSAGE_MAX, - "'%s' exceeds allowed symbol size %d", sym, PARSER_SYMBOL_MAX); - return VARNAM_ERROR; - } - return VARNAM_SUCCESS; -} - -static const char *builtin_set(struct execution_context *context, unsigned int argcount) -{ - const char *name; - const char *value; - struct symbol *s; - - if(!argcount_ok (context, 2, argcount, PARSER_SET_FN)) { - return NULL; - } - - assert(context->sp >= 1); - value = pop_arg (context); - name = pop_arg (context); - - if(!symbol_length_ok( context, name ) || !symbol_length_ok( context, value )) { - return NULL; - } - - s = lookup(name); - if(s == NULL) { - s = make_symbol(name, value, SYMBOL_VARIABLE, 0); - install_symbol(s); - } - else if(s->reserved) { - snprintf(context->error_message, - PARSER_ERROR_MESSAGE_MAX, - "'%s' is a reserved word and can't be used as a variable name", name); - return NULL; - } - else { - strncpy(s->value, value, PARSER_SYMBOL_MAX); - } - - return value; -} - -/* creates a vowel */ -static const char *builtin_vo(struct execution_context *context, unsigned int argcount) -{ - const char *pattern = NULL, *value1 = NULL, *value2 = NULL; - struct token *tok = NULL; - - /* this function allows 2 or 3 arguments */ - if(!argcount_ok (context, 3, argcount, PARSER_VO_FN) && - !argcount_ok (context, 2, argcount, PARSER_VO_FN)) { - - snprintf(context->error_message, - PARSER_ERROR_MESSAGE_MAX, - "'vo' expects 2 or 3 arguments but found %d", argcount); - return NULL; - } - - if(argcount == 3) { - assert(context->sp >= 2); - value2 = pop_arg (context); - } - assert(context->sp >= 1); - value1 = pop_arg (context); - pattern = pop_arg (context); - - if(!symbol_length_ok( context, pattern ) || !symbol_length_ok( context, value1 ) || !symbol_length_ok( context, value2 )) { - return NULL; - } - - if(!pattern_valid(context, pattern, PARSER_VO_FN)) { - return NULL; - } - else if(!value_valid(context, value1, PARSER_VO_FN)) { - return NULL; - } - else if(argcount == 3 && !value_valid(context, value2, PARSER_VO_FN)) { - return NULL; - } - - tok = create_token(pattern, value1, value2 == NULL ? "" : value2, PARSER_TOKEN_VOWEL); - trie_add_child(context->result, pattern, tok); - - return value1; -} - -/* create a consonant */ -static const char *builtin_co(struct execution_context *context, unsigned int argcount) -{ - const char *pattern = NULL, *value = NULL; - struct token *tok = NULL; - - if(!argcount_ok (context, 2, argcount, PARSER_CO_FN)) { - return NULL; - } - - assert(context->sp >= 1); - value = pop_arg (context); - pattern = pop_arg (context); - - if(!symbol_length_ok( context, pattern ) || !symbol_length_ok( context, value )) { - return NULL; - } - - if(!pattern_valid(context, pattern, PARSER_CO_FN)) { - return NULL; - } - else if(!value_valid(context, value, PARSER_CO_FN)) { - return NULL; - } - - tok = create_token(pattern, value, "", PARSER_TOKEN_CONSONANT); - trie_add_child(context->result, pattern, tok); - - return value; -} - -/* create a consonant cluster */ -static const char *builtin_cc(struct execution_context *context, unsigned int argcount) -{ - const char *pattern = NULL, *value = NULL; - struct token *tok = NULL; - - if(!argcount_ok (context, 2, argcount, PARSER_CC_FN)) { - return NULL; - } - - assert(context->sp >= 1); - value = pop_arg (context); - pattern = pop_arg (context); - - if(!symbol_length_ok( context, pattern ) || !symbol_length_ok( context, value )) { - return NULL; - } - - if(!pattern_valid(context, pattern, PARSER_CC_FN)) { - return NULL; - } - else if(!value_valid(context, value, PARSER_CC_FN)) { - return NULL; - } - - tok = create_token(pattern, value, "", PARSER_TOKEN_CONSONANT_CLUSTER); - trie_add_child(context->result, pattern, tok); - - return value; -} - -/* create a number */ -static const char *builtin_nu(struct execution_context *context, unsigned int argcount) -{ - const char *pattern = NULL, *value = NULL; - struct token *tok = NULL; - - if(!argcount_ok (context, 2, argcount, PARSER_NU_FN)) { - return NULL; - } - - assert(context->sp >= 1); - value = pop_arg (context); - pattern = pop_arg (context); - - if(!symbol_length_ok( context, pattern ) || !symbol_length_ok( context, value )) { - return NULL; - } - - if(!pattern_valid(context, pattern, PARSER_NU_FN)) { - return NULL; - } - else if(!value_valid(context, value, PARSER_NU_FN)) { - return NULL; - } - - tok = create_token(pattern, value, "", PARSER_TOKEN_NUMBER); - trie_add_child(context->result, pattern, tok); - - return value; -} - -/* create a symbol */ -static const char *builtin_sy(struct execution_context *context, unsigned int argcount) -{ - const char *pattern = NULL, *value = NULL; - struct token *tok = NULL; - - if(!argcount_ok (context, 2, argcount, PARSER_SY_FN)) { - return NULL; - } - - assert(context->sp >= 1); - value = pop_arg (context); - pattern = pop_arg (context); - - if(!symbol_length_ok( context, pattern ) || !symbol_length_ok( context, value )) { - return NULL; - } - - if(!pattern_valid(context, pattern, PARSER_SY_FN)) { - return NULL; - } - else if(!value_valid(context, value, PARSER_SY_FN)) { - return NULL; - } - - tok = create_token(pattern, value, "", PARSER_TOKEN_SYMBOL); - trie_add_child(context->result, pattern, tok); - - return value; -} - -/* create a symbol imn 'other' category*/ -static const char *builtin_ot(struct execution_context *context, unsigned int argcount) -{ - const char *pattern = NULL, *value = NULL; - struct token *tok = NULL; - - if(!argcount_ok (context, 2, argcount, PARSER_OT_FN)) { - return NULL; - } - - assert(context->sp >= 1); - value = pop_arg (context); - pattern = pop_arg (context); - - if(!symbol_length_ok( context, pattern ) || !symbol_length_ok( context, value )) { - return NULL; - } - - if(!pattern_valid(context, pattern, PARSER_OT_FN)) { - return NULL; - } - else if(!value_valid(context, value, PARSER_OT_FN)) { - return NULL; - } - - tok = create_token(pattern, value, "", PARSER_TOKEN_OTHER); - trie_add_child(context->result, pattern, tok); - - return value; -} - -static int eval_exp_recursive(struct execution_context *context, sexp_t *exp) -{ - struct symbol *s; - int result = 0; - - assert(exp != NULL); assert(context != NULL); - - push_exp(context, exp); - - if(exp->ty == SEXP_VALUE) { - snprintf(context->error_message, - PARSER_ERROR_MESSAGE_MAX, - "'%s' is not a valid expression. A valid expression will look like (%s)", exp->val, exp->val); - return VARNAM_ERROR; - } - - assert(exp->list != NULL); - - /** - * expressions that are incorrectly nested like ((exp)) - */ - if(exp->list->ty != SEXP_VALUE) { - snprintf(context->error_message, - PARSER_ERROR_MESSAGE_MAX, - "Incorrect nested expression detected. Can't infer the executable command"); - return VARNAM_ERROR; - } - - assert(exp->list->val != NULL); - - s = lookup(exp->list->val); - if(s == NULL) { - snprintf(context->error_message, - PARSER_ERROR_MESSAGE_MAX, - "'%s' is not a valid command", exp->list->val); - return VARNAM_ERROR; - } - - result = s->handler(context, exp, s); - if(result != VARNAM_SUCCESS) { - return result; - } - - /** - * that was a successful execution! removing the expression in the stack as it doesn't - * make sense to keep it there - **/ - pop_exp( context ); - return VARNAM_SUCCESS; -} - -static int eval_function(struct execution_context *context, - sexp_t *sexp, - struct symbol *s) -{ - sexp_t *exp; - struct symbol *sym; - unsigned int argcount = 0; - const char *result; - - assert(s != NULL); - assert(s->type == SYMBOL_FUNCTION); - assert(s->name != NULL); - assert(sexp->ty == SEXP_LIST); - assert(sexp->list->ty == SEXP_VALUE); - - argcount = 0; - - /** - * reads each atom from the expression and pushes it to the stack. - * if it finds nested expression, ask eval_exp() to process it. - **/ - for(exp = sexp->list->next; exp != NULL; exp = exp->next) - { - if(exp->ty == SEXP_VALUE) - { - switch(exp->aty) - { - case SEXP_BASIC: - /* we saw an identifier. need to validate this against the known symbols */ - if(( sym = lookup(exp->val) ) == NULL) { - snprintf(context->error_message, - PARSER_ERROR_MESSAGE_MAX, - "'%s' is an unknown identifier", exp->val); - return VARNAM_ERROR; - } - else if(sym->type != SYMBOL_VARIABLE) { - snprintf(context->error_message, - PARSER_ERROR_MESSAGE_MAX, - "'%s' is invalid in this context. Expected a variable or literal", exp->val); - return VARNAM_ERROR; - - } - else { - push_arg(context, sym->value); - ++argcount; - } - break; - case SEXP_DQUOTE: - /* this is a double quoted string literal. pushing it as it is */ - push_arg(context, exp->val); - ++argcount; - break; - case SEXP_SQUOTE: - /* single quoted values are invalid */ - snprintf(context->error_message, - PARSER_ERROR_MESSAGE_MAX, - "'%s' is an invalid literal. String literals has to be specified within double quotes", exp->val); - return VARNAM_ERROR; - case SEXP_BINARY: - snprintf(context->error_message, - PARSER_ERROR_MESSAGE_MAX, - "Binary value found which is invalid"); - return VARNAM_ERROR; - } - } - else - { - /* seeing a nested expression. evaluate it and push the result into the stack */ - ++argcount; - if(eval_exp_recursive(context, exp) == VARNAM_ERROR) { - /* a nested expression failed. so this function evaluation also failed */ - return VARNAM_ERROR; - } - } - } - - /** - * if we reach here, it means that all the nested expressions are evaluated and we are good to execute the actual - * command. argument values are available in the stack. - **/ - result = s->function(context, argcount); - - if(result != NULL) { - if(top_arg(context) != NULL) { - /** - * stack has more data. so this will be a nested function call. need to push the result of last - * function call so that the caller can use it. - **/ - push_arg(context, result); - } - return VARNAM_SUCCESS; - } - else { - return VARNAM_ERROR; - } -} - -/** - * evaluates the supplied expression. Errors are writtern to the error list - */ -static void eval_exp(struct parser_result *res, sexp_t *exp) -{ - struct execution_context context; - struct parser_error *err = NULL, *temp = NULL; - const char *arg_stack[PARSER_STACK_SIZE]; - char error_message[PARSER_ERROR_MESSAGE_MAX]; - int status = 0; - - assert(exp != NULL); - assert(res != NULL); - - arg_stack[0] = ""; - error_message[0] = 0; - - context.arg_stack = arg_stack; - context.sp = 0; - context.call_stack = NULL; - context.error_message = error_message; - context.result = res->result; - - status = eval_exp_recursive(&context, exp); - if(status != VARNAM_SUCCESS) { - err = (struct parser_error *) xmalloc(sizeof (struct parser_error)); - assert(err); - - strcpy(err->message, context.error_message); - err->call_stack = context.call_stack; - err->next = NULL; - if(res->err == NULL) { - res->err = err; - } - else { - temp = res->err; - while (temp->next != NULL) temp = temp->next; - temp->next = err; - } - } - else { - destroy_sexp( exp ); - } -} - -struct parser_result *parser_parse() -{ - sexp_t *exp = NULL; - struct parser_result *result; - lex_statuscodes lexstatus; - - result = (struct parser_result *) xmalloc(sizeof (struct parser_result)); - assert(result); - - result->err = NULL; - result->result = trie_create(); - assert(result->result); - - for(; ;) { - exp = lex_nextexp(); - if(exp == NULL) { - lexstatus = lex_status(); - if(lex_status() == LEX_DONE) { - break; - } - else if(lex_status() == LEX_ERRORED) { - /* lex failed. this will stop the compilation as lexical errors here are non-recoverable */ - varnam_error("Lex error : %s", lex_message()); - break; /* TODO: print the message properly */ - } - break; - } - eval_exp(result, exp); - } - - return result; -} - -int parser_init(const char *filename) -{ - struct symbol *set, *vo, *co, *cc, *nu, *sy, *ot; - int ls; - - ls = lex_init(filename); - if(ls != VARNAM_SUCCESS) { - varnam_error("%s\n", lex_message()); - return ls; - } - - memset(&st[0], 0, sizeof(st)); - - /** - * default entries into the symbol table - **/ - set = make_symbol("set", "", SYMBOL_FUNCTION, 1); - set->function = &builtin_set; - set->handler = &eval_function; - install_symbol(set); - - vo = make_symbol("vo", "", SYMBOL_FUNCTION, 1); - vo->function = &builtin_vo; - vo->handler = &eval_function; - install_symbol(vo); - - co = make_symbol("co", "", SYMBOL_FUNCTION, 1); - co->function = &builtin_co; - co->handler = &eval_function; - install_symbol(co); - - cc = make_symbol("cc", "", SYMBOL_FUNCTION, 1); - cc->function = &builtin_cc; - cc->handler = &eval_function; - install_symbol(cc); - - nu = make_symbol("nu", "", SYMBOL_FUNCTION, 1); - nu->function = &builtin_nu; - nu->handler = &eval_function; - install_symbol(nu); - - sy = make_symbol("sy", "", SYMBOL_FUNCTION, 1); - sy->function = &builtin_sy; - sy->handler = &eval_function; - install_symbol(sy); - - ot = make_symbol("ot", "", SYMBOL_FUNCTION, 1); - ot->function = &builtin_ot; - ot->handler = &eval_function; - install_symbol(ot); - - return VARNAM_SUCCESS; -} - -void parser_destroy(struct parser_result *pr) -{ - int i; - struct symbol *sym = NULL, *next_sym = NULL; - struct parser_error *err = NULL, *next_err = NULL; - struct exp_list *exps, *next_exps = NULL; - - /* cleaning the symbol table entries */ - for(i = 0; i < PARSER_HASH_SIZE; i++) { - for(sym = st[i]; sym != NULL;) { - next_sym = sym->next; - xfree(sym); - sym = next_sym; - } - } - - /* cleaning the error list */ - for(err = pr->err; err != NULL;) { - next_err = err->next; - for( exps = err->call_stack; exps != NULL; ) { - next_exps = exps->next; - if( exps->exp ) { - destroy_sexp( exps->exp ); - } - xfree( exps ); - exps = next_exps; - } - xfree( err ); - err = next_err; - } - - trie_free( pr->result, free_token ); - lex_destroy(); - xfree( pr ); -} diff --git a/parser.h b/parser.h deleted file mode 100644 index ba18085..0000000 --- a/parser.h +++ /dev/null @@ -1,66 +0,0 @@ -/* parser.h - implements parser to parse the s-expression - * - * Copyright (C) Navaneeth.K.N - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - - * This library 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 - * Lesser General Public License for more details. - - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - - -#ifndef PARSER_H_INCLUDED_052443 -#define PARSER_H_INCLUDED_052443 - -#define PARSER_ERROR_MESSAGE_MAX 4000 -#define PARSER_SYMBOL_MAX 30 - -#include "sexpr/sexp.h" - -struct exp_list { - sexp_t *exp; - struct exp_list *next; -}; - -struct parser_error { - char message[PARSER_ERROR_MESSAGE_MAX]; - struct exp_list *call_stack; - struct parser_error *next; -}; - -enum token_type { - PARSER_TOKEN_VOWEL, - PARSER_TOKEN_CONSONANT, - PARSER_TOKEN_CONSONANT_CLUSTER, - PARSER_TOKEN_NUMBER, - PARSER_TOKEN_SYMBOL, - PARSER_TOKEN_OTHER -}; - -/* this will be the item in each trie node */ -struct token { - enum token_type type; - char pattern[PARSER_SYMBOL_MAX]; - char value1[PARSER_SYMBOL_MAX]; - char value2[PARSER_SYMBOL_MAX]; - int children; -}; - -struct parser_result { - struct parser_error *err; - struct trie *result; -}; - -int parser_init(const char *filename); -struct parser_result *parser_parse(); -void parser_destroy(struct parser_result *result); - -#endif diff --git a/util.c b/util.c deleted file mode 100644 index 18945fc..0000000 --- a/util.c +++ /dev/null @@ -1,121 +0,0 @@ -/* util.c - * - * Copyright (C) 2010 Navaneeth.K.N - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - - * This library 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 - * Lesser General Public License for more details. - - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - - -#include -#include -#include -#include -#include "util.h" - -void varnam_info(const char *format, ...) -{ - va_list args; - va_start(args, format); - vfprintf(stdout, format, args); - va_end(args); - printf("\n"); -} - -void varnam_error(const char *format, ...) -{ - va_list args; - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); - printf("\n"); -} - -#ifdef WIN32 -const char directory_separator[] = "\\"; -#else -const char directory_separator[] = "/"; -#endif - -struct path_info* splitpath(const char *full_path) -{ - size_t length = strlen(full_path); - struct path_info *p = (struct path_info*) xmalloc(sizeof(struct path_info) + length + 3); /* Extra space for padding and shifting */ - if(p) - { - char *path = (char *) &p[1]; /* copy of the path */ - char *end = &path[length + 1]; - char *extension; - char *last_separator; - - /* copy the path */ - strcpy(path, full_path); - *end = '\0'; - p->directory = end; - p->extension = end; - p->filename = path; - - last_separator = strrchr(path, directory_separator[0]); /* Finding the last directory separator */ - if(last_separator) { - memmove(last_separator + 1, last_separator, strlen(last_separator) + 1); /* inserting a directory separator where null terminator will be inserted */ - p->directory = path; - *(++last_separator) = '\0'; /* Truncate the directory path */ - p->filename = ++last_separator; /* Taking the remaining as file name */ - } - - /* Finding the extension starts from second character. This allows handling filenames - starts with '.' like '.emacs'.*/ - extension = strrchr(&p->filename[1], '.'); - if(extension) { - - /* shifting the bytes to preserve the extension */ - memmove(extension + 1, extension, strlen(extension) + 1); - p->extension = extension + 1; - - *extension = '\0'; /* Truncates the file name */ - } - } - return p; -} - -char *substr(char *dst, unsigned int start, unsigned int length, const char *src) -{ - sprintf(dst, "%.*s", length, src + start); - return dst; -} - -/* return true if string1 starts with string2 */ -int startswith(const char *string1, const char *string2) -{ - for(; ; string1++, string2++) { - if(!*string2) { - break; - } - else if(*string1 != *string2) { - return 0; - } - } - return 1; -} - -void *xmalloc(size_t size) -{ - void *ret = malloc(size); - return ret; -} - -void xfree (void *ptr) -{ - if(ptr) - free(ptr); -} diff --git a/strbuf.c b/varnam-strbuf.c similarity index 98% rename from strbuf.c rename to varnam-strbuf.c index e7fc051..d98f97b 100644 --- a/strbuf.c +++ b/varnam-strbuf.c @@ -17,7 +17,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include -#include "util.h" +#include + +#include "varnam-util.h" static int grow_buffer(struct strbuf *string) { diff --git a/tl.c b/varnam-tl.c similarity index 89% rename from tl.c rename to varnam-tl.c index 7357334..2c43893 100644 --- a/tl.c +++ b/varnam-tl.c @@ -16,15 +16,13 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "util.h" -#include "parser.h" -#include "foreign/sqlite3.h" -#include "varnam.h" -#include "varnam-result-codes.h" #include +#include -const char tl_usage[] = - "transliterate: varnam tl \n"; +#include "varnam-util.h" +#include "foreign/sqlite3.h" +#include "varnam-types.h" +#include "varnam-result-codes.h" static struct token *get_token(sqlite3 *db, const char *lookup) { @@ -49,8 +47,8 @@ static struct token *get_token(sqlite3 *db, const char *lookup) tok = (struct token *) xmalloc(sizeof (struct token)); assert( tok ); - strncpy( tok->pattern, pattern, PARSER_SYMBOL_MAX); - strncpy( tok->value1, value1, PARSER_SYMBOL_MAX); + strncpy( tok->pattern, pattern, VARNAM_SYMBOL_MAX); + strncpy( tok->value1, value1, VARNAM_SYMBOL_MAX); tok->children = has_children; } } @@ -63,7 +61,7 @@ static int can_find_solution(sqlite3 *db, struct token *last, const char *lookup { char sql[500]; sqlite3_stmt *stmt; - int rc; int result = VARNAM_ERROR; + int rc; int result = 0; assert( lookup ); @@ -79,7 +77,7 @@ static int can_find_solution(sqlite3 *db, struct token *last, const char *lookup rc = sqlite3_step( stmt ); if( rc == SQLITE_ROW ) { if( sqlite3_column_int( stmt, 0 ) > 0 ) { - result = VARNAM_SUCCESS; + result = 1; } } } @@ -111,7 +109,7 @@ static int tokenize(sqlite3 *db, matchpos = counter; if( last->children <= 0 ) break; } - else if( can_find_solution( db, last, lookup->buffer ) == VARNAM_ERROR ) { + else if( !can_find_solution( db, last, lookup->buffer )) { break; } ++text; diff --git a/trie.c b/varnam-trie.c similarity index 99% rename from trie.c rename to varnam-trie.c index a03731e..ab3caef 100644 --- a/trie.c +++ b/varnam-trie.c @@ -20,8 +20,10 @@ #include #include -#include "util.h" -#include "trie.h" +#include + +#include "varnam-util.h" +#include "varnam-trie.h" #include "varnam-result-codes.h" static struct trie *trie_new(const char *label, void *value) diff --git a/trie.h b/varnam-trie.h similarity index 98% rename from trie.h rename to varnam-trie.h index 4d92ba0..4288681 100644 --- a/trie.h +++ b/varnam-trie.h @@ -20,7 +20,7 @@ #ifndef TRIE_H_INCLUDED_095519 #define TRIE_H_INCLUDED_095519 -#include "util.h" +#include "varnam-util.h" struct trie { int root; /* if 1, then this is root */ diff --git a/lex.h b/varnam-types.h similarity index 52% rename from lex.h rename to varnam-types.h index 32f8850..26b07e3 100644 --- a/lex.h +++ b/varnam-types.h @@ -1,4 +1,4 @@ -/* lex.h - a lexical tokenizer +/* varnam-types.h * * Copyright (C) Navaneeth.K.N * @@ -16,26 +16,39 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef LEX_H_INCLUDED_080329 -#define LEX_H_INCLUDED_080329 - -#include "sexpr/sexp.h" - -typedef enum { - - LEX_OK, - LEX_EOF, - LEX_DONE, - LEX_ERRORED - -} lex_statuscodes; - -int lex_init(const char *filename); -sexp_t *lex_nextexp(); -void lex_destroy_expression(sexp_t *expression); -void lex_destroy(); -lex_statuscodes lex_status(); -const char* lex_message(); -const char* lex_partial_expression(); +#ifndef VARNAMLIB_H_INCLUDED_103830 +#define VARNAMLIB_H_INCLUDED_103830 + +#include "foreign/sqlite3.h" + +#define VARNAM_SYMBOL_MAX 30 +#define VARNAM_LIB_TEMP_BUFFER_SIZE 100 + +struct varnam_internal { + sqlite3 *db; + char *message; +}; + +typedef struct varnam { + char *symbols_file; + struct varnam_internal *internal; +} varnam; + +enum token_type { + VARNAM_TOKEN_VOWEL, + VARNAM_TOKEN_CONSONANT, + VARNAM_TOKEN_CONSONANT_CLUSTER, + VARNAM_TOKEN_NUMBER, + VARNAM_TOKEN_SYMBOL, + VARNAM_TOKEN_OTHER +}; + +struct token { + enum token_type type; + char pattern[VARNAM_SYMBOL_MAX]; + char value1[VARNAM_SYMBOL_MAX]; + char value2[VARNAM_SYMBOL_MAX]; + int children; +}; #endif diff --git a/varnam-util.c b/varnam-util.c new file mode 100644 index 0000000..4ee2a91 --- /dev/null +++ b/varnam-util.c @@ -0,0 +1,59 @@ +/* util.c + * + * Copyright (C) 2010 Navaneeth.K.N + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library 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 + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + + +#include +#include +#include +#include + +#include "varnam-util.h" +#include "varnam-types.h" +#include "foreign/snprintf.h" + +char *substr(char *dst, unsigned int start, unsigned int length, const char *src) +{ + sprintf(dst, "%.*s", length, src + start); + return dst; +} + +/* return true if string1 starts with string2 */ +int startswith(const char *string1, const char *string2) +{ + for(; ; string1++, string2++) { + if(!*string2) { + break; + } + else if(*string1 != *string2) { + return 0; + } + } + return 1; +} + +void *xmalloc(size_t size) +{ + void *ret = malloc(size); + return ret; +} + +void xfree (void *ptr) +{ + if(ptr) + free(ptr); +} diff --git a/util.h b/varnam-util.h similarity index 73% rename from util.h rename to varnam-util.h index 49acc1c..c525f8e 100644 --- a/util.h +++ b/varnam-util.h @@ -20,35 +20,11 @@ #ifndef UTIL_H_INCLUDED_085039 #define UTIL_H_INCLUDED_085039 -#include #include "foreign/snprintf.h" -#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) - -void varnam_info(const char *format, ...); -void varnam_error(const char *format, ...); - -struct path_info { - char *directory; - char *filename; - char *extension; -}; - char *substr(char *dst, unsigned int start, unsigned int length, const char *src); int startswith(const char *string1, const char *string2); -/* Allocate memory block that can hold path_info followed by actual path. - * allocating 3 locations extra to protect shifting of bytes for preserving - * '/' in the directory path and '.' in the extension. - * - * Returns a path_info structure. -*/ -struct path_info* splitpath(const char *full_path); - -/* - * methods to operate on dynamically growing string buffers. implementation in strbuf.c - */ - struct strbuf { char *buffer; /* null terminated buffer */ size_t length; /* length of the string excluding null terminator */ diff --git a/varnam.c b/varnam.c index 49c8385..80f15bb 100644 --- a/varnam.c +++ b/varnam.c @@ -17,16 +17,17 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "varnam.h" -#include "util.h" -#include "varnam-result-codes.h" #include +#include "varnam-types.h" +#include "varnam-util.h" +#include "varnam-result-codes.h" + int varnam_init(const char *symbols_file, size_t file_length, varnam **handle, char **msg) { int rc; varnam *c; - struct varnam_internal *vp; + struct varnam_internal *vi; if(symbols_file == NULL || file_length <= 0) return VARNAM_MISUSE; @@ -35,16 +36,20 @@ int varnam_init(const char *symbols_file, size_t file_length, varnam **handle, c if(!c) return VARNAM_MEMORY_ERROR; - vp = (struct varnam_internal *) xmalloc(sizeof (struct varnam_internal *)); - if(!vp) + vi = (struct varnam_internal *) xmalloc(sizeof (struct varnam_internal)); + if(!vi) + return VARNAM_MEMORY_ERROR; + + vi->message = (char *) xmalloc(sizeof (char) * VARNAM_LIB_TEMP_BUFFER_SIZE); + if(!vi->message) return VARNAM_MEMORY_ERROR; - c->internal = vp; + c->internal = vi; - rc = sqlite3_open(symbols_file, &vp->db); + rc = sqlite3_open(symbols_file, &vi->db); if( rc ) { - varnam_error("Can't open %s: %s\n", symbols_file, sqlite3_errmsg(vp->db)); - sqlite3_close(vp->db); + asprintf(msg, "Can't open %s: %s\n", symbols_file, sqlite3_errmsg(vi->db)); + sqlite3_close(vi->db); return VARNAM_ERROR; } diff --git a/varnam.h b/varnam.h index 2df2af8..9157d79 100644 --- a/varnam.h +++ b/varnam.h @@ -20,23 +20,13 @@ #ifndef VARNAM_H_INCLUDED_091620 #define VARNAM_H_INCLUDED_091620 -#include "foreign/sqlite3.h" -#include "util.h" #include -struct varnam_internal { - sqlite3 *db; -}; - -typedef struct varnam { - char *symbols_file; - struct varnam_internal *internal; -} varnam; - -int varnam_init(const char *symbols_file, size_t file_length, varnam **handle, char **msg); +#include "util.h" +#include "varnam-types.h" -int varnam_compile(varnam *handle, const char *scheme_file, const char *output_directory); +extern int varnam_init(const char *symbols_file, size_t file_length, varnam **handle, char **msg); -int varnam_transliterate(varnam *handle, const char *input, struct strbuf *output); +extern int varnam_transliterate(varnam *handle, const char *input, struct strbuf *output); #endif diff --git a/vstgen.c b/vstgen.c deleted file mode 100644 index 8b437a8..0000000 --- a/vstgen.c +++ /dev/null @@ -1,138 +0,0 @@ -/* vstgen.c - Implementation of Varnam Symbol Table generator - * - * Copyright (C) 2010 Navaneeth.K.N - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - - * This library 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 - * Lesser General Public License for more details. - - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "trie.h" -#include "util.h" -#include "parser.h" -#include "varnam-result-codes.h" -#include "foreign/sqlite3.h" - -static const char *token_type_tostring(enum token_type type) -{ - switch(type) - { - case PARSER_TOKEN_VOWEL: - return "vo"; - case PARSER_TOKEN_CONSONANT: - return "co"; - case PARSER_TOKEN_CONSONANT_CLUSTER: - return "cc"; - case PARSER_TOKEN_NUMBER: - return "nu"; - case PARSER_TOKEN_SYMBOL: - return "sy"; - case PARSER_TOKEN_OTHER: - return "ot"; - } - return ""; -} - -#define VSTGEN_SYMBOLS_STORE "symbols" - -static unsigned int totalitems; -static unsigned int current; - -static int callback(struct trie* t, unsigned int depth, void *userdata) -{ - sqlite3 *db; const struct token *tok; - char *zErrMsg = NULL; - int rc; - char sql[500]; - - if(t->root) return VARNAM_SUCCESS; - - assert(userdata); - assert(t->value); - - db = (sqlite3 *) userdata; - tok = (const struct token *) t->value; - - snprintf(sql, 500, "insert into %s values ('%s', '%s', '%s', '%s', %d);", VSTGEN_SYMBOLS_STORE, token_type_tostring(tok->type), - tok->pattern, tok->value1, tok->value2, t->child == NULL ? 0 : 1); - - rc = sqlite3_exec(db, sql, NULL, 0, &zErrMsg); - if( rc != SQLITE_OK ) { - varnam_error("Error processing %s : %s", t->label, zErrMsg); - sqlite3_free(zErrMsg); - return VARNAM_ERROR; - } - - varnam_info(":: (%d/%d) Processing : %s", ++current, totalitems, t->label); - return VARNAM_SUCCESS; -} - -extern int varnam_generate_symbols(const char *output_file_path, struct trie *result, char **error_message) -{ - sqlite3 *db; - char *zErrMsg = 0; - int rc; - char sql[200]; - - assert(output_file_path); - assert(result); - - rc = sqlite3_open(output_file_path, &db); - if( rc ) { - varnam_error("Can't open %s: %s\n", output_file_path, sqlite3_errmsg(db)); - sqlite3_close(db); - return VARNAM_ERROR; - } - - snprintf(sql, 200, "drop table if exists %s;", VSTGEN_SYMBOLS_STORE); - rc = sqlite3_exec(db, sql, NULL, 0, &zErrMsg); - if( rc != SQLITE_OK ){ - varnam_error("Failed to initialize output file : %s", zErrMsg); - sqlite3_free(zErrMsg); - return VARNAM_ERROR; - } - - snprintf(sql, 200, "create table %s (type TEXT, pattern TEXT, value1 TEXT, value2 TEXT, children INTEGER);", VSTGEN_SYMBOLS_STORE); - rc = sqlite3_exec(db, sql, NULL, 0, &zErrMsg); - if( rc != SQLITE_OK ){ - varnam_error("Failed to initialize output file : %s", zErrMsg); - sqlite3_free(zErrMsg); - return VARNAM_ERROR; - } - - snprintf(sql, 200, "BEGIN;", VSTGEN_SYMBOLS_STORE); - rc = sqlite3_exec(db, sql, NULL, 0, &zErrMsg); - if( rc != SQLITE_OK ){ - varnam_error("Failed to start a transaction : %s", zErrMsg); - sqlite3_free(zErrMsg); - return VARNAM_ERROR; - } - - varnam_info(":: Generating symbols"); - - totalitems = trie_children_count( result ); - current = 0; - trie_iterate(result, callback, db); - - snprintf(sql, 200, "COMMIT;", VSTGEN_SYMBOLS_STORE); - rc = sqlite3_exec(db, sql, NULL, 0, &zErrMsg); - if( rc != SQLITE_OK ){ - varnam_error("Failed to commit transaction : %s", zErrMsg); - sqlite3_free(zErrMsg); - return VARNAM_ERROR; - } - - varnam_info(":: Symbols generated"); - - sqlite3_close( db ); - return VARNAM_SUCCESS; -}