📄 jsgfgrammar.java
字号:
/* * Copyright 1999-2002 Carnegie Mellon University. * Portions Copyright 2002 Sun Microsystems, Inc. * Portions Copyright 2002 Mitsubishi Electric Research Laboratories. * All Rights Reserved. Use is subject to license terms. * * See the file "license.terms" for information on usage and * redistribution of this file, and for a DISCLAIMER OF ALL * WARRANTIES. * */package edu.cmu.sphinx.jsapi;import java.io.IOException;import java.net.MalformedURLException;import java.net.URL;import java.util.HashMap;import java.util.Map;import java.util.List;import java.util.LinkedList;import javax.speech.EngineException;import javax.speech.recognition.GrammarException;import javax.speech.recognition.GrammarSyntaxDetail;import javax.speech.recognition.Recognizer;import javax.speech.recognition.Rule;import javax.speech.recognition.RuleAlternatives;import javax.speech.recognition.RuleCount;import javax.speech.recognition.RuleGrammar;import javax.speech.recognition.RuleName;import javax.speech.recognition.RuleParse;import javax.speech.recognition.RuleSequence;import javax.speech.recognition.RuleTag;import javax.speech.recognition.RuleToken;import com.sun.speech.engine.recognition.BaseRecognizer;import edu.cmu.sphinx.linguist.language.grammar.Grammar;import edu.cmu.sphinx.linguist.language.grammar.GrammarNode;import edu.cmu.sphinx.util.LogMath;import edu.cmu.sphinx.util.props.PropertyException;import edu.cmu.sphinx.util.props.PropertySheet;import edu.cmu.sphinx.util.props.PropertyType;import edu.cmu.sphinx.util.props.Registry;/** * Defines a BNF-style grammar based on JSGF grammar rules in a file. * * <p> * 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 <a * href="http://java.sun.com/products/java-media/speech/">Java Speech API * (JSAPI) </a>. * * <p> * 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 * <p><a * href="http://java.sun.com/products/java-media/speech/forDevelopers/JSGF/">http://java.sun.com/products/java-media/speech/forDevelopers/JSGF/ * </a>. * * <p> * <b>Example 1: "Hello World" in JSGF </b> * * <p> * The example below shows how a JSGF grammar that generates the sentences * "Hello World": * * <p> * <table width="100%" cellpadding="10"> * <tr> * <td bgcolor="#DDDDDD"> * * <pre> * #JSGF V1.0 * * public <helloWorld> = Hello World; * </pre> * * </td> * </tr> * </table> * * <i>Figure 1: Hello grammar that generates the sentences "Hello World". </i> * * <p> * 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. * * <p> * The location of the grammar file(s) is(are) defined by the * {@link #PROP_BASE_GRAMMAR_URL baseGrammarURL}property. 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 {@link #PROP_GRAMMAR_NAME grammarName}. In this example, the * grammar name is "helloWorld". * * <p> * <b>Example 2: Command Grammar in JSGF </b> * * <p> * 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 <a * href="http://java.sun.com/products/java-media/speech/forDevelopers/JSGF/">JSGF * specification </a>. It is considerably more complex than the previous * example. It defines the public grammar called "basicCmd". * * <p> * <table width="100%" cellpadding="10"> * <tr> * <td bgcolor="#DDDDDD"> * * <pre> * #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 ]; * </pre> * * </td> * </tr> * </table> * * <i>Figure 2: Command grammar that generates simple control commands. </i> * * <p> * The features of JSGF that are shown in this example includes: * <ul> * <li>using other grammar rules within a grammar rule. * <li>the OR "|" operator. * <li>the grouping "(...)" operator. * <li>the optional grouping "[...]" operator. * <li>the zero-or-many "*" (called Kleene star) operator. * <li>a probability (e.g., "open" is more likely than the others). * </ul> * * <p> * <h3>From JSGF to Grammar Graph</h3> * * 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 <code>"<sil>"</code> means "silence". * * <p> * <img src="doc-files/helloWorld.jpg"> <br> * <i>Figure 3: Grammar graph created from the Hello World grammar. </i> * * <p> * <img src="doc-files/commandGrammar.jpg"> <br> * <i>Figure 4: Grammar graph created from the Command grammar. </i> * * <p> * <h3>Limitations</h3> * * There is a known limitation with the current JSGF support. * Grammars that contain non-speech loops * currently cause the recognizer to hang. * <p> * For example, in the following grammar * * <pre> * #JSGF V1.0 * grammar jsgf.nastygram; * public <nasty> = I saw a ((cat* | dog* | mouse*)+)+; * </pre> * * 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. * * <h3>Dynamic grammar behavior</h3> * It is possible to modify the grammar of a running application. Some * rules and notes: * <ul> * <li> Unlike a JSAPI recognizer, the JSGF Grammar only maintains one * Rule Grammar. This restriction may be relaxed in the future. * <li> The grammar should not be modified while a recognition is * in process * <li> The call to JSGFGrammar.loadJSGF will load in a * completely new grammar, tossing any old grammars or changes. * No call to commitChanges is necessary (although such a call * would be harmless in this situation). * <li> RuleGrammars can be modified via calls to * RuleGrammar.setEnabled and RuleGrammar.setRule). In order for * these changes to take place, JSGFGrammar.commitChanges must be * called after all grammar changes have been made. * </ul> * <p> * <h3>Implementation Notes</h3> * <ol> * <li>All internal probabilities are maintained in LogMath log base. * </ol> */public class JSGFGrammar extends Grammar { /** * Sphinx property that defines the location of the JSGF grammar file. */ public final static String PROP_BASE_GRAMMAR_URL = "grammarLocation"; /** * Sphinx property that defines the location of the JSGF grammar file. */ public final static String PROP_GRAMMAR_NAME = "grammarName"; /** * Default value for PROP_GRAMMAR_NAME */ public final static String PROP_GRAMMAR_NAME_DEFAULT = "default.gram"; /** * Sphinx property that defines the logMath component. */ public final static String PROP_LOG_MATH = "logMath"; // --------------------- // Configurable data // --------------------- private RuleGrammar ruleGrammar; private RuleStack ruleStack; private Recognizer recognizer; private String grammarName; private URL baseURL = null; private LogMath logMath; private boolean loadGrammar = true; private GrammarNode firstNode = null; /* * (non-Javadoc) * * @see edu.cmu.sphinx.util.props.Configurable#register(java.lang.String, * edu.cmu.sphinx.util.props.Registry) */ public void register(String name, Registry registry) throws PropertyException { super.register(name, registry); registry.register(PROP_BASE_GRAMMAR_URL, PropertyType.RESOURCE); registry.register(PROP_GRAMMAR_NAME, PropertyType.STRING); registry.register(PROP_LOG_MATH, PropertyType.COMPONENT); } /* * (non-Javadoc) * * @see edu.cmu.sphinx.util.props.Configurable#newProperties(edu.cmu.sphinx.util.props.PropertySheet) */ public void newProperties(PropertySheet ps) throws PropertyException { super.newProperties(ps); baseURL = ps.getResource(PROP_BASE_GRAMMAR_URL); logMath = (LogMath) ps.getComponent(PROP_LOG_MATH, LogMath.class); grammarName = ps .getString(PROP_GRAMMAR_NAME, PROP_GRAMMAR_NAME_DEFAULT); loadGrammar = true; } /** * Returns the RuleGrammar of this JSGFGrammar. * * @return the RuleGrammar */ public RuleGrammar getRuleGrammar() { return ruleGrammar; } /** * Sets the URL context of the JSGF grammars. * * @param url the URL context of the grammars */ public void setBaseURL(URL url) { baseURL = url; } /** * The JSGF grammar specified by grammarName will be loaded from * the base url (tossing out any previously loaded grammars) * * @param grammarName the name of the grammar * @throws IOException if an error occurs while loading or * compiling the grammar */ public void loadJSGF(String grammarName) throws IOException { this.grammarName = grammarName; loadGrammar = true; commitChanges(); } /** * Creates the grammar. * * @return the initial node of the Grammar */ protected GrammarNode createGrammar() throws IOException { commitChanges(); return firstNode; } /** * Returns the initial node for the grammar * * @return the initial grammar node */ public GrammarNode getInitialNode() { return firstNode; } /** * Parses the given Rule into a network of GrammarNodes. * * @param rule * the Rule to parse * * @return a grammar graph */ private GrammarGraph parseRule(Rule rule) throws GrammarException { GrammarGraph result; if (rule != null) { debugPrintln("parseRule: " + rule.toString()); } if (rule instanceof RuleAlternatives) { result = parseRuleAlternatives((RuleAlternatives) rule); } else if (rule instanceof RuleCount) { result = parseRuleCount((RuleCount) rule); } else if (rule instanceof RuleName) { result = parseRuleName((RuleName) rule); } else if (rule instanceof RuleSequence) { result = parseRuleSequence((RuleSequence) rule); } else if (rule instanceof RuleTag) { result = parseRuleTag((RuleTag) rule); } else if (rule instanceof RuleToken) { result = parseRuleToken((RuleToken) rule); } else if (rule instanceof RuleParse) { throw new IllegalArgumentException( "Unsupported Rule type: RuleParse: " + rule.toString()); } else { throw new IllegalArgumentException("Unsupported Rule type: " + rule.toString()); } return result; } /** * Parses the given RuleName into a network of GrammarNodes. * * @param initialRuleName * the RuleName rule to parse * * @return a grammar graph */ private GrammarGraph parseRuleName(RuleName initialRuleName) throws GrammarException { debugPrintln("parseRuleName: " + initialRuleName.toString()); GrammarGraph result = (GrammarGraph) ruleStack.contains(initialRuleName .getRuleName()); if (result != null) { // its a recursive call return result; } else { result = new GrammarGraph(); ruleStack.push(initialRuleName.getRuleName(), result); } RuleName ruleName = ruleGrammar.resolve(initialRuleName); if (ruleName == RuleName.NULL) { result.getStartNode().add(result.getEndNode(), 0.0f); } else if (ruleName == RuleName.VOID) { // no connection for void } else { if (ruleName == null) { throw new GrammarException("Can't resolve " + initialRuleName + " g " + initialRuleName.getFullGrammarName()); } RuleGrammar rg = recognizer.getRuleGrammar(ruleName .getFullGrammarName()); if (rg == null) { throw new GrammarException("Can't resolve grammar name " + ruleName.getFullGrammarName()); } Rule rule = rg.getRule(ruleName.getSimpleRuleName()); if (rule == null) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -