edu.cmu.sphinx.jsgf
Class JSGFGrammar

java.lang.Object
  extended by edu.cmu.sphinx.linguist.language.grammar.Grammar
      extended by edu.cmu.sphinx.jsgf.JSGFGrammar
All Implemented Interfaces:
GrammarInterface, Configurable

public class JSGFGrammar
extends Grammar

Defines a BNF-style grammar based on JSGF grammar rules in a file.

The Java Speech Grammar Format (JSGF) is a BNF-style, platform-independent, and vendor-independent textual representation of grammars for use in speech recognition. It is used by the Java Speech API (JSAPI) . Here we only intend to give a couple of examples of grammars written in JSGF, so that you can quickly learn to write your own grammars. For more examples and a complete specification of JSGF, go to http://java.sun.com/products/java-media/speech/forDevelopers/JSGF/ .

Example 1: "Hello World" in JSGF

The example below shows how a JSGF grammar that generates the sentences "Hello World":
  #JSGF V1.0
  public <helloWorld> = Hello World;
 
Figure 1: Hello grammar that generates the sentences "Hello World".

The above grammar is saved in a file called "hello.gram". It defines a public grammar rule called "helloWorld". In order for this grammar rule to be publicly accessible, we must be declared it "public". Non-public grammar rules are not visible outside of the grammar file. The location of the grammar file(s) is(are) defined by the baseGrammarURLproperty. Since all JSGF grammar files end with ".gram", it will automatically search all such files at the given URL for the grammar. The name of the grammar to search for is specified by grammarName. In this example, the grammar name is "helloWorld".

Example 2: Command Grammar in JSGF

This examples shows a grammar that generates basic control commands like "move a menu thanks please", "close file", "oh mighty computer please kindly delete menu thanks". It is the same as one of the command & control examples in the JSGF specification . It is considerably more complex than the previous example. It defines the public grammar called "basicCmd".
  #JSGF V1.0
  public <basicCmd> = <startPolite> <command> <endPolite>;
  <command> = <action> <object>;
  <action> = /10/ open |/2/ close |/1/ delete |/1/ move;
  <object> = [the | a] (window | file | menu);
  <startPolite> = (please | kindly | could you | oh mighty computer) *;
  <endPolite> = [ please | thanks | thank you ];
 
Figure 2: Command grammar that generates simple control commands.

The features of JSGF that are shown in this example includes:

From JSGF to Grammar Graph

After the JSGF grammar is read in, it is converted to a graph of words representing the grammar. Lets call this the grammar graph. It is from this grammar graph that the eventual search structure used for speech recognition is built. Below, we show the grammar graphs created from the above JSGF grammars. The nodes "<sil>" means "silence".


Figure 3: Grammar graph created from the Hello World grammar.


Figure 4: Grammar graph created from the Command grammar.

Limitations

There is a known limitation with the current JSGF support. Grammars that contain non-speech loops currently cause the recognizer to hang.

For example, in the following grammar

  #JSGF V1.0
  grammar jsgf.nastygram;
  public <nasty> = I saw a ((cat* | dog* | mouse*)+)+;
 
the production: ((cat* | dog* | mouse*)+)+ can result in a continuous loop, since (cat* | dog* | mouse*) can represent no speech (i.e. zero cats, dogs and mice), this is equivalent to ()+. To avoid this problem, the grammar writer should ensure that there are no rules that could possibly match no speech within a plus operator or kleene star operator.

Dynamic grammar behavior

It is possible to modify the grammar of a running application. Some rules and notes:

Implementation Notes

  1. All internal probabilities are maintained in LogMath log base.


Nested Class Summary
(package private)  class JSGFGrammar.GrammarGraph
          Represents a graph of grammar nodes.
(package private)  class JSGFGrammar.RuleStack
          Manages a stack of grammar graphs that can be accessed by grammar name
 
Field Summary
private  java.net.URL baseURL
           
private  GrammarNode firstNode
           
private  java.lang.String grammarName
           
private  boolean loadGrammar
           
private  java.util.logging.Logger logger
           
private  LogMath logMath
           
private  JSGFRuleGrammarManager manager
           
static java.lang.String PROP_BASE_GRAMMAR_URL
          The property that defines the location of the JSGF grammar file.
static java.lang.String PROP_GRAMMAR_NAME
          The property that defines the location of the JSGF grammar file.
static java.lang.String PROP_LOG_MATH
          The property that defines the logMath component.
private  JSGFRuleGrammar ruleGrammar
           
private  JSGFGrammar.RuleStack ruleStack
           
 
Fields inherited from class edu.cmu.sphinx.linguist.language.grammar.Grammar
dictionary, initialNode, PROP_ADD_FILLER_WORDS, PROP_ADD_SIL_WORDS, PROP_DICTIONARY, PROP_OPTIMIZE_GRAMMAR, PROP_SHOW_GRAMMAR
 
Constructor Summary
JSGFGrammar()
           
JSGFGrammar(java.lang.String location, LogMath logMath, java.lang.String grammarName, boolean showGrammar, boolean optimizeGrammar, boolean addSilenceWords, boolean addFillerWords, Dictionary dictionary)
           
JSGFGrammar(java.net.URL baseURL, LogMath logMath, java.lang.String grammarName, boolean showGrammar, boolean optimizeGrammar, boolean addSilenceWords, boolean addFillerWords, Dictionary dictionary)
           
 
Method Summary
 void commitChanges()
          Commit changes to all loaded grammars and all changes of grammar since the last commitChange
protected  GrammarNode createGrammar()
          Creates the grammar.
private  void dumpGrammar()
          Dumps interesting things about this grammar
private  java.lang.String getFullRuleName(java.lang.String ruleName)
          Gets the fully resolved rule name
 JSGFRuleGrammarManager getGrammarManager()
          Returns manager used to load grammars
 java.lang.String getGrammarName()
          Returns the name of this grammar.
 GrammarNode getInitialNode()
          Returns the initial node for the grammar
private  JSGFRuleGrammar getNamedRuleGrammar(java.lang.String grammarName)
           
private  java.util.List<java.lang.Float> getNormalizedWeights(java.util.List<java.lang.Float> weights)
          Normalize the weights.
 JSGFRuleGrammar getRuleGrammar()
          Returns the RuleGrammar of this JSGFGrammar.
private static java.net.URL grammarNameToURL(java.net.URL baseURL, java.lang.String grammarName)
           
private  void loadFullQualifiedRules(JSGFRuleGrammar grammar)
          Load grammars imported by a fully qualified Rule Token if they are not already loaded.
private  void loadImports(JSGFRuleGrammar grammar)
          Load grammars imported by the specified RuleGrammar if they are not already loaded.
 void loadJSGF(java.lang.String grammarName)
          The JSGF grammar specified by grammarName will be loaded from the base url (tossing out any previously loaded grammars)
private  JSGFRuleGrammar loadNamedGrammar(java.lang.String grammarName)
          Load named grammar from import rule
 void newProperties(PropertySheet ps)
          This method is called when this configurable component needs to be reconfigured.
private  JSGFGrammar.GrammarGraph processRule(JSGFRule rule)
          Parses the given Rule into a network of GrammarNodes.
private  JSGFGrammar.GrammarGraph processRuleAlternatives(JSGFRuleAlternatives ruleAlternatives)
          Parses the given RuleAlternatives into a network of GrammarNodes.
private  JSGFGrammar.GrammarGraph processRuleCount(JSGFRuleCount ruleCount)
          Parses the given RuleCount into a network of GrammarNodes.
private  JSGFGrammar.GrammarGraph processRuleName(JSGFRuleName initialRuleName)
          Parses the given RuleName into a network of GrammarNodes.
private  JSGFGrammar.GrammarGraph processRuleSequence(JSGFRuleSequence ruleSequence)
          Parses the given RuleSequence into a network of GrammarNodes.
private  JSGFGrammar.GrammarGraph processRuleTag(JSGFRuleTag ruleTag)
          Parses the given RuleTag into a network GrammarNodes.
private  JSGFGrammar.GrammarGraph processRuleToken(JSGFRuleToken ruleToken)
          Creates a GrammarNode with the word in the given RuleToken.
 void setBaseURL(java.net.URL url)
          Sets the URL context of the JSGF grammars.
 
Methods inherited from class edu.cmu.sphinx.linguist.language.grammar.Grammar
allocate, createGrammar, createGrammarNode, createGrammarNode, createGrammarNode, createGrammarNode, createGrammarNode, deallocate, dumpGrammar, dumpRandomSentences, dumpRandomSentences, dumpStatistics, getDictionary, getGrammarNodes, getNumNodes, getRandomSentence, newGrammar, postProcessGrammar
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

PROP_BASE_GRAMMAR_URL

@S4String
public static final java.lang.String PROP_BASE_GRAMMAR_URL
The property that defines the location of the JSGF grammar file.

See Also:
Constant Field Values

PROP_GRAMMAR_NAME

@S4String(defaultValue="default.gram")
public static final java.lang.String PROP_GRAMMAR_NAME
The property that defines the location of the JSGF grammar file.

See Also:
Constant Field Values

PROP_LOG_MATH

@S4Component(type=LogMath.class)
public static final java.lang.String PROP_LOG_MATH
The property that defines the logMath component.

See Also:
Constant Field Values

ruleGrammar

private JSGFRuleGrammar ruleGrammar

manager

private JSGFRuleGrammarManager manager

ruleStack

private JSGFGrammar.RuleStack ruleStack

grammarName

private java.lang.String grammarName

baseURL

private java.net.URL baseURL

logMath

private LogMath logMath

loadGrammar

private boolean loadGrammar

firstNode

private GrammarNode firstNode

logger

private java.util.logging.Logger logger
Constructor Detail

JSGFGrammar

public JSGFGrammar(java.lang.String location,
                   LogMath logMath,
                   java.lang.String grammarName,
                   boolean showGrammar,
                   boolean optimizeGrammar,
                   boolean addSilenceWords,
                   boolean addFillerWords,
                   Dictionary dictionary)
            throws java.net.MalformedURLException,
                   java.lang.ClassNotFoundException
Throws:
java.net.MalformedURLException
java.lang.ClassNotFoundException

JSGFGrammar

public JSGFGrammar(java.net.URL baseURL,
                   LogMath logMath,
                   java.lang.String grammarName,
                   boolean showGrammar,
                   boolean optimizeGrammar,
                   boolean addSilenceWords,
                   boolean addFillerWords,
                   Dictionary dictionary)

JSGFGrammar

public JSGFGrammar()
Method Detail

newProperties

public void newProperties(PropertySheet ps)
                   throws PropertyException
Description copied from interface: Configurable
This method is called when this configurable component needs to be reconfigured.

Specified by:
newProperties in interface Configurable
Overrides:
newProperties in class Grammar
Parameters:
ps - a property sheet holding the new data
Throws:
PropertyException - if there is a problem with the properties.

getRuleGrammar

public JSGFRuleGrammar getRuleGrammar()
Returns the RuleGrammar of this JSGFGrammar.

Returns:
the RuleGrammar

getGrammarManager

public JSGFRuleGrammarManager getGrammarManager()
Returns manager used to load grammars

Returns:
manager with loaded grammars

setBaseURL

public void setBaseURL(java.net.URL url)
Sets the URL context of the JSGF grammars.

Parameters:
url - the URL context of the grammars

getGrammarName

public java.lang.String getGrammarName()
Returns the name of this grammar.


loadJSGF

public void loadJSGF(java.lang.String grammarName)
              throws java.io.IOException,
                     JSGFGrammarParseException,
                     JSGFGrammarException
The JSGF grammar specified by grammarName will be loaded from the base url (tossing out any previously loaded grammars)

Parameters:
grammarName - the name of the grammar
Throws:
java.io.IOException - if an error occurs while loading or compiling the grammar
JSGFGrammarException
JSGFGrammarParseException

createGrammar

protected GrammarNode createGrammar()
                             throws java.io.IOException
Creates the grammar.

Specified by:
createGrammar in class Grammar
Returns:
the initial node of the Grammar
Throws:
java.io.IOException - if the grammar could not be loaded

getInitialNode

public GrammarNode getInitialNode()
Returns the initial node for the grammar

Specified by:
getInitialNode in interface GrammarInterface
Overrides:
getInitialNode in class Grammar
Returns:
the initial grammar node

processRule

private JSGFGrammar.GrammarGraph processRule(JSGFRule rule)
                                      throws JSGFGrammarException
Parses the given Rule into a network of GrammarNodes.

Parameters:
rule - the Rule to parse
Returns:
a grammar graph
Throws:
JSGFGrammarException

processRuleName

private JSGFGrammar.GrammarGraph processRuleName(JSGFRuleName initialRuleName)
                                          throws JSGFGrammarException
Parses the given RuleName into a network of GrammarNodes.

Parameters:
initialRuleName - the RuleName rule to parse
Returns:
a grammar graph
Throws:
JSGFGrammarException

processRuleCount

private JSGFGrammar.GrammarGraph processRuleCount(JSGFRuleCount ruleCount)
                                           throws JSGFGrammarException
Parses the given RuleCount into a network of GrammarNodes.

Parameters:
ruleCount - the RuleCount object to parse
Returns:
a grammar graph
Throws:
JSGFGrammarException

processRuleAlternatives

private JSGFGrammar.GrammarGraph processRuleAlternatives(JSGFRuleAlternatives ruleAlternatives)
                                                  throws JSGFGrammarException
Parses the given RuleAlternatives into a network of GrammarNodes.

Parameters:
ruleAlternatives - the RuleAlternatives to parse
Returns:
a grammar graph
Throws:
JSGFGrammarException

getNormalizedWeights

private java.util.List<java.lang.Float> getNormalizedWeights(java.util.List<java.lang.Float> weights)
Normalize the weights. The weights should always be zero or greater. We need to convert the weights to a log probability.

Parameters:
weights - the weights to normalize

processRuleSequence

private JSGFGrammar.GrammarGraph processRuleSequence(JSGFRuleSequence ruleSequence)
                                              throws JSGFGrammarException
Parses the given RuleSequence into a network of GrammarNodes.

Parameters:
ruleSequence - the RuleSequence to parse
Returns:
the first and last GrammarNodes of the network
Throws:
JSGFGrammarException

processRuleTag

private JSGFGrammar.GrammarGraph processRuleTag(JSGFRuleTag ruleTag)
                                         throws JSGFGrammarException
Parses the given RuleTag into a network GrammarNodes.

Parameters:
ruleTag - the RuleTag to parse
Returns:
the first and last GrammarNodes of the network
Throws:
JSGFGrammarException

processRuleToken

private JSGFGrammar.GrammarGraph processRuleToken(JSGFRuleToken ruleToken)
Creates a GrammarNode with the word in the given RuleToken.

Parameters:
ruleToken - the RuleToken that contains the word
Returns:
a GrammarNode with the word in the given RuleToken

grammarNameToURL

private static java.net.URL grammarNameToURL(java.net.URL baseURL,
                                             java.lang.String grammarName)
                                      throws java.net.MalformedURLException
Throws:
java.net.MalformedURLException

commitChanges

public void commitChanges()
                   throws java.io.IOException,
                          JSGFGrammarParseException,
                          JSGFGrammarException
Commit changes to all loaded grammars and all changes of grammar since the last commitChange

Throws:
JSGFGrammarParseException
JSGFGrammarException
java.io.IOException

loadImports

private void loadImports(JSGFRuleGrammar grammar)
                  throws java.io.IOException,
                         JSGFGrammarParseException
Load grammars imported by the specified RuleGrammar if they are not already loaded.

Throws:
JSGFGrammarParseException
java.io.IOException

getNamedRuleGrammar

private JSGFRuleGrammar getNamedRuleGrammar(java.lang.String grammarName)

loadNamedGrammar

private JSGFRuleGrammar loadNamedGrammar(java.lang.String grammarName)
                                  throws JSGFGrammarParseException,
                                         java.io.IOException
Load named grammar from import rule

Parameters:
grammarName -
Returns:
already loaded grammar
Throws:
JSGFGrammarParseException
java.io.IOException

loadFullQualifiedRules

private void loadFullQualifiedRules(JSGFRuleGrammar grammar)
                             throws java.io.IOException,
                                    JSGFGrammarParseException
Load grammars imported by a fully qualified Rule Token if they are not already loaded.

Parameters:
grammar -
Throws:
java.io.IOException
GrammarException
JSGFGrammarParseException

getFullRuleName

private java.lang.String getFullRuleName(java.lang.String ruleName)
                                  throws JSGFGrammarException
Gets the fully resolved rule name

Parameters:
ruleName - the partial name
Returns:
the fully resolved name
Throws:
JSGFGrammarException

dumpGrammar

private void dumpGrammar()
Dumps interesting things about this grammar