| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <string.h> |
| | #include <assert.h> |
| |
|
| | #include <pocketsphinx.h> |
| |
|
| | #include "util/ckd_alloc.h" |
| | #include "util/strfuncs.h" |
| | #include "util/hash_table.h" |
| | #include "util/filename.h" |
| |
|
| | #include "lm/jsgf.h" |
| | #include "lm/jsgf_internal.h" |
| | #include "lm/jsgf_parser.h" |
| | #include "lm/jsgf_scanner.h" |
| |
|
| | extern int yyparse(void *scanner, jsgf_t * jsgf); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | 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 (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) |
| | { |
| | |
| | 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; |
| |
|
| | |
| | |
| | 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; |
| |
|
| | |
| | if (strchr(name + 1, '.')) |
| | return ckd_salloc(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; |
| |
|
| | |
| | if (strchr(name + 1, '.')) |
| | return ckd_salloc(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; |
| | } |
| |
|
| | |
| | |
| | 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 RECURSION -2 |
| | static int expand_rule(jsgf_t *grammar, jsgf_rule_t *rule); |
| | static int |
| | expand_rhs(jsgf_t *grammar, jsgf_rule_t *rule, jsgf_rhs_t *rhs) |
| | { |
| | gnode_t *gn; |
| | int lastnode; |
| |
|
| | |
| | lastnode = rule->entry; |
| |
|
| | |
| | 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; |
| | void *val; |
| |
|
| | |
| | if (0 == strcmp(atom->name, "<NULL>")) { |
| | |
| | jsgf_add_link(grammar, atom, |
| | lastnode, grammar->nstate); |
| | lastnode = grammar->nstate; |
| | ++grammar->nstate; |
| | continue; |
| | } |
| | else if (0 == strcmp(atom->name, "<VOID>")) { |
| | |
| | return -1; |
| | } |
| |
|
| | fullname = jsgf_fullname_from_rule(rule, atom->name); |
| | if (hash_table_lookup(grammar->rules, fullname, &val) == -1) { |
| | E_ERROR("Undefined rule in RHS: %s\n", fullname); |
| | ckd_free(fullname); |
| | return -1; |
| | } |
| | ckd_free(fullname); |
| |
|
| | |
| | subrule = val; |
| | |
| | for (subnode = grammar->rulestack; subnode; subnode = gnode_next(subnode)) |
| | if (gnode_ptr(subnode) == (void *)subrule) |
| | break; |
| |
|
| | if (subnode != NULL) { |
| | |
| | if (gnode_next(gn) != NULL) { |
| | E_ERROR |
| | ("Only right-recursion is permitted (in %s.%s)\n", |
| | grammar->name, rule->name); |
| | return -1; |
| | } |
| | |
| | E_INFO("Right recursion %s %d => %d\n", atom->name, lastnode, |
| | subrule->entry); |
| | jsgf_add_link(grammar, atom, lastnode, subrule->entry); |
| | return RECURSION; |
| | } |
| | else { |
| | |
| | if (expand_rule(grammar, subrule) == -1) |
| | return -1; |
| | |
| | jsgf_add_link(grammar, atom, |
| | lastnode, subrule->entry); |
| | lastnode = subrule->exit; |
| | } |
| | } |
| | else { |
| | |
| | jsgf_add_link(grammar, atom, lastnode, grammar->nstate); |
| | lastnode = grammar->nstate; |
| | ++grammar->nstate; |
| | } |
| | } |
| |
|
| | return lastnode; |
| | } |
| |
|
| | static int |
| | expand_rule(jsgf_t * grammar, jsgf_rule_t * rule) |
| | { |
| | jsgf_rhs_t *rhs; |
| | float norm; |
| |
|
| | |
| | grammar->rulestack = glist_add_ptr(grammar->rulestack, rule); |
| |
|
| | |
| | norm = 0; |
| | for (rhs = rule->rhs; rhs; rhs = rhs->alt) { |
| | if (rhs->atoms) { |
| | jsgf_atom_t *atom = gnode_ptr(rhs->atoms); |
| | norm += atom->weight; |
| | } |
| | } |
| |
|
| | rule->entry = grammar->nstate++; |
| | rule->exit = grammar->nstate++; |
| | if (norm == 0) norm = 1; |
| | for (rhs = rule->rhs; rhs; rhs = rhs->alt) { |
| | int lastnode; |
| |
|
| | if (rhs->atoms) { |
| | jsgf_atom_t *atom = gnode_ptr(rhs->atoms); |
| | atom->weight /= norm; |
| | } |
| | lastnode = expand_rhs(grammar, rule, rhs); |
| | if (lastnode == -1) { |
| | return -1; |
| | } |
| | else if (lastnode == RECURSION) { |
| | |
| | } |
| | else { |
| | jsgf_add_link(grammar, NULL, lastnode, rule->exit); |
| | } |
| | } |
| |
|
| | |
| | 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; |
| | |
| | if (grammar == NULL || rule == NULL) |
| | return NULL; |
| |
|
| | |
| | for (gn = grammar->links; gn; gn = gnode_next(gn)) { |
| | ckd_free(gnode_ptr(gn)); |
| | } |
| | glist_free(grammar->links); |
| | grammar->links = NULL; |
| | rule->entry = rule->exit = 0; |
| | grammar->nstate = 0; |
| | expand_rule(grammar, rule); |
| |
|
| | 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; |
| | } |
| |
|
| |
|
| | |
| | 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; |
| |
|
| | |
| | namelen = strlen(name); |
| | path = ckd_malloc(namelen - 2 + 6); |
| | strcpy(path, name + 1); |
| | |
| | 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'; |
| |
|
| | |
| | import_all = (strlen(name) > 2 |
| | && 0 == strcmp(name + namelen - 3, ".*>")); |
| |
|
| | |
| | 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); |
| |
|
| | |
| | |
| | |
| | if (hash_table_lookup(jsgf->imports, path, &val) == 0) { |
| | E_INFO("Already imported %s\n", path); |
| | imp = val; |
| | ckd_free(path); |
| | } |
| | else { |
| | |
| | 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; |
| | |
| | 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) { |
| | |
| | rule_matches = |
| | !strncmp(rule_name, rule->name, packlen + 1); |
| | } |
| | else { |
| | |
| | rule_matches = !strcmp(rule_name, rule->name); |
| | } |
| | ckd_free(rule_name); |
| | if (rule->is_public && rule_matches) { |
| | void *val; |
| | char *newname; |
| |
|
| | |
| | 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; |
| | 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; |
| | } |
| |
|
| | jsgf_rule_iter_t * |
| | jsgf_rule_iter_next(jsgf_rule_iter_t *itor) |
| | { |
| | return hash_table_iter_next(itor); |
| | } |
| |
|
| | jsgf_rule_t *jsgf_rule_iter_rule(jsgf_rule_iter_t *itor) |
| | { |
| | return ((jsgf_rule_t *)(itor)->ent->val); |
| | } |
| |
|
| | void |
| | jsgf_rule_iter_free(jsgf_rule_iter_t *itor) |
| | { |
| | return hash_table_iter_free(itor); |
| | } |
| |
|