Grammar Language Tutorial

This document is a step-by-step tutorial showing how to develop dynamic speech recognition grammars with the Grammar Language.

The Grammar Language is a proper superset of W3C's SRGS ABNF format. The latter is a language that only addresses the needs of static grammars. For those not familiar with the syntax of ABNF grammars, here is a quick introduction:

The Grammar Language Reference gives a more formal definition of the language syntax.

Introduction

Dynamic grammars are grammars whose full contents is not known until application run time. They contain elements that are generated based on previous interactions with the caller, profile information, data coming from databases or web services, etc.

To help develop dynamic grammars, the Grammar Language extends the ABNF format with dynamic grammar directives. These directives can access variables and objects passed to the instantiation service via an instantiation context. This context maps variable names to values.

NuGram Server currently only supports instantiation contexts specified as JSON objects. For this reason, all the expressions below return JSON objects, arrays, strings, numbers, or boolean values.

Dynamic Elements

Most elements of the ABNF syntax have a dynamic counterpart. This section describes the most commonly used directives.

Dynamic headers

The value of all ABNF headers can be made dynamic by replacing their value by the @string directive. The directive accepts a single argument, an expression that must evaluate to a string. Here are a few examples:

  language @string callerLanguage;
  tag-format <semantics/1.0>;
  base @string meta.baseUrl;
  root $name;

Here, callerLanguage and meta are both variables that will need to be provided in the instantiation context at run time. If the instantiation context is the following JSON object:

  { "callerLanguage": "en-US", "meta":{"baseUrl":"http://localhost/somePath"} }

the generated grammar will look like:

  language en-US;
  tag-format <semantics/1.0>;
  base <http://localhost/somePath>;
  root $name;

Dynamic expansions

All ABNF expansion elements can be made dynamic using the Grammar Language. The two most basic such elements are the tokens and the semantic tags. Their dynamic counterpart are @word and @tag. Their syntax is:

  @word (expression)
  @tag (expression ... )

Each expression must evaluate to a string. For the @tag directive, all the values obtained by evaluating the enclosed expressions are concatenated to produce the tag text. For example:

  @tag ("out.id = '" entry.id "';")

will generate the tag

  {out.id = '1234';}

given the instantiation context {"entry":{"id":1234}}.

References to grammar rules can also be computed dynamically using the @ref directive:

  @ref (expression)

where expression must evaluate to a string. The string must start with # for a references to a local rule. Otherwise it will be treated as a reference to an external grammar rule.

References to externally-defined rules can be written as standard rule references with string interpolation where expressions are enclosed in curly brackets. For example, the following expansion

  $<../{language}/{Global.engineId}/someGrammar.abnf>

is equivalent to

  @ref ("../" language "/" Global.engineId "/someGrammar.abnf")

Two other dynamic directives are commonly used: @alt to introduce an alternative (choice) between an undetermined number of other expansions, and @seq to introduce a sequence of an undetermined number of expansions. Their syntax is given below:

  @alt expansions @end
  @seq expansions @end

Beware that each child expansion of a @alt directive will be treated as a separate choice. This means that the expansion

  @alt one two three four @end

is strictly equivalent to

  (one | two | three | four)

These two directives are especially useful in combination with the @for directive:

  @alt
    @for (name : names)
      @word (name)
    @end
  @end

Control Flow

The Grammar Language provides two control flow operators: @for to iterate over an array of objects, and @if to instantiate parts of the grammar selectively.

The syntax of the @for directive is :

  @for (variable : expression)
    ...
  @end

The expression must evaluate to an array. The body of the directive is executed once for each value in the array, and the variable is bound to that value in the body. Here is an example:

  @for (entry : entries)
      @call employeeName (entry)
      @tag ("out.id = '" entry.id "';")
  @end

The syntax of the @if directive is:

  @if (expression)
    ...
  @elseif (expression)
    ...
  @elseif (expression)
    ...
  ...
  @else
    ...
  @end

Each expression must evaluate to a boolean value. When it evaluates to a value different than the JSON false value, the expansions following the expression are executed. The @elseif clauses and the @else clause are all optional.

Here is an example:

  @if (entry.isDepartment)
      @call departmentName (entry)
  @else
      @call employeeName (entry)
  @end  

Expressions

The Grammar Language supports a limited expression language. This expression language is powerful enough to reference variables, access properties of JSON objects, compare values using a few operators (currently only != and ==), and combine expressions using logical operators (||, &&, and !).

Macros

When the same expansion is repeated over and over again in a grammar, it may be a good idea to create a macro for it. A macro is much like procedure in general-purpose programming languages. They are called and can accept parameters.

Macro definitions

The syntax for macro definitions is:

  @define name( parameters )
    expansion
  @end

where parameters is a comma-separated list of variable names. Here is an example:

  @define employeeName (employee) :
      [ @word (employee.firstname) ] 
      @word (employee.lastname)
  @end

This declaration defines a macro employeeName that accepts a single parameter.

Macros can be defined in any order. They can be called before they are defined (in document order). Moreover, the macro names are in a different namespace than the variables. It is thus non-ambiguous to have variable X and a macro X in the same grammar.

Macro calls

A macro call has the following syntax:

  @call (expression, expression, ...)

Here is an example of a macro call:

  @call streetAddress(address)