diff options
Diffstat (limited to 'media/sphinxbase/src/libsphinxbase/lm/jsgf.c')
-rw-r--r-- | media/sphinxbase/src/libsphinxbase/lm/jsgf.c | 943 |
1 files changed, 0 insertions, 943 deletions
diff --git a/media/sphinxbase/src/libsphinxbase/lm/jsgf.c b/media/sphinxbase/src/libsphinxbase/lm/jsgf.c deleted file mode 100644 index 90e161c621..0000000000 --- a/media/sphinxbase/src/libsphinxbase/lm/jsgf.c +++ /dev/null @@ -1,943 +0,0 @@ -/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ -/* ==================================================================== - * Copyright (c) 2007 Carnegie Mellon University. All rights - * reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * This work was supported in part by funding from the Defense Advanced - * Research Projects Agency and the National Science Foundation of the - * United States of America, and the CMU Sphinx Speech Consortium. - * - * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND - * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY - * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ==================================================================== - * - */ - -#include <string.h> -#include <assert.h> - -#include "sphinxbase/ckd_alloc.h" -#include "sphinxbase/strfuncs.h" -#include "sphinxbase/hash_table.h" -#include "sphinxbase/filename.h" -#include "sphinxbase/err.h" -#include "sphinxbase/jsgf.h" - -#include "jsgf_internal.h" -#include "jsgf_parser.h" -#include "jsgf_scanner.h" - -extern int yyparse (void* scanner, jsgf_t* jsgf); - -/** - * \file jsgf.c - * - * This file implements the data structures for parsing JSGF grammars - * into Sphinx finite-state grammars. - **/ - -static int expand_rule(jsgf_t *grammar, jsgf_rule_t *rule, int rule_entry, int rule_exit); - -jsgf_atom_t * -jsgf_atom_new(char *name, float weight) -{ - jsgf_atom_t *atom; - - atom = ckd_calloc(1, sizeof(*atom)); - atom->name = ckd_salloc(name); - atom->weight = weight; - return atom; -} - -int -jsgf_atom_free(jsgf_atom_t *atom) -{ - if (atom == NULL) - return 0; - ckd_free(atom->name); - ckd_free(atom); - return 0; -} - -jsgf_t * -jsgf_grammar_new(jsgf_t *parent) -{ - jsgf_t *grammar; - - grammar = ckd_calloc(1, sizeof(*grammar)); - /* If this is an imported/subgrammar, then we will share a global - * namespace with the parent grammar. */ - if (parent) { - grammar->rules = parent->rules; - grammar->imports = parent->imports; - grammar->searchpath = parent->searchpath; - grammar->parent = parent; - } - else { - grammar->rules = hash_table_new(64, 0); - grammar->imports = hash_table_new(16, 0); - } - - return grammar; -} - -void -jsgf_grammar_free(jsgf_t *jsgf) -{ - /* FIXME: Probably should just use refcounting instead. */ - if (jsgf->parent == NULL) { - hash_iter_t *itor; - gnode_t *gn; - - for (itor = hash_table_iter(jsgf->rules); itor; - itor = hash_table_iter_next(itor)) { - ckd_free((char *)itor->ent->key); - jsgf_rule_free((jsgf_rule_t *)itor->ent->val); - } - hash_table_free(jsgf->rules); - for (itor = hash_table_iter(jsgf->imports); itor; - itor = hash_table_iter_next(itor)) { - ckd_free((char *)itor->ent->key); - jsgf_grammar_free((jsgf_t *)itor->ent->val); - } - hash_table_free(jsgf->imports); - for (gn = jsgf->searchpath; gn; gn = gnode_next(gn)) - ckd_free(gnode_ptr(gn)); - glist_free(jsgf->searchpath); - for (gn = jsgf->links; gn; gn = gnode_next(gn)) - ckd_free(gnode_ptr(gn)); - glist_free(jsgf->links); - } - ckd_free(jsgf->name); - ckd_free(jsgf->version); - ckd_free(jsgf->charset); - ckd_free(jsgf->locale); - ckd_free(jsgf); -} - -static void -jsgf_rhs_free(jsgf_rhs_t *rhs) -{ - gnode_t *gn; - - if (rhs == NULL) - return; - - jsgf_rhs_free(rhs->alt); - for (gn = rhs->atoms; gn; gn = gnode_next(gn)) - jsgf_atom_free(gnode_ptr(gn)); - glist_free(rhs->atoms); - ckd_free(rhs); -} - -jsgf_atom_t * -jsgf_kleene_new(jsgf_t *jsgf, jsgf_atom_t *atom, int plus) -{ - jsgf_rule_t *rule; - jsgf_atom_t *rule_atom; - jsgf_rhs_t *rhs; - - /* Generate an "internal" rule of the form (<NULL> | <name> <g0006>) */ - /* Or if plus is true, (<name> | <name> <g0006>) */ - rhs = ckd_calloc(1, sizeof(*rhs)); - if (plus) - rhs->atoms = glist_add_ptr(NULL, jsgf_atom_new(atom->name, 1.0)); - else - rhs->atoms = glist_add_ptr(NULL, jsgf_atom_new("<NULL>", 1.0)); - rule = jsgf_define_rule(jsgf, NULL, rhs, 0); - rule_atom = jsgf_atom_new(rule->name, 1.0); - rhs = ckd_calloc(1, sizeof(*rhs)); - rhs->atoms = glist_add_ptr(NULL, rule_atom); - rhs->atoms = glist_add_ptr(rhs->atoms, atom); - rule->rhs->alt = rhs; - - return jsgf_atom_new(rule->name, 1.0); -} - -jsgf_rule_t * -jsgf_optional_new(jsgf_t *jsgf, jsgf_rhs_t *exp) -{ - jsgf_rhs_t *rhs = ckd_calloc(1, sizeof(*rhs)); - jsgf_atom_t *atom = jsgf_atom_new("<NULL>", 1.0); - rhs->alt = exp; - rhs->atoms = glist_add_ptr(NULL, atom); - return jsgf_define_rule(jsgf, NULL, rhs, 0); -} - -void -jsgf_add_link(jsgf_t *grammar, jsgf_atom_t *atom, int from, int to) -{ - jsgf_link_t *link; - - link = ckd_calloc(1, sizeof(*link)); - link->from = from; - link->to = to; - link->atom = atom; - grammar->links = glist_add_ptr(grammar->links, link); -} - -static char * -extract_grammar_name(char *rule_name) -{ - char* dot_pos; - char* grammar_name = ckd_salloc(rule_name + 1); - if ((dot_pos = strrchr(grammar_name + 1, '.')) == NULL) { - ckd_free(grammar_name); - return NULL; - } - *dot_pos='\0'; - return grammar_name; -} - -char const * -jsgf_grammar_name(jsgf_t *jsgf) -{ - return jsgf->name; -} - -static char * -jsgf_fullname(jsgf_t *jsgf, const char *name) -{ - char *fullname; - - /* Check if it is already qualified */ - if (strchr(name + 1, '.')) - return ckd_salloc(name); - - /* Skip leading < in name */ - fullname = ckd_malloc(strlen(jsgf->name) + strlen(name) + 4); - sprintf(fullname, "<%s.%s", jsgf->name, name + 1); - return fullname; -} - -static char * -jsgf_fullname_from_rule(jsgf_rule_t *rule, const char *name) -{ - char *fullname, *grammar_name; - - /* Check if it is already qualified */ - if (strchr(name + 1, '.')) - return ckd_salloc(name); - - /* Skip leading < in name */ - if ((grammar_name = extract_grammar_name(rule->name)) == NULL) - return ckd_salloc(name); - fullname = ckd_malloc(strlen(grammar_name) + strlen(name) + 4); - sprintf(fullname, "<%s.%s", grammar_name, name + 1); - ckd_free(grammar_name); - - return fullname; -} - -/* Extract as rulename everything after the secondlast dot, if existent. - * Because everything before the secondlast dot is the path-specification. */ -static char * -importname2rulename(char *importname) -{ - char *rulename = ckd_salloc(importname); - char *last_dotpos; - char *secondlast_dotpos; - - if ((last_dotpos = strrchr(rulename+1, '.')) != NULL) { - *last_dotpos='\0'; - if ((secondlast_dotpos = strrchr(rulename+1, '.')) != NULL) { - *last_dotpos='.'; - *secondlast_dotpos='<'; - secondlast_dotpos = ckd_salloc(secondlast_dotpos); - ckd_free(rulename); - return secondlast_dotpos; - } - else { - *last_dotpos='.'; - return rulename; - } - } - else { - return rulename; - } -} - -#define NO_NODE -1 -#define RECURSIVE_NODE -2 - -/** - * - * Expand a right-hand-side of a rule (i.e. a single alternate). - * - * @returns the FSG state at the end of this rule, NO_NODE if there's an - * error, and RECURSIVE_NODE if the right-hand-side ended in right-recursion (i.e. - * a link to an earlier FSG state). - */ -static int -expand_rhs(jsgf_t *grammar, jsgf_rule_t *rule, jsgf_rhs_t *rhs, - int rule_entry, int rule_exit) -{ - gnode_t *gn; - int lastnode; - - /* Last node expanded in this sequence. */ - lastnode = rule_entry; - - /* Iterate over atoms in rhs and generate links/nodes */ - for (gn = rhs->atoms; gn; gn = gnode_next(gn)) { - jsgf_atom_t *atom = gnode_ptr(gn); - - if (jsgf_atom_is_rule(atom)) { - jsgf_rule_t *subrule; - char *fullname; - gnode_t *subnode; - jsgf_rule_stack_t *rule_stack_entry = NULL; - - /* Special case for <NULL> and <VOID> pseudo-rules - If this is the only atom in the rhs, and it's the - first rhs in the rule, then emit a null transition, - creating an exit state if needed. */ - if (0 == strcmp(atom->name, "<NULL>")) { - if (gn == rhs->atoms && gnode_next(gn) == NULL) { - if (rule_exit == NO_NODE) { - jsgf_add_link(grammar, atom, - lastnode, grammar->nstate); - rule_exit = lastnode = grammar->nstate; - ++grammar->nstate; - } else { - jsgf_add_link(grammar, atom, - lastnode, rule_exit); - } - } - continue; - } - else if (0 == strcmp(atom->name, "<VOID>")) { - /* Make this entire RHS unspeakable */ - return NO_NODE; - } - - fullname = jsgf_fullname_from_rule(rule, atom->name); - if (hash_table_lookup(grammar->rules, fullname, (void**)&subrule) == -1) { - E_ERROR("Undefined rule in RHS: %s\n", fullname); - ckd_free(fullname); - return NO_NODE; - } - ckd_free(fullname); - - /* Look for this subrule in the stack of expanded rules */ - for (subnode = grammar->rulestack; subnode; subnode = gnode_next(subnode)) { - rule_stack_entry = (jsgf_rule_stack_t *)gnode_ptr(subnode); - if (rule_stack_entry->rule == subrule) - break; - } - - if (subnode != NULL) { - /* Allow right-recursion only. */ - if (gnode_next(gn) != NULL) { - E_ERROR("Only right-recursion is permitted (in %s.%s)\n", - grammar->name, rule->name); - return NO_NODE; - } - /* Add a link back to the beginning of this rule instance */ - E_INFO("Right recursion %s %d => %d\n", atom->name, lastnode, rule_stack_entry->entry); - jsgf_add_link(grammar, atom, lastnode, rule_stack_entry->entry); - - /* Let our caller know that this rhs didn't reach an - end state. */ - lastnode = RECURSIVE_NODE; - } - else { - /* If this is the last atom in this rhs, link its - expansion to the parent rule's exit state. - Otherwise, create a new exit state for it. */ - int subruleexit = NO_NODE; - if (gnode_next(gn) == NULL && rule_exit >= 0) - subruleexit = rule_exit; - - /* Expand the subrule */ - lastnode = expand_rule(grammar, subrule, lastnode, subruleexit); - - if (lastnode == NO_NODE) - return NO_NODE; - } - } - else { - /* An exit-state is created if this isn't the last atom - in the rhs, or if the containing rule doesn't have an - exit state yet. - Otherwise, the rhs's exit state becomes the containing - rule's exit state. */ - int exitstate; - if (gnode_next(gn) == NULL && rule_exit >= 0) { - exitstate = rule_exit; - } else { - exitstate = grammar->nstate; - ++grammar->nstate; - } - - /* Add a link for this token */ - jsgf_add_link(grammar, atom, - lastnode, exitstate); - lastnode = exitstate; - } - } - - return lastnode; -} - -static int -expand_rule(jsgf_t *grammar, jsgf_rule_t *rule, int rule_entry, - int rule_exit) -{ - jsgf_rule_stack_t* rule_stack_entry; - jsgf_rhs_t *rhs; - - /* Push this rule onto the stack */ - rule_stack_entry = (jsgf_rule_stack_t*)ckd_calloc(1, sizeof (jsgf_rule_stack_t)); - rule_stack_entry->rule = rule; - rule_stack_entry->entry = rule_entry; - grammar->rulestack = glist_add_ptr(grammar->rulestack, - rule_stack_entry); - - for (rhs = rule->rhs; rhs; rhs = rhs->alt) { - int lastnode; - - lastnode = expand_rhs(grammar, rule, rhs, - rule_entry, rule_exit); - - if (lastnode == NO_NODE) { - return NO_NODE; - } else if (lastnode == RECURSIVE_NODE) { - /* The rhs ended with right-recursion, i.e. a transition to - an earlier state. Nothing needs to happen at this level. */ - ; - } else if (rule_exit == NO_NODE) { - /* If this rule doesn't have an exit state yet, use the exit - state of its first right-hand-side. - All other right-hand-sides will use this exit state. */ - assert (lastnode >= 0); - rule_exit = lastnode; - } - } - - /* If no exit-state was created, use the entry-state. */ - if (rule_exit == NO_NODE) { - rule_exit = rule_entry; - } - - /* Pop this rule from the rule stack */ - ckd_free(gnode_ptr(grammar->rulestack)); - grammar->rulestack = gnode_free(grammar->rulestack, NULL); - - return rule_exit; -} - -jsgf_rule_iter_t * -jsgf_rule_iter(jsgf_t *grammar) -{ - return hash_table_iter(grammar->rules); -} - -jsgf_rule_t * -jsgf_get_rule(jsgf_t *grammar, char const *name) -{ - void *val; - char *fullname; - - fullname = string_join("<", name, ">", NULL); - if (hash_table_lookup(grammar->rules, fullname, &val) < 0) { - ckd_free(fullname); - return NULL; - } - ckd_free(fullname); - return (jsgf_rule_t *)val; -} - -jsgf_rule_t * -jsgf_get_public_rule(jsgf_t *grammar) -{ - jsgf_rule_iter_t *itor; - jsgf_rule_t *public_rule = NULL; - - for (itor = jsgf_rule_iter(grammar); itor; - itor = jsgf_rule_iter_next(itor)) { - jsgf_rule_t *rule = jsgf_rule_iter_rule(itor); - if (jsgf_rule_public(rule)) { - const char *rule_name = jsgf_rule_name(rule); - char *dot_pos; - if ((dot_pos = strrchr(rule_name + 1, '.')) == NULL) { - public_rule = rule; - jsgf_rule_iter_free(itor); - break; - } - if (0 == strncmp(rule_name + 1, jsgf_grammar_name(grammar), dot_pos - rule_name - 1)) { - public_rule = rule; - jsgf_rule_iter_free(itor); - break; - } - } - } - return public_rule; -} - -char const * -jsgf_rule_name(jsgf_rule_t *rule) -{ - return rule->name; -} - -int -jsgf_rule_public(jsgf_rule_t *rule) -{ - return rule->is_public; -} - -static fsg_model_t * -jsgf_build_fsg_internal(jsgf_t *grammar, jsgf_rule_t *rule, - logmath_t *lmath, float32 lw, int do_closure) -{ - fsg_model_t *fsg; - glist_t nulls; - gnode_t *gn; - int rule_entry, rule_exit; - - /* Clear previous links */ - for (gn = grammar->links; gn; gn = gnode_next(gn)) { - ckd_free(gnode_ptr(gn)); - } - glist_free(grammar->links); - grammar->links = NULL; - grammar->nstate = 0; - - /* Create the top-level entry state, and expand the - top-level rule. */ - rule_entry = grammar->nstate++; - rule_exit = expand_rule(grammar, rule, rule_entry, NO_NODE); - - /* If no exit-state was created, create one. */ - if (rule_exit == NO_NODE) { - rule_exit = grammar->nstate++; - jsgf_add_link(grammar, NULL, rule_entry, rule_exit); - } - - fsg = fsg_model_init(rule->name, lmath, lw, grammar->nstate); - fsg->start_state = rule_entry; - fsg->final_state = rule_exit; - grammar->links = glist_reverse(grammar->links); - for (gn = grammar->links; gn; gn = gnode_next(gn)) { - jsgf_link_t *link = gnode_ptr(gn); - - if (link->atom) { - if (jsgf_atom_is_rule(link->atom)) { - fsg_model_null_trans_add(fsg, link->from, link->to, - logmath_log(lmath, link->atom->weight)); - } - else { - int wid = fsg_model_word_add(fsg, link->atom->name); - fsg_model_trans_add(fsg, link->from, link->to, - logmath_log(lmath, link->atom->weight), wid); - } - } - else { - fsg_model_null_trans_add(fsg, link->from, link->to, 0); - } - } - if (do_closure) { - nulls = fsg_model_null_trans_closure(fsg, NULL); - glist_free(nulls); - } - - return fsg; -} - -fsg_model_t * -jsgf_build_fsg(jsgf_t *grammar, jsgf_rule_t *rule, - logmath_t *lmath, float32 lw) -{ - return jsgf_build_fsg_internal(grammar, rule, lmath, lw, TRUE); -} - -fsg_model_t * -jsgf_build_fsg_raw(jsgf_t *grammar, jsgf_rule_t *rule, - logmath_t *lmath, float32 lw) -{ - return jsgf_build_fsg_internal(grammar, rule, lmath, lw, FALSE); -} - -fsg_model_t * -jsgf_read_file(const char *file, logmath_t * lmath, float32 lw) -{ - fsg_model_t *fsg; - jsgf_rule_t *rule; - jsgf_t *jsgf; - jsgf_rule_iter_t *itor; - - if ((jsgf = jsgf_parse_file(file, NULL)) == NULL) { - E_ERROR("Error parsing file: %s\n", file); - return NULL; - } - - rule = NULL; - for (itor = jsgf_rule_iter(jsgf); itor; - itor = jsgf_rule_iter_next(itor)) { - rule = jsgf_rule_iter_rule(itor); - if (jsgf_rule_public(rule)) { - jsgf_rule_iter_free(itor); - break; - } - } - if (rule == NULL) { - E_ERROR("No public rules found in %s\n", file); - return NULL; - } - fsg = jsgf_build_fsg(jsgf, rule, lmath, lw); - jsgf_grammar_free(jsgf); - return fsg; -} - -fsg_model_t * -jsgf_read_string(const char *string, logmath_t * lmath, float32 lw) -{ - fsg_model_t *fsg; - jsgf_rule_t *rule; - jsgf_t *jsgf; - jsgf_rule_iter_t *itor; - - if ((jsgf = jsgf_parse_string(string, NULL)) == NULL) { - E_ERROR("Error parsing input string\n"); - return NULL; - } - - rule = NULL; - for (itor = jsgf_rule_iter(jsgf); itor; - itor = jsgf_rule_iter_next(itor)) { - rule = jsgf_rule_iter_rule(itor); - if (jsgf_rule_public(rule)) { - jsgf_rule_iter_free(itor); - break; - } - } - if (rule == NULL) { - jsgf_grammar_free(jsgf); - E_ERROR("No public rules found in input string\n"); - return NULL; - } - fsg = jsgf_build_fsg(jsgf, rule, lmath, lw); - jsgf_grammar_free(jsgf); - return fsg; -} - - -int -jsgf_write_fsg(jsgf_t *grammar, jsgf_rule_t *rule, FILE *outfh) -{ - fsg_model_t *fsg; - logmath_t *lmath = logmath_init(1.0001, 0, 0); - - if ((fsg = jsgf_build_fsg_raw(grammar, rule, lmath, 1.0)) == NULL) - goto error_out; - - fsg_model_write(fsg, outfh); - logmath_free(lmath); - return 0; - -error_out: - logmath_free(lmath); - return -1; -} - -jsgf_rule_t * -jsgf_define_rule(jsgf_t *jsgf, char *name, jsgf_rhs_t *rhs, int is_public) -{ - jsgf_rule_t *rule; - void *val; - - if (name == NULL) { - name = ckd_malloc(strlen(jsgf->name) + 16); - sprintf(name, "<%s.g%05d>", jsgf->name, hash_table_inuse(jsgf->rules)); - } - else { - char *newname; - - newname = jsgf_fullname(jsgf, name); - name = newname; - } - - rule = ckd_calloc(1, sizeof(*rule)); - rule->refcnt = 1; - rule->name = ckd_salloc(name); - rule->rhs = rhs; - rule->is_public = is_public; - - E_INFO("Defined rule: %s%s\n", - rule->is_public ? "PUBLIC " : "", - rule->name); - val = hash_table_enter(jsgf->rules, name, rule); - if (val != (void *)rule) { - E_WARN("Multiply defined symbol: %s\n", name); - } - return rule; -} - -jsgf_rule_t * -jsgf_rule_retain(jsgf_rule_t *rule) -{ - ++rule->refcnt; - return rule; -} - -int -jsgf_rule_free(jsgf_rule_t *rule) -{ - if (rule == NULL) - return 0; - if (--rule->refcnt > 0) - return rule->refcnt; - jsgf_rhs_free(rule->rhs); - ckd_free(rule->name); - ckd_free(rule); - return 0; -} - - -/* FIXME: This should go in libsphinxutil */ -static char * -path_list_search(glist_t paths, char *path) -{ - gnode_t *gn; - - for (gn = paths; gn; gn = gnode_next(gn)) { - char *fullpath; - FILE *tmp; - - fullpath = string_join(gnode_ptr(gn), "/", path, NULL); - tmp = fopen(fullpath, "r"); - if (tmp != NULL) { - fclose(tmp); - return fullpath; - } - else { - ckd_free(fullpath); - } - } - return NULL; -} - -jsgf_rule_t * -jsgf_import_rule(jsgf_t *jsgf, char *name) -{ - char *c, *path, *newpath; - size_t namelen, packlen; - void *val; - jsgf_t *imp; - int import_all; - - /* Trim the leading and trailing <> */ - namelen = strlen(name); - path = ckd_malloc(namelen - 2 + 6); /* room for a trailing .gram */ - strcpy(path, name + 1); - /* Split off the first part of the name */ - c = strrchr(path, '.'); - if (c == NULL) { - E_ERROR("Imported rule is not qualified: %s\n", name); - ckd_free(path); - return NULL; - } - packlen = c - path; - *c = '\0'; - - /* Look for import foo.* */ - import_all = (strlen(name) > 2 && 0 == strcmp(name + namelen - 3, ".*>")); - - /* Construct a filename. */ - for (c = path; *c; ++c) - if (*c == '.') *c = '/'; - strcat(path, ".gram"); - newpath = path_list_search(jsgf->searchpath, path); - if (newpath == NULL) { - E_ERROR("Failed to find grammar %s\n", path); - ckd_free(path); - return NULL; - } - ckd_free(path); - - path = newpath; - E_INFO("Importing %s from %s to %s\n", name, path, jsgf->name); - - /* FIXME: Also, we need to make sure that path is fully qualified - * here, by adding any prefixes from jsgf->name to it. */ - /* See if we have parsed it already */ - if (hash_table_lookup(jsgf->imports, path, &val) == 0) { - E_INFO("Already imported %s\n", path); - imp = val; - ckd_free(path); - } - else { - /* If not, parse it. */ - imp = jsgf_parse_file(path, jsgf); - val = hash_table_enter(jsgf->imports, path, imp); - if (val != (void *)imp) { - E_WARN("Multiply imported file: %s\n", path); - } - } - if (imp != NULL) { - hash_iter_t *itor; - /* Look for public rules matching rulename. */ - for (itor = hash_table_iter(imp->rules); itor; - itor = hash_table_iter_next(itor)) { - hash_entry_t *he = itor->ent; - jsgf_rule_t *rule = hash_entry_val(he); - int rule_matches; - char *rule_name = importname2rulename(name); - - if (import_all) { - /* Match package name (symbol table is shared) */ - rule_matches = !strncmp(rule_name, rule->name, packlen + 1); - } - else { - /* Exact match */ - rule_matches = !strcmp(rule_name, rule->name); - } - ckd_free(rule_name); - if (rule->is_public && rule_matches) { - void *val; - char *newname; - - /* Link this rule into the current namespace. */ - c = strrchr(rule->name, '.'); - assert(c != NULL); - newname = jsgf_fullname(jsgf, c); - - E_INFO("Imported %s\n", newname); - val = hash_table_enter(jsgf->rules, newname, - jsgf_rule_retain(rule)); - if (val != (void *)rule) { - E_WARN("Multiply defined symbol: %s\n", newname); - } - if (!import_all) { - hash_table_iter_free(itor); - return rule; - } - } - } - } - - return NULL; -} - -static void -jsgf_set_search_path(jsgf_t *jsgf, const char *filename) -{ - char *jsgf_path; - -#if !defined(_WIN32_WCE) - if ((jsgf_path = getenv("JSGF_PATH")) != NULL) { - char *word, *c; - /* FIXME: This should be a function in libsphinxbase. */ - word = jsgf_path = ckd_salloc(jsgf_path); - while ((c = strchr(word, ':'))) { - *c = '\0'; - jsgf->searchpath = glist_add_ptr(jsgf->searchpath, word); - word = c + 1; - } - jsgf->searchpath = glist_add_ptr(jsgf->searchpath, word); - jsgf->searchpath = glist_reverse(jsgf->searchpath); - return; - } -#endif - - if (!filename) { - jsgf->searchpath = glist_add_ptr(jsgf->searchpath, ckd_salloc(".")); - return; - } - - jsgf_path = ckd_salloc(filename); - path2dirname(filename, jsgf_path); - jsgf->searchpath = glist_add_ptr(jsgf->searchpath, jsgf_path); -} - -jsgf_t * -jsgf_parse_file(const char *filename, jsgf_t *parent) -{ - yyscan_t yyscanner; - jsgf_t *jsgf; - int yyrv; - FILE *in = NULL; - - yylex_init(&yyscanner); - if (filename == NULL) { - yyset_in(stdin, yyscanner); - } - else { - in = fopen(filename, "r"); - if (in == NULL) { - E_ERROR_SYSTEM("Failed to open %s for parsing", filename); - return NULL; - } - yyset_in(in, yyscanner); - } - - jsgf = jsgf_grammar_new(parent); - - if (!parent) - jsgf_set_search_path(jsgf, filename); - - yyrv = yyparse(yyscanner, jsgf); - if (yyrv != 0) { - E_ERROR("Failed to parse JSGF grammar from '%s'\n", filename ? filename : "(stdin)"); - jsgf_grammar_free(jsgf); - yylex_destroy(yyscanner); - return NULL; - } - if (in) - fclose(in); - yylex_destroy(yyscanner); - - return jsgf; -} - -jsgf_t * -jsgf_parse_string(const char *string, jsgf_t * parent) -{ - yyscan_t yyscanner; - jsgf_t *jsgf; - int yyrv; - YY_BUFFER_STATE buf; - - yylex_init(&yyscanner); - buf = yy_scan_string(string, yyscanner); - - jsgf = jsgf_grammar_new(parent); - if (!parent) - jsgf_set_search_path(jsgf, NULL); - - yyrv = yyparse(yyscanner, jsgf); - if (yyrv != 0) { - E_ERROR("Failed to parse JSGF grammar from input string\n"); - jsgf_grammar_free(jsgf); - yy_delete_buffer(buf, yyscanner); - yylex_destroy(yyscanner); - return NULL; - } - yy_delete_buffer(buf, yyscanner); - yylex_destroy(yyscanner); - - return jsgf; -} |