47 #include "jsgf_parser.h"
48 #include "jsgf_scanner.h"
50 int yyparse(
void *scanner,
jsgf_t *jsgf);
60 jsgf_atom_new(
char *name,
float weight)
101 #if !defined(_WIN32_WCE)
102 if ((jsgf_path = getenv(
"JSGF_PATH")) != NULL) {
108 while ((c = strchr(word,
':'))) {
130 if (jsgf->
parent == NULL) {
146 for (gn = jsgf->
searchpath; gn; gn = gnode_next(gn))
149 for (gn = jsgf->
links; gn; gn = gnode_next(gn))
168 jsgf_rhs_free(rhs->
alt);
169 for (gn = rhs->
atoms; gn; gn = gnode_next(gn))
189 rule = jsgf_define_rule(jsgf, NULL, rhs, 0);
190 rule_atom = jsgf_atom_new(rule->
name, 1.0);
196 return jsgf_atom_new(rule->
name, 1.0);
206 return jsgf_define_rule(jsgf, NULL, rhs, 0);
222 extract_grammar_name(
char *rule_name)
226 if ((dot_pos = strrchr(grammar_name + 1,
'.')) == NULL) {
241 jsgf_fullname(
jsgf_t *jsgf,
const char *name)
246 if (strchr(name + 1,
'.'))
251 sprintf(fullname,
"<%s.%s", jsgf->
name, name + 1);
256 jsgf_fullname_from_rule(
jsgf_rule_t *rule,
const char *name)
258 char *fullname, *grammar_name;
261 if (strchr(name + 1,
'.'))
265 if ((grammar_name = extract_grammar_name(rule->
name)) == NULL)
267 fullname =
ckd_malloc(strlen(grammar_name) + strlen(name) + 4);
268 sprintf(fullname,
"<%s.%s", grammar_name, name + 1);
277 importname2rulename(
char *importname)
281 char *secondlast_dotpos;
283 if ((last_dotpos = strrchr(rulename+1,
'.')) != NULL) {
285 if ((secondlast_dotpos = strrchr(rulename+1,
'.')) != NULL) {
287 *secondlast_dotpos=
'<';
288 secondlast_dotpos =
ckd_salloc(secondlast_dotpos);
290 return secondlast_dotpos;
310 lastnode = rule->
entry;
313 for (gn = rhs->
atoms; gn; gn = gnode_next(gn)) {
315 if (jsgf_atom_is_rule(atom)) {
322 if (0 == strcmp(atom->
name,
"<NULL>")) {
324 jsgf_add_link(grammar, atom,
325 lastnode, grammar->
nstate);
326 lastnode = grammar->
nstate;
330 else if (0 == strcmp(atom->
name,
"<VOID>")) {
335 fullname = jsgf_fullname_from_rule(rule, atom->
name);
337 E_ERROR(
"Undefined rule in RHS: %s\n", fullname);
344 for (subnode = grammar->
rulestack; subnode; subnode = gnode_next(subnode))
345 if (
gnode_ptr(subnode) == (
void *)subrule)
347 if (subnode != NULL) {
349 if (gnode_next(gn) != NULL) {
350 E_ERROR(
"Only right-recursion is permitted (in %s.%s)\n",
355 E_INFO(
"Right recursion %s %d => %d\n", atom->
name, lastnode, subrule->
entry);
356 jsgf_add_link(grammar, atom, lastnode, subrule->
entry);
360 if (expand_rule(grammar, subrule) == -1)
363 jsgf_add_link(grammar, atom,
364 lastnode, subrule->
entry);
365 lastnode = subrule->
exit;
370 jsgf_add_link(grammar, atom,
371 lastnode, grammar->
nstate);
372 lastnode = grammar->
nstate;
391 for (rhs = rule->
rhs; rhs; rhs = rhs->
alt) {
400 if (norm == 0) norm = 1;
401 for (rhs = rule->
rhs; rhs; rhs = rhs->
alt) {
408 lastnode = expand_rhs(grammar, rule, rhs);
409 if (lastnode == -1) {
413 jsgf_add_link(grammar, NULL, lastnode, rule->
exit);
452 logmath_t *lmath, float32 lw,
int do_closure)
459 for (gn = grammar->
links; gn; gn = gnode_next(gn)) {
463 grammar->
links = NULL;
466 expand_rule(grammar, rule);
468 fsg = fsg_model_init(rule->
name, lmath, lw, grammar->
nstate);
472 for (gn = grammar->
links; gn; gn = gnode_next(gn)) {
476 if (jsgf_atom_is_rule(link->
atom)) {
477 fsg_model_null_trans_add(fsg, link->
from, link->
to,
481 int wid = fsg_model_word_add(fsg, link->
atom->
name);
482 fsg_model_trans_add(fsg, link->
from, link->
to,
487 fsg_model_null_trans_add(fsg, link->
from, link->
to, 0);
491 nulls = fsg_model_null_trans_closure(fsg, NULL);
502 return jsgf_build_fsg_internal(grammar, rule, lmath, lw, TRUE);
509 return jsgf_build_fsg_internal(grammar, rule, lmath, lw, FALSE);
521 E_ERROR(
"Error parsing file: %s\n", file);
535 E_ERROR(
"No public rules found in %s\n", file);
552 fsg_model_write(fsg, outfh);
568 sprintf(name,
"<%s.g%05d>", jsgf->
name, hash_table_inuse(jsgf->
rules));
573 newname = jsgf_fullname(jsgf, name);
583 E_INFO(
"Defined rule: %s%s\n",
584 rule->
public ?
"PUBLIC " :
"",
587 if (val != (
void *)rule) {
588 E_WARN(
"Multiply defined symbol: %s\n", name);
607 jsgf_rhs_free(rule->
rhs);
616 path_list_search(
glist_t paths,
char *path)
620 for (gn = paths; gn; gn = gnode_next(gn)) {
625 tmp = fopen(fullpath,
"r");
637 jsgf_import_rule(
jsgf_t *jsgf,
char *name)
639 char *c, *path, *newpath;
640 size_t namelen, packlen;
646 namelen = strlen(name);
648 strcpy(path, name + 1);
650 c = strrchr(path,
'.');
652 E_ERROR(
"Imported rule is not qualified: %s\n", name);
660 import_all = (strlen(name) > 2 && 0 == strcmp(name + namelen - 3,
".*>"));
663 for (c = path; *c; ++c)
664 if (*c ==
'.') *c =
'/';
665 strcat(path,
".gram");
666 newpath = path_list_search(jsgf->
searchpath, path);
672 E_INFO(
"Importing %s from %s to %s\n", name, path, jsgf->
name);
678 E_INFO(
"Already imported %s\n", path);
686 if (val != (
void *)imp) {
687 E_WARN(
"Multiply imported file: %s\n", path);
698 char *rule_name = importname2rulename(name);
702 rule_matches = !strncmp(rule_name, rule->
name, packlen + 1);
706 rule_matches = !strcmp(rule_name, rule->
name);
709 if (rule->
public && rule_matches) {
714 c = strrchr(rule->
name,
'.');
716 newname = jsgf_fullname(jsgf, c);
718 E_INFO(
"Imported %s\n", newname);
720 jsgf_rule_retain(rule));
721 if (val != (
void *)rule) {
722 E_WARN(
"Multiply defined symbol: %s\n", newname);
743 yylex_init(&yyscanner);
744 if (filename == NULL) {
745 yyset_in(stdin, yyscanner);
748 in = fopen(filename,
"r");
753 yyset_in(in, yyscanner);
757 yyrv = yyparse(yyscanner, jsgf);
759 E_ERROR(
"Failed to parse JSGF grammar from '%s'\n", filename ? filename :
"(stdin)");
761 yylex_destroy(yyscanner);
766 yylex_destroy(yyscanner);
jsgf_rule_t * jsgf_get_rule(jsgf_t *grammar, char const *name)
Get a rule by name from a grammar.
int32 start_state
Must be in the range [0..n_state-1].
jsgf_t * jsgf_parse_file(const char *filename, jsgf_t *parent)
Parse a JSGF grammar from a file.
Miscellaneous useful string functions.
Internal definitions for JSGF grammar compiler.
hash_entry_t * ent
Current entry in that table.
SPHINXBASE_EXPORT int32 hash_table_lookup(hash_table_t *h, const char *key, void **val)
Look up a key in a hash table and optionally return the associated value.
#define jsgf_rule_iter_next(itor)
Advance an iterator to the next rule in the grammar.
int32 final_state
Must be in the range [0..n_state-1].
#define ckd_calloc(n, sz)
Macros to simplify the use of above functions.
#define E_INFO
Print logging information to standard error stream.
Sphinx's memory allocation/deallocation routines.
glist_t links
Generated FSG links.
SPHINXBASE_EXPORT void hash_table_iter_free(hash_iter_t *itor)
Delete an unfinished iterator.
SPHINXBASE_EXPORT int logmath_log(logmath_t *lmath, float64 p)
Convert linear floating point number to integer log in base B.
A node in a generic list.
int jsgf_rule_public(jsgf_rule_t *rule)
Test if a rule is public or not.
SPHINXBASE_EXPORT hash_iter_t * hash_table_iter(hash_table_t *h)
Start iterating over key-value pairs in a hash table.
SPHINXBASE_EXPORT int logmath_free(logmath_t *lmath)
Free a log table.
#define ckd_salloc(ptr)
Macro for ckd_salloc
fsg_model_t * jsgf_read_file(const char *file, logmath_t *lmath, float32 lw)
Read JSGF from file and return FSG object from it.
int entry
Entry state for current instance of this rule.
#define hash_entry_val(e)
Access macros.
SPHINXBASE_EXPORT hash_table_t * hash_table_new(int32 size, int32 casearg)
Allocate a new hash table for a given expected size.
glist_t searchpath
List of directories to search for grammars.
char const * jsgf_grammar_name(jsgf_t *jsgf)
Get the grammar name from the file.
SPHINXBASE_EXPORT void ckd_free(void *ptr)
Test and free a 1-D array.
SPHINXBASE_EXPORT glist_t glist_add_ptr(glist_t g, void *ptr)
Create and prepend a new list node, with the given user-defined data, at the HEAD of the given generi...
#define E_WARN
Print warning information to standard error stream.
jsgf_rhs_t * alt
Linked list of alternates.
SPHINXBASE_EXPORT logmath_t * logmath_init(float64 base, int shift, int use_table)
Initialize a log math computation table.
glist_t rulestack
Stack of currently expanded rules.
jsgf_rule_iter_t * jsgf_rule_iter(jsgf_t *grammar)
Get an iterator over all rules in a grammar.
SPHINXBASE_EXPORT void hash_table_free(hash_table_t *h)
Free the specified hash table; the caller is responsible for freeing the key strings pointed to by th...
int exit
Exit state for current instance of this rule.
int public
Is this rule marked 'public'?
int nstate
Number of generated states.
A note by ARCHAN at 20050510: Technically what we use is so-called "hash table with buckets" which is...
char * charset
JSGF charset (default UTF-8)
SPHINXBASE_EXPORT glist_t glist_reverse(glist_t g)
Reverse the order of the given glist.
jsgf_rhs_t * rhs
Expansion.
void jsgf_grammar_free(jsgf_t *jsgf)
Free a JSGF grammar.
SPHINXBASE_EXPORT void glist_free(glist_t g)
Free the given generic list; user-defined data contained within is not automatically freed...
SPHINXBASE_EXPORT gnode_t * gnode_free(gnode_t *gn, gnode_t *pred)
Free the given node, gn, of a glist, pred being its predecessor in the list.
#define gnode_ptr(g)
Head of a list of gnodes.
char * name
Rule name (NULL for an alternation/grouping)
Implementation of logging routines.
jsgf_t * jsgf_grammar_new(jsgf_t *parent)
Create a new JSGF grammar.
int refcnt
Reference count.
SPHINXBASE_EXPORT void * hash_table_enter(hash_table_t *h, const char *key, void *val)
Try to add a new entry with given key and associated value to hash table h.
jsgf_atom_t * atom
Name, tags, weight.
#define jsgf_rule_iter_rule(itor)
Get the current rule in a rule iterator.
fsg_model_t * jsgf_build_fsg_raw(jsgf_t *grammar, jsgf_rule_t *rule, logmath_t *lmath, float32 lw)
Build a Sphinx FSG object from a JSGF rule.
char * version
JSGF version (from header)
SPHINXBASE_EXPORT hash_iter_t * hash_table_iter_next(hash_iter_t *itor)
Get the next key-value pair in iteration.
#define ckd_malloc(sz)
Macro for ckd_malloc
glist_t atoms
Sequence of items.
SPHINXBASE_EXPORT char * string_join(const char *base,...)
Concatenate a NULL-terminated argument list of strings, returning a newly allocated string...
fsg_model_t * jsgf_build_fsg(jsgf_t *grammar, jsgf_rule_t *rule, logmath_t *lmath, float32 lw)
Build a Sphinx FSG object from a JSGF rule.
jsgf_t * parent
Parent grammar (if this is an imported one)
char * name
Rule or token name.
#define E_ERROR
Print error message to standard error stream.
#define jsgf_rule_iter_free(itor)
Free a rule iterator (if the end hasn't been reached).
hash_table_t * rules
Defined or imported rules in this grammar.
Hash table implementation.
char * locale
JSGF locale (default C)
void * val
Key-length; the key string does not have to be a C-style NULL terminated string; it can have arbitrar...
Word level FSG definition.
int jsgf_write_fsg(jsgf_t *grammar, jsgf_rule_t *rule, FILE *outfh)
Convert a JSGF rule to Sphinx FSG text form.
#define E_ERROR_SYSTEM
Print error text; Call perror("");.
float weight
Weight (default 1)
hash_table_t * imports
Pointers to imported grammars.
char const * jsgf_rule_name(jsgf_rule_t *rule)
Get the rule name from a rule.