Scripts, tags, and semantic interpretation

Script language is used within a grammar to assign values to variable slots, as discussed in Sample grammar file revisited:

<ruleref uri="#No"/>
<tag> YesNo='no'</tag>

Here, the simple script within the tag assigns a value of 'no' to the YesNo slot when the No rule is triggered.

A well-designed grammar distinguishes between what the caller actually speaks (the raw text that was recognized) and the semantic meaning of that speech. For example, if there are five ways for the caller to say “direct my calls home”, the grammar must account for all of them. But, the grammar only needs to pass one meaning to the application (in a single format that the application will interpret correctly).

Your grammars can extract the caller’s meaning from different permutations of words, and pass this on in a single format, by setting keys and values in a script.

Using ECMAScript to assign key/value pairs

ECMAScript is a JavaScript standard scripting language, and it is accepted by Recognizer as a default. It’s compatible with all three of the supported tag-formats (semantics/1.0, semantics/1.0-literals, and swi-semantics/1.0).

You can use ECMAScript within a <tag> element in your grammar file to add key/value pair assignments to rules. For example:

<rule id="myrule"> 
    <item> first choice </item> 
    <tag> ECMAScript statement(s) </tag> 
</rule> 

You can include a <tag> element as a child of any of the following elements:

  • <grammar>
  • <item>
  • <one-of>
  • <rule>
  • <ruleref>

Keys and values can be used to define the interface between the grammars and the application. You can change the grammar without affecting the application so long as the keys remain unchanged, because the interface stays the same.

After a recognition, you can get an XML representation of the current results (as returned in the result format for your environment or voice platform).

Scripting considerations

A full discussion of ECMAScript is beyond the scope of this manual; if you are not already familiar with ECMAScript, we recommend that you refer to a book specifically dedicated to the topic for a detailed discussion of all it offers. However, in the context of Nuance, a few points are worth highlighting.

Commonly-used operators and functions

ECMAScript offers several particularly useful operations:

  • String concatenation: This can be performed using the + operator. Be careful that the operands are strings; if they are numbers, this indicates addition.
  • String fragment extraction: Performed using the substr function.
  • Character-to-integer conversion: Performed using the toString function.
  • Integer-to-character conversion: Performed using the parseInt function.
  • Regular expressions: These can help canonicalize the returned key. For example, you can remove all spaces with:
    KEY = KEYWITHSPACES.replace(/[] +/g), '');
  • The var declarator: This function keeps variables local to the script. Use this for variables in the root rule that you do not want to pass to the application:
    <ruleref uri="myrule" />
    <tag>
    var a = parseInt(myrule.SWI_literal,10);
     SWI_meaning = a + ' ' + 'done';
    </tag>

    In this case, the variable a is not accessible to any other rule.

  • Testing attribute instantiation: Often, the instantiation of a variable depends on a script being executed in an optional rule. If a script tries to manipulate an undefined variable during recognition, an error results. For instance:
    <rule id="string">
     <item repeat="0-1">
      <ruleref uri="#D1"/>
      <tag>VALUE = D1.V;</tag>
     </item>
     <ruleref uri="#D2" />
     <tag>VALUE += D2.V</tag>
    </rule>

    In this case, if rule D1 is included in the parse, VALUE is instantiated and the script attached to D2 will run properly. Otherwise, an error will be returned since the script is incrementing an undefined variable. The usual way to handle this is to rewrite as follows:

    <rule id="string">
     <item repeat="0-1">
      <ruleref uri="#D1" />
      <tag>VALUE = D1.V; </tag>
     </item>
     <ruleref uri="#D2" />
     <tag>VALUE = VALUE ? VALUE + D2.V : D2.V </tag>
    </rule>

    Alternatively, you can initialize VALUE to an empty string:

    <rule id="string">
     <tag>VALUE=''; </tag>
     <item repeat="0-1">
      <ruleref uri="#D1" />
      <tag>VALUE=D1.V; </tag>
     </item>
     <ruleref uri="#D2" />
     <tag>VALUE=VALUE+D2.V; </tag>
    </rule>

Using parseTool to verify ECMAScript

Now that the basic relations among rules, objects, and scripts have been established, let’s follow the operation of the grammar in response to the phrase, “direct my calls home”. First, we enter the following command at the prompt:

parseTool directcalls.grxml -t_s 

Note: We’re assuming that directcalls.grxml is in the same directory as parseTool.

The parseTool utility processes the file and displays the “next sentence” prompt:

PROG parseTool:
        arg <spec-filename> == directcalls.grxml
        arg <-test_sentences> == -t_s
next sentence: 

Enter direct my calls home at the prompt. The output is as follows:

Parsing 'direct my calls home' with uri 'directcalls.grxml'... 
Parse 0: {{{direct my calls DirectMyCalls} {{home Home} Where} CallCommand} ROOT} 
<?xml version='1.0'?> 
<result> 
<interpretation grammar="ParseToolGrammar" confidence="100"> 
 <input mode="speech"> 
  direct my calls home 
 </input> 
 <instance> 
  <ACTION confidence="100"> 
   direct calls 
  </ACTION> 
  <LOCATION confidence="100"> 
   home 
  </LOCATION> 
  <SWI_meaning> 
   direct calls home 
  </SWI_meaning> 
  <SWI_literal> 
   Direct my calls home 
  </SWI_literal> 
  <SWI_grammarName> 
   ParseToolGrammar 
  </SWI_grammarName> 
 </instance> 
</interpretation> 
</result> 
Parse successful, line 1 

We can see that “direct my calls home” produces the expected results:

  • The ACTION key is set to direct calls
  • The LOCATION key is set to home
  • The SWI_meaning key concatenates the other keys to get direct calls home