Appendix C -- The Form Interpretation Algorithm

Execution of the code in forms is handled by the form interpretation algorithm (FIA), which loops through the items in the form and processes (or reprocesses) them.

The FIA was introduced in Lesson 6 and is mentioned frequently in subsequent lessons. This appendix provides more detail about its behavior.

Overview

The FIA loops repeatedly through the constituents of a form until every one of the constituents has been processed (some of them more than once).

The constituents of a form can be:

  1. Form items

    1. Input items, such as <field> and <subdialog> elements

    2. Control items, such as <block> elements

  2. Things that are not form items

    1. Variable declarations (<var> elements)

    2. <script> elements

Note

"Form item" is a formal term used in VoiceXML documentation.

The difference between form items and non-form items is this:

  • The FIA loops through the form items repeatedly, "visiting" (that is, executing) each one that does not have a "guard condition" turned on.

  • Non-form items are processed once, during form initialization, but are not processed during the FIA loop.

Guard conditions

Every form item has a "guard condition," which is turned on or off. It is off by default.

Important

When a form item's guard condition is turned on, the FIA ignores the item whenever the FIA loops through the form.

There are two different ways to turn on a guard condition:

  1. The form items all have a "form item variable." If this variable has a value other than undefined, the form item's guard condition is turned on. This type of guard condition is common.

  2. All form items have an optional cond attribute. If a form item is given a cond attribute and the cond expression evaluates to false when the FIA examines the form item in the FIA loop (that is, at run time), then that form item has its guard condition turned on. This type of guard condition is uncommon.

The two types of guard conditions are combined in a logical OR: if a form item variable has a value OR if the form item has a cond attribute that evaluates to false, then the guard condition is turned on.

When the FIA enters a form to process it, most of the form items will have no cond attribute and their variables will be set to undefined. This means that their guard condition is turned off and the FIA will "visit" (that is, execute) them.

Form item variables

When the FIA first enters a form, it will make sure that all form items have a form item variable. If you have given a form item a name attribute in your code, the value of the name attribute will be the name of the form item variable. If you did not give the form item a name attribute, then, the FIA itself will create an internal name for the form item variable (and you won't know what it is).

Input items (such as <field> and <subdialog> elements) are usually given a name by the programmer, while control items like <block> elements are usually not given names.

How does a field's form item variable get a value other than undefined? There are two ways:

  1. When a field is filled, the FIA itself assigns the match value to the field's form item variable. Once this is done, the field's guard condition is on and the FIA will not revisit the field (unless its form item variable is cleared).

  2. You, the programmer, can give the variable a value with the expr attribute. For example, <field name="fieldx" expr="skip_for_now"/> defines a field that has a form item variable named fieldx with the value "skip_for_now".

    You would only do this when you want the FIA to skip the fieldx field for the time being.

Note

You, the programmer, can use the <clear/> element to change the value of a form item variable to undefined. For example, <clear namelist="fieldx"/> will reset the value of the fieldx variable above to undefined.

How does a block's form item variable get a value other than undefined? In the same way as a field's form item variable if you, the programmer, have given the <block> element a name attribute. This is normally not done, however, so there is really only one way:

  1. When the FIA visits a <block> element, the first thing that it does is to change the block's form item variable (its internal name is hidden from you) from undefined to true. Then the code in the <block> element is executed and the FIA leaves the block. The FIA will not return to this block because its guard condition is now turned on.

Flow of the FIA behavior

Step1: Initialization

  1. initializes variables and runs scripts (these are not form items)

  2. sets form item variables:

    • creates a variable name for any form items that don't have a name attribute

    • sets all form item variables to either undefined or the value of the expr attribute that is given by the code

  3. creates a prompt counter for each form input item and sets it to 1

Step 2: Loops through form items and visits the first one it finds with its guard condition turned off. Obeys any transfer of control instructions (e.g., <goto>, <submit>, <transfer>) when encountered—this may cause a transfer to a subsequent form item or may cause the application to leave the form.

Steps 3 to n: Goes back to the beginning of the form and loops through the form items again, visiting the first one it finds with its guard condition turned off. Obeys any transfer of control instructions when encountered.

Final Step (n+1): Exits the VoiceXML application when there are no longer any form items with their guard condition turned off and a transfer of control instruction has not been encountered.

Important

  1. When the FIA visits and successfully executes a form item (field, subdialog, or block) it turns on the item's guard condition. If it finishes execution of the form item without having encountered a transfer of control instruction, it continues with its "loop."

  2. When the FIA has finished with a form item, it does not proceed immediately to the next form item in document order. It goes back to the first form item and loops through all the form items in document order again, visiting any items that have their guard condition turned off and ignoring form items with their guard conditions turned on. Unless a guard condition has been turned off by a <clear namelist="..."/> statement, of course, the FIA will not find any earlier fields to revisit and execute.

As an example, consider a form that contains seven fields as form items. All of these form items have their guard conditions turned off. Form 6 has a <clear> statement in it. The others do not.

  1. The FIA begins by examining field number 1 and visiting the field if its guard condition is turned off.

  2. When the FIA reaches field number 6, it will have visited, executed, and turned on the guard conditions of fields 1 through 5.

  3. If the <filled> section in field number 6 has a <clear namelist="field3"/> statement in it, the guard condition in field 3 will be turned off.

  4. When the FIA is finished with field 6 (it will have turned on the guard condition of field 6), it will go back and look at fields 1 through 6 in order again.

  5. The FIA will find the guard condition of field 3 turned off so it will revisit that field.

  6. When finished with field 3, the FIA will turn on field 3's guard condition and then proceed to examine fields 1 through 6 again. It will not visit any of them, however, because their guard conditions are turned on.

  7. Then, and only then, will the FIA proceed to field 7.

A model directed form for analyzing how the FIA works

To demonstrate how the FIA works, we will use a sample directed form that includes:

  • Two <var> elements

  • Two <script> elements

  • Four <field> elements

  • Two <block> elements

  • One <subdialog> element

Here is an outline:

<form>
   <var name="var1" expr="101"/>
   <script>.......(first script)...............</script>
   <field name="field1">.......................</field>                <!-- form item number 1 -->
   <block>..........(first block)..............</block>                <!-- form item number 2 -->
   <field name="field2" expr="skip_for_now">...........</field>        <!-- form item number 3 -->
   <var name="var2" expr="'gypsy'"/>
   <script>.......(second script)..............</script>
   <field name="field3">.......................</field>                <!-- form item number 4 -->
   <block>........(second block)...............</block>                <!-- form item number 5 -->
   <field name="field4">                            <field>            <!-- form item number 6 -->
   <subdialog name="sub1" src="anotherForm">...</subdialog>            <!-- form item number 7 -->
</form>

Initialization of the directed form

The first thing the FIA does when it enters a form is initialize the form. The FIA will step through the form one element at a time in "document order", and do this:

  1. Declare the var1 variable and give it the value 101.

  2. Execute all the statements in the first <script> element.

  3. Create an input item variable named field1 for the first field and set its value to undefined. Also create the first field's prompt counter and set it to 1.

  4. Create a control item variable for the first block, give it an internal name, and set it to undefined.

  5. Create an input item variable named field2 for the second field and set its value to "skip_for_now". Also create the second field's prompt counter and set it to 1.

  6. Declare the var2 variable and give it the value "gypsy".

  7. Execute all the statements in the second <script> element.

  8. Create an input item variable named field3 for the third field and set its value to undefined. Also create the third field's prompt counter and set it to 1.

  9. Create a control item variable for the second block, give it an internal name, and set it to undefined.

  10. Create an input item variable named field4 for the fourth field and set its value to undefined. Also create the fourth field's prompt counter and set it to 1.

  11. Create an input item variable named field5 for the fifth field and set its value to undefined. Also create the fifth field's prompt counter and set it to 1.

  12. Create an input item variable named sub1 for the <subdialog> element and set its value to undefined. Also create the <subdialog> element's prompt counter and set it to 1.

Execution of the directed form

After initialization is completed, the FIA will not recreate variables or run scripts again because they are not form items.

The FIA will loop through the form items in sequence. This includes both input items (<field> and <subdialog> elements) and control items (<block> elements). The FIA will visit those form items that do not have a guard condition turned on.

On the first iteration of the FIA loop, field 2 has a guard condition turned on because its input item variable has a value ("skip_for_now"), so the FIA will ignore it. All the other fields, subdialogs, and blocks do not have guard conditions turned on (they have undefined field item variables and none of them have cond attributes that evaluate to false), so they will all be visited by the FIA.

Adding some more detail to the directed form

We add some pseudo content to three fields and the subdialog so we can analyze in more detail what happens when the FIA loops through the form items. Two lines of code that have to do with turning guard conditions on and off are shown in bold font.

<form>
   <var name="var1" expr="101"/>

   <script>.......(first script)...............</script>

   <field name="field1">                                       <!-- form item number 1 -->
      <prompt>.......</prompt>
      <grammar>.......</grammar>
      <catch  event="nomatch noinput">
          Sorry. Didn't get that. Please try again
         <reprompt/>
      </catch>
      <filled>.......</filled>
   </field>

   <block>..........(first block).........</block>            <!-- form item number 2 -->

   <field name="field2" expr="skip_for_now">                  <!-- form item number 3 -->
      <prompt>.......</prompt>
      <grammar>.......</grammar>
      <catch  event="nomatch noinput">
          Sorry. Didn't get that. Please try again
         <reprompt/>
      </catch>
      <filled>.......</filled>
   </field>

   <var name="var2" expr="'gypsy'"/>

   <script>.......(second script)..............</script>

   <field name="field3">                                      <!-- form item number 4 -->
    <prompt>.......</prompt>
    <grammar>.......</grammar>
    <catch  event="nomatch noinput">
      Sorry. Didn't get that. Please try again
    </catch>
    <filled>........</filled>
 </field>

   <block>........(second block)...............</block>       <!-- form item number 5 -->

   <field name="field4">                                      <!-- form item number 6 -->
      <prompt>.......</prompt>
      <grammar>.......</grammar>
      <catch  event="nomatch noinput">
          Sorry. Didn't get that. Please try again
         <reprompt/>
      </catch>
      <filled>
         <clear namelist="field2"/>
         ..........
      </filled>
   </field>

   <subdialog name="sub1" src="anotherForm">
      <param name="variable_to_send"  expr="whatever"/>       <!-- form item number 7 -->
      <filled>.............</filled>
   </subdialog>
</form>

Processing the form

In processing this form, the FIA does this, in sequence:

  1. The FIA visits field number 1. If a match is not made, the FIA reprompts and starts listening again. The FIA keeps reprompting and listening until there's a match or the caller hangs up.

    If a match is made, the FIA turns on the guard condition for field number 1 by setting the field1 variable to the match value and then executes the statements in the <filled> element.

    If there is a transfer of control statement in the <filled> element, the statement is executed and the FIA transfers control elsewhere

    If there is no transfer of control statement, the FIA exits field number 1 and resumes its "loop."

  2. The FIA starts again at the beginning and examines the guard condition of the first form item in the form, which is the same field number 1 that it just finished. As the guard condition is now turned on (field1 has a value), the FIA does not revisit field number 1.

  3. The FIA then examines the form item number 2, which is a block. Since the block's guard condition is turned off, the FIA visits it. First, the FIA turns on the <block> element's guard condition by setting its form item variable to true. Then it executes all the statements in the block.

    Since we did not assign a name attribute to the <block> element, the FIA gave it an internal name. We do not know what this name is, so we cannot clear it, now or later. Thus, while this block will be examined again by the FIA in its loop, it will never be visited and executed again.

  4. The FIA starts again at the beginning and examines all the form items until it finds one with its guard condition turned off. This will be not be form item number 3, which is field number 2. The form item variable for field 2 has a value ("skip_for_now") so the field's guard condition is turned on and the FIA skips the field.

  5. The FIA continues to examine the form items until it finds one with its guard condition turned off. This will be form item number 4, which is field number 3. Field 3 is handled the same way as field number 1 (see step 1), with one exception: the <catch event="nomatch noinput"/> element does not include a reprompt (or equivalent text). This means that the field will continue to listen if there is no match or no input, but, lacking a reprompt, the caller may not know that the application is waiting for input. Hence the caller (and the application) may just sit there until the caller gets fed up and hangs up.

  6. The FIA starts again at the beginning and examines all the form items until it finds one with its guard condition turned off. This will be form item number 5, which is a block. This block is handled the same way as the previous block (see step 3).

  7. The FIA starts again at the beginning and examines all the form items until it finds one with its guard condition turned off. This will be form item number 6, which is field number 4. Field 4 is handled the same way as field number 1 (see step 1.), with one exception: the <filled> element include a statement that clears the form item variable for field number 2: <clear namelist="field2"/>.

  8. The FIA starts again at the beginning (with the first form item) and examines all the form items until it finds one with its guard condition turned off. This will be form item number 3, which is field number 2 (remember, its guard condition was just cleared). Field 2 is handled the same way as field number 1 (see step 1)

    When a match is made, it is put in the field2 variable, and the FIA moves on.

  9. The FIA starts again at the beginning and examines all the form items until it finds one with its guard condition turned off. This will be form item number 7, which is the <subdialog> element named sub1.

    Note

    Since we never turned off the guard condition for field number 4, it is not revisited and the <clear namelist="field2"/> is not executed. Therefore, field number 2 is not revisited again either.

    The <subdialog> element is executed, calling the subdialog form. When the subdialog form returns a value to the form item variable of the <subdialog> element (sub1), the <subdialog> element's guard condition is turned on.

    The FIA executes the statements in the <filled> element of the <subdialog> element. If there is no transfer of control statement in the <filled> element, the FIA resumes its loop.

  10. The FIA starts again at the beginning and examines all the form items until it finds one with its guard condition turned off. Now, however, all of the form items have their guard conditions turned on. Since the FIA is still looping through the form items, it must not have encountered a transfer of control statement. So, lacking a form item to visit, the FIA exits the application.

Some comments

  1. A transfer of control statement at any point in the FIA loop can cause the FIA to leave the form without necessarily exiting the application.

  2. When a <field> input item is not filled (that is, there is no match or no input), the FIA will do the following:

    • Exit the application if there is no event handler for nomatch or noinput.

    • Follow the instructions in the event handler for nomatch or noinput, which could include a transfer of control with a <goto> element, an instruction to try to get input again, or an instruction to exit.

    • Keep trying repeatedly to get input if there are no instructions to the contrary in the event handler for nomatch or noinput. Under these circumstances, the only way the FIA will stop is if the caller hangs up.

  3. If we add a <clear namelist="field1"/> statement to the <filled> section of the first field (field1), the FIA will revisit and re-execute the first field repeatedly without going on to any subsequent form items. In the grammar testing application in Lesson 5, this was done deliberately to allow the caller to test a number of different utterances in the same application without having to call repeatedly.