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; }
static int expand_rule(jsgf_t *grammar, jsgf_rule_t *rule) { jsgf_rhs_t *rhs; float norm; /* Push this rule onto the stack */ grammar->rulestack = glist_add_ptr(grammar->rulestack, rule); /* Normalize weights for all alternatives exiting rule->entry */ 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 { jsgf_add_link(grammar, NULL, lastnode, rule->exit); } } /* Pop this rule from the rule stack */ grammar->rulestack = gnode_free(grammar->rulestack, NULL); return rule->exit; }