]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
mod_rayo: add some hacky support for SISR in DTMF recognizer
authorChris Rienzo <chris.rienzo@grasshopper.com>
Fri, 30 Aug 2013 21:43:10 +0000 (17:43 -0400)
committerChris Rienzo <chris.rienzo@grasshopper.com>
Fri, 30 Aug 2013 21:45:37 +0000 (17:45 -0400)
src/mod/event_handlers/mod_rayo/nlsml.c
src/mod/event_handlers/mod_rayo/nlsml.h
src/mod/event_handlers/mod_rayo/rayo_input_component.c
src/mod/event_handlers/mod_rayo/srgs.c
src/mod/event_handlers/mod_rayo/srgs.h
src/mod/event_handlers/mod_rayo/test_nlsml/main.c
src/mod/event_handlers/mod_rayo/test_srgs/main.c

index b5e9cefa4f301c7394b1e24bdaffee895e34f729..b050565071cfd840888edd5f9b84a89df686a512 100644 (file)
@@ -397,9 +397,10 @@ static int isdtmf(const char digit)
 /**
  * Construct an NLSML result for digit match
  * @param digits the matching digits
+ * @param interpretation the optional digit interpretation
  * @return the NLSML <result>
  */
-iks *nlsml_create_dtmf_match(const char *digits)
+iks *nlsml_create_dtmf_match(const char *digits, const char *interpretation)
 {
        iks *result = iks_new("result");
        iks_insert_attrib(result, "xmlns", NLSML_NS);
@@ -410,10 +411,11 @@ iks *nlsml_create_dtmf_match(const char *digits)
                int num_digits = strlen(digits);
                switch_stream_handle_t stream = { 0 };
 
-               iks *interpretation = iks_insert(result, "interpretation");
-               iks *input = iks_insert(interpretation, "input");
-               iks_insert_attrib(input, "mode", "dtmf");
-               iks_insert_attrib(input, "confidence", "100");
+               iks *interpretation_node = iks_insert(result, "interpretation");
+               iks *input_node = iks_insert(interpretation_node, "input");
+               iks *instance_node = iks_insert(interpretation_node, "instance");
+               iks_insert_attrib(input_node, "mode", "dtmf");
+               iks_insert_attrib(input_node, "confidence", "100");
 
                SWITCH_STANDARD_STREAM(stream);
                for (i = 0; i < num_digits; i++) {
@@ -426,7 +428,13 @@ iks *nlsml_create_dtmf_match(const char *digits)
                                }
                        }
                }
-               iks_insert_cdata(input, stream.data, strlen(stream.data));
+               iks_insert_cdata(input_node, stream.data, strlen(stream.data));
+
+               if (zstr(interpretation)) {
+                       iks_insert_cdata(instance_node, stream.data, strlen(stream.data));
+               } else {
+                       iks_insert_cdata(instance_node, interpretation, strlen(interpretation));
+               }
                switch_safe_free(stream.data);
        }
        return result;
index d8417213ec23282bb1508a4e0aa1b18889222734..75c4ad6378ee79ef354c1639dd4c4c4799bad7cc 100644 (file)
@@ -42,7 +42,7 @@ enum nlsml_match_type {
 extern int nlsml_init(void);
 enum nlsml_match_type nlsml_parse(const char *result, const char *uuid);
 iks *nlsml_normalize(const char *result);
-extern iks *nlsml_create_dtmf_match(const char *digits);
+extern iks *nlsml_create_dtmf_match(const char *digits, const char *interpretation);
 
 #endif
 
index 3bf3b6dfb6677e727799d4e163d9037cc2dec66f..8238deb48adaa9dda98f64d7d9d6c49aa4dc1b52 100644 (file)
@@ -157,6 +157,7 @@ static switch_status_t input_component_on_dtmf(switch_core_session_t *session, c
                int is_term_digit = 0;
                struct input_component *component;
                enum srgs_match_type match;
+               const char *interpretation = NULL;
 
                switch_mutex_lock(handler->mutex);
 
@@ -179,7 +180,7 @@ static switch_status_t input_component_on_dtmf(switch_core_session_t *session, c
                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Collected term digit = \"%c\"\n", dtmf->digit);
                }
 
-               match = srgs_grammar_match(component->grammar, component->digits);
+               match = srgs_grammar_match(component->grammar, component->digits, &interpretation);
 
                /* adjust result if terminating digit was pressed */
                if (is_term_digit) {
@@ -208,7 +209,7 @@ static switch_status_t input_component_on_dtmf(switch_core_session_t *session, c
                                break;
                        }
                        case SMT_MATCH_END: {
-                               iks *result = nlsml_create_dtmf_match(component->digits);
+                               iks *result = nlsml_create_dtmf_match(component->digits, interpretation);
                                /* notify of match and remove input component */
                                handler->dtmf_component = NULL;
                                switch_core_media_bug_remove(session, &handler->bug);
@@ -248,13 +249,14 @@ static switch_bool_t input_component_bug_callback(switch_media_bug_t *bug, void
                                int elapsed_ms = (switch_micro_time_now() - component->last_digit_time) / 1000;
                                if (component->num_digits && component->inter_digit_timeout > 0 && elapsed_ms > component->inter_digit_timeout) {
                                        enum srgs_match_type match;
+                                       const char *interpretation = NULL;
                                        handler->dtmf_component = NULL;
                                        switch_core_media_bug_set_flag(bug, SMBF_PRUNE);
 
                                        /* we got some input, check for match */
-                                       match = srgs_grammar_match(component->grammar, component->digits);
+                                       match = srgs_grammar_match(component->grammar, component->digits, &interpretation);
                                        if (match == SMT_MATCH || match == SMT_MATCH_END) {
-                                               iks *result = nlsml_create_dtmf_match(component->digits);
+                                               iks *result = nlsml_create_dtmf_match(component->digits, interpretation);
                                                /* notify of match */
                                                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "MATCH = %s\n", component->digits);
                                                send_match_event(RAYO_COMPONENT(component), result);
index 1d5ce0e08e882e2a9521601aa188617bada2e146..30c662724b381dc780162b557ccd0ffdb250a853 100644 (file)
@@ -33,6 +33,7 @@
 #include "srgs.h"
 
 #define MAX_RECURSION 100
+#define MAX_TAGS 30
 
 /** function to handle tag attributes */
 typedef int (* tag_attribs_fn)(struct srgs_grammar *, char **);
@@ -111,6 +112,7 @@ struct item_value {
        int repeat_min;
        int repeat_max;
        const char *weight;
+       char *tag;
 };
 
 /**
@@ -161,6 +163,10 @@ struct srgs_grammar {
        struct srgs_node *cur;
        /** rule names mapped to node */
        switch_hash_t *rules;
+       /** possible matching tags */
+       const char *tags[MAX_TAGS];
+       /** number of tags */
+       int tag_count;
        /** grammar encoding */
        char *encoding;
        /** grammar language */
@@ -708,6 +714,30 @@ static int tag_hook(void *user_data, char *name, char **atts, int type)
        return result;
 }
 
+/**
+ * Process <tag> CDATA
+ * @param grammar the grammar
+ * @param data the CDATA
+ * @param len the CDATA length
+ * @return IKS_OK
+ */
+static int process_cdata_tag(struct srgs_grammar *grammar, char *data, size_t len)
+{
+       struct srgs_node *item = grammar->cur->parent;
+       if (item && item->type == SNT_ITEM) {
+               item->value.item.tag = switch_core_alloc(grammar->pool, sizeof(char) * (len + 1));
+               item->value.item.tag[len] = '\0';
+               strncpy(item->value.item.tag, data, len);
+               if (grammar->tag_count < MAX_TAGS) {
+                       grammar->tags[grammar->tag_count++] = item->value.item.tag;
+               } else {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "too many <tag>s\n");
+                       return IKS_BADXML;
+               }
+       }
+       return IKS_OK;
+}
+
 /**
  * Process CDATA grammar tokens
  * @param grammar the grammar
@@ -956,8 +986,12 @@ static int create_regexes(struct srgs_grammar *grammar, struct srgs_node *node,
                case SNT_ITEM:
                        if (node->child) {
                                struct srgs_node *item = node->child;
-                               if (node->value.item.repeat_min != 1 || node->value.item.repeat_max != 1) {
-                                       stream->write_function(stream, "%s", "(?:");
+                               if (node->value.item.repeat_min != 1 || node->value.item.repeat_max != 1 || !zstr(node->value.item.tag)) {
+                                       if (zstr(node->value.item.tag)) {
+                                               stream->write_function(stream, "%s", "(?:");
+                                       } else {
+                                               stream->write_function(stream, "(?P<%s>", node->value.item.tag);
+                                       }
                                }
                                for(; item; item = item->next) {
                                        if (!create_regexes(grammar, item, stream)) {
@@ -980,6 +1014,8 @@ static int create_regexes(struct srgs_grammar *grammar, struct srgs_node *node,
                                        } else {
                                                stream->write_function(stream, "){%i}", node->value.item.repeat_min);
                                        }
+                               } else if (!zstr(node->value.item.tag)) {
+                                       stream->write_function(stream, "%s", ")");
                                }
                        }
                        break;
@@ -1171,7 +1207,7 @@ struct srgs_grammar *srgs_parse(struct srgs_parser *parser, const char *document
 }
 
 #define MAX_INPUT_SIZE 128
-#define OVECTOR_SIZE 30
+#define OVECTOR_SIZE MAX_TAGS
 #define WORKSPACE_SIZE 1024
 
 /**
@@ -1214,15 +1250,17 @@ static int is_match_end(pcre *compiled_regex, const char *input)
  * Find a match
  * @param grammar the grammar to match
  * @param input the input to compare
+ * @param interpretation the (optional) interpretation of the input result
  * @return the match result
  */
-enum srgs_match_type srgs_grammar_match(struct srgs_grammar *grammar, const char *input)
+enum srgs_match_type srgs_grammar_match(struct srgs_grammar *grammar, const char *input, const char **interpretation)
 {
        int result = 0;
        int ovector[OVECTOR_SIZE];
-       int workspace[WORKSPACE_SIZE];
        pcre *compiled_regex;
 
+       *interpretation = NULL;
+
        if (zstr(input)) {
                return SMT_NO_MATCH;
        }
@@ -1234,12 +1272,24 @@ enum srgs_match_type srgs_grammar_match(struct srgs_grammar *grammar, const char
        if (!(compiled_regex = get_compiled_regex(grammar))) {
                return SMT_NO_MATCH;
        }
-       result = pcre_dfa_exec(compiled_regex, NULL, input, strlen(input), 0, PCRE_PARTIAL,
-               ovector, sizeof(ovector) / sizeof(ovector[0]),
-               workspace, sizeof(workspace) / sizeof(workspace[0]));
+       result = pcre_exec(compiled_regex, NULL, input, strlen(input), 0, PCRE_PARTIAL,
+               ovector, OVECTOR_SIZE);
 
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "match = %i\n", result);
        if (result > 0) {
+               int i;
+               char buffer[MAX_INPUT_SIZE + 1];
+               buffer[MAX_INPUT_SIZE] = '\0';
+
+               /* find matching instance... */
+               for (i = 0; i < grammar->tag_count; i++) {
+                       buffer[0] = '\0';
+                       if (pcre_copy_named_substring(compiled_regex, input, ovector, result, grammar->tags[i], buffer, MAX_INPUT_SIZE) != PCRE_ERROR_NOSUBSTRING && !zstr_buf(buffer)) {
+                               *interpretation = grammar->tags[i];
+                               break;
+                       }
+               }
+
                if (is_match_end(compiled_regex, input)) {
                        return SMT_MATCH_END;
                }
@@ -1562,7 +1612,7 @@ int srgs_init(void)
        add_root_tag_def("grammar", process_grammar, process_cdata_bad, "meta,metadata,lexicon,tag,rule");
        add_tag_def("ruleref", process_ruleref, process_cdata_bad, "");
        add_tag_def("token", process_attribs_ignore, process_cdata_ignore, "");
-       add_tag_def("tag", process_attribs_ignore, process_cdata_ignore, "");
+       add_tag_def("tag", process_attribs_ignore, process_cdata_tag, "");
        add_tag_def("one-of", process_attribs_ignore, process_cdata_tokens, "item");
        add_tag_def("item", process_item, process_cdata_tokens, "token,ruleref,item,one-of,tag");
        add_tag_def("rule", process_rule, process_cdata_tokens, "token,ruleref,item,one-of,tag,example");
index f777c9f523067595ef2b530e3189ff662f97ded2..29ee916ce7b86dfc13d7055ab3004fff9d269f5c 100644 (file)
@@ -51,7 +51,7 @@ extern struct srgs_grammar *srgs_parse(struct srgs_parser *parser, const char *d
 extern const char *srgs_grammar_to_regex(struct srgs_grammar *grammar);
 extern const char *srgs_grammar_to_jsgf(struct srgs_grammar *grammar);
 extern const char *srgs_grammar_to_jsgf_file(struct srgs_grammar *grammar, const char *basedir, const char *ext);
-extern enum srgs_match_type srgs_grammar_match(struct srgs_grammar *grammar, const char *input);
+extern enum srgs_match_type srgs_grammar_match(struct srgs_grammar *grammar, const char *input, const char **interpretation);
 extern void srgs_parser_destroy(struct srgs_parser *parser);
 
 #endif
index f5d6067d3bc8d1f3b0aee4ab72520bd75473df60..0577288b7cfb36584902dd6a6f1718e2d356cf63 100644 (file)
@@ -245,14 +245,15 @@ static const char *nlsml_dtmf_result =
        "<result xmlns='http://www.ietf.org/xml/ns/mrcpv2' "
        "xmlns:xf='http://www.w3.org/2000/xforms'><interpretation>"
        "<input mode='dtmf' confidence='100'>1 2 3 4</input>"
+       "<instance>1 2 3 4</instance>"
        "</interpretation></result>";
 
 /**
- * Test parsing NLSML example results
+ * Test creating DTMF match result
  */
 static void test_create_dtmf_match(void)
 {
-       iks *result = nlsml_create_dtmf_match("1234");
+       iks *result = nlsml_create_dtmf_match("1234", NULL);
        char *result_str;
        ASSERT_NOT_NULL(result);
        result_str = iks_string(NULL, result);
@@ -260,6 +261,26 @@ static void test_create_dtmf_match(void)
        iks_free(result_str);
 }
 
+static const char *nlsml_dtmf_instance_result =
+       "<result xmlns='http://www.ietf.org/xml/ns/mrcpv2' "
+       "xmlns:xf='http://www.w3.org/2000/xforms'><interpretation>"
+       "<input mode='dtmf' confidence='100'>1</input>"
+       "<instance>foo</instance>"
+       "</interpretation></result>";
+
+/**
+ * Test creating DTMF match result with instance interpretation
+ */
+static void test_create_dtmf_instance(void)
+{
+       iks *result = nlsml_create_dtmf_match("1", "foo");
+       char *result_str;
+       ASSERT_NOT_NULL(result);
+       result_str = iks_string(NULL, result);
+       ASSERT_STRING_EQUALS(nlsml_dtmf_instance_result, result_str);
+       iks_free(result_str);
+}
+
 static const char *nlsml_good_normalized =
        "<result x-model='http://theYesNoModel'"
        " xmlns:xf='http://www.w3.org/2000/xforms'"
@@ -295,6 +316,7 @@ int main(int argc, char **argv)
        nlsml_init();
        TEST(test_parse_nlsml_examples);
        TEST(test_create_dtmf_match);
+       TEST(test_create_dtmf_instance);
        TEST(test_normalize);
        return 0;
 }
index 0a2fe7a53ef922c701f938efd26196c4954843ac..f97559297df4f6d064d9377468c1674e6fe27d79 100644 (file)
@@ -5,6 +5,67 @@
 #include "srgs.h"
 
 
+static const char *adhearsion_menu_grammar =
+       "<grammar xmlns=\"http://www.w3.org/2001/06/grammar\" version=\"1.0\" xml:lang=\"en-US\" mode=\"dtmf\" root=\"options\" tag-format=\"semantics/1.0-literals\">"
+       "  <rule id=\"options\" scope=\"public\">\n"
+       "    <one-of>\n"
+       "      <item><tag>0</tag>1</item>\n"
+       "      <item><tag>1</tag>5</item>\n"
+       "      <item><tag>2</tag>7</item>\n"
+       "      <item><tag>3</tag>9</item>\n"
+       "    </one-of>\n"
+       "  </rule>\n"
+       "</grammar>\n";
+
+/**
+ * Test matching against adhearsion menu grammar
+ */
+static void test_match_adhearsion_menu_grammar(void)
+{
+       struct srgs_parser *parser;
+       struct srgs_grammar *grammar;
+       const char *interpretation;
+
+       parser = srgs_parser_new("1234");
+       ASSERT_NOT_NULL((grammar = srgs_parse(parser, adhearsion_menu_grammar)));
+
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "0", &interpretation));
+       ASSERT_NULL(interpretation);
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1", &interpretation));
+       ASSERT_STRING_EQUALS("0", interpretation);
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "2", &interpretation));
+       ASSERT_NULL(interpretation);
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "3", &interpretation));
+       ASSERT_NULL(interpretation);
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "4", &interpretation));
+       ASSERT_NULL(interpretation);
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "5", &interpretation));
+       ASSERT_STRING_EQUALS("1", interpretation);
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "6", &interpretation));
+       ASSERT_NULL(interpretation);
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "7", &interpretation));
+       ASSERT_STRING_EQUALS("2", interpretation);
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "8", &interpretation));
+       ASSERT_NULL(interpretation);
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "9", &interpretation));
+       ASSERT_STRING_EQUALS("3", interpretation);
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "#", &interpretation));
+       ASSERT_NULL(interpretation);
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "*", &interpretation));
+       ASSERT_NULL(interpretation);
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A", &interpretation));
+       ASSERT_NULL(interpretation);
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "27", &interpretation));
+       ASSERT_NULL(interpretation);
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "223", &interpretation));
+       ASSERT_NULL(interpretation);
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "0123456789*#", &interpretation));
+       ASSERT_NULL(interpretation);
+
+       srgs_parser_destroy(parser);
+}
+
+
 static const char *adhearsion_ask_grammar =
        "<grammar xmlns=\"http://www.w3.org/2001/06/grammar\" version=\"1.0\" xml:lang=\"en-US\" mode=\"dtmf\" root=\"inputdigits\">"
        "  <rule id=\"inputdigits\" scope=\"public\">\n"
@@ -32,26 +93,28 @@ static void test_match_adhearsion_ask_grammar(void)
 {
        struct srgs_parser *parser;
        struct srgs_grammar *grammar;
+       const char *interpretation;
 
        parser = srgs_parser_new("1234");
        ASSERT_NOT_NULL((grammar = srgs_parse(parser, adhearsion_ask_grammar)));
 
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "0"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "2"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "3"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "4"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "5"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "6"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "7"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "8"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "9"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "#"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "*"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "27"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "223"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "0123456789*#"));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "0", &interpretation));
+       ASSERT_NULL(interpretation);
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "2", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "3", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "4", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "5", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "6", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "7", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "8", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "9", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "*", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "27", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "223", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "0123456789*#", &interpretation));
 
        srgs_parser_destroy(parser);
 }
@@ -84,26 +147,27 @@ static void test_match_multi_digit_grammar(void)
 {
        struct srgs_parser *parser;
        struct srgs_grammar *grammar;
+       const char *interpretation;
 
        parser = srgs_parser_new("1234");
        ASSERT_NOT_NULL((grammar = srgs_parse(parser, multi_digit_grammar)));
 
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "0"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "2"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "3"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "4"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "5"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "6"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "7"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "8"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "9"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "*"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "27"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "223"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "0123456789*#"));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "0", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "2", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "3", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "4", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "5", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "6", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "7", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "8", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "9", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "*", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "27", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "223", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "0123456789*#", &interpretation));
 
        srgs_parser_destroy(parser);
 }
@@ -137,26 +201,27 @@ static void test_match_multi_rule_grammar(void)
 {
        struct srgs_parser *parser;
        struct srgs_grammar *grammar;
+       const char *interpretation;
 
        parser = srgs_parser_new("1234");
        ASSERT_NOT_NULL((grammar = srgs_parse(parser, multi_rule_grammar)));
 
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "0"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "2"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "3"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "4"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "5"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "6"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "7"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "8"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "9"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "*"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "27"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "223"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "0123456789*#"));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "0", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "2", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "3", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "4", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "5", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "6", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "7", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "8", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "9", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "*", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "27", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "223", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "0123456789*#", &interpretation));
 
        srgs_parser_destroy(parser);
 }
@@ -200,28 +265,29 @@ static void test_match_rayo_example_grammar(void)
 {
        struct srgs_parser *parser;
        struct srgs_grammar *grammar;
+       const char *interpretation;
 
        parser = srgs_parser_new("1234");
        ASSERT_NOT_NULL((grammar = srgs_parse(parser, rayo_example_grammar)));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "0"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "2"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "3"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "4"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "5"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "6"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "7"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "8"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "9"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "*"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "*9"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1234#"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "2321#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "27"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "223"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "0123456789*#"));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "0", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "2", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "3", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "4", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "5", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "6", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "7", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "8", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "9", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "*", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "*9", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1234#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "2321#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "27", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "223", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "0123456789*#", &interpretation));
 
        srgs_parser_destroy(parser);
 }
@@ -566,6 +632,7 @@ static void test_repeat_item_grammar(void)
 {
        struct srgs_parser *parser;
        struct srgs_grammar *grammar;
+       const char *interpretation;
 
        parser = srgs_parser_new("1234");
        ASSERT_NULL(srgs_parse(parser, repeat_item_grammar_bad));
@@ -575,74 +642,74 @@ static void test_repeat_item_grammar(void)
        ASSERT_NULL(srgs_parse(parser, repeat_item_grammar_bad5));
        ASSERT_NULL(srgs_parse(parser, repeat_item_grammar_bad6));
        ASSERT_NOT_NULL((grammar = srgs_parse(parser, repeat_item_grammar)));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1111#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1111"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1234#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1234"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "11115#"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "11115"));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1111#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1111", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1234#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1234", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "11115#", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "11115", &interpretation));
        ASSERT_NOT_NULL((grammar = srgs_parse(parser, repeat_item_range_grammar)));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1111#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1111"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1234#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1234"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "11115#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "11115"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "111156#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "111156"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "1111567#"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "1111567"));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1111#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1111", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1234#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1234", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "11115#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "11115", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "111156#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "111156", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "1111567#", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "1111567", &interpretation));
        ASSERT_NOT_NULL((grammar = srgs_parse(parser, repeat_item_optional_grammar)));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "1111#"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "1111"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "1234#"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "1234"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "11115#"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "11115"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "111156#"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "111156"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "1111567#"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "1111567"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "#"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, ""));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A#"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A"));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "1111#", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "1111", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "1234#", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "1234", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "11115#", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "11115", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "111156#", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "111156", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "1111567#", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "1111567", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "#", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A#", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A", &interpretation));
        ASSERT_NOT_NULL((grammar = srgs_parse(parser, repeat_item_plus_grammar)));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1111#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1111"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1234#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1234"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "11115#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "11115"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "111156#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "111156"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "111157#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "111157"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "#"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, ""));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A#"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A"));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1111#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1111", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1234#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1234", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "11115#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "11115", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "111156#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "111156", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "111157#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "111157", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "#", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A#", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A", &interpretation));
        ASSERT_NOT_NULL((grammar = srgs_parse(parser, repeat_item_star_grammar)));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1111#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1111"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1234#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1234"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "11115#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "11115"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "111156#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "111156"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "111157#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "111157"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1#"));
-       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "#"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, ""));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A#"));
-       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A"));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1111#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1111", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1234#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1234", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "11115#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "11115", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "111156#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "111156", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "111157#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "111157", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_PARTIAL, srgs_grammar_match(grammar, "1", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "#", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A#", &interpretation));
+       ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A", &interpretation));
 
        srgs_parser_destroy(parser);
 }
@@ -678,12 +745,13 @@ static void test_repeat_item_range_ambiguous_grammar(void)
 {
        struct srgs_parser *parser;
        struct srgs_grammar *grammar;
+       const char *interpretation;
 
        parser = srgs_parser_new("1234");
        ASSERT_NOT_NULL((grammar = srgs_parse(parser, repeat_item_range_ambiguous_grammar)));
-       ASSERT_EQUALS(SMT_MATCH, srgs_grammar_match(grammar, "1"));
-       ASSERT_EQUALS(SMT_MATCH, srgs_grammar_match(grammar, "12"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "123"));
+       ASSERT_EQUALS(SMT_MATCH, srgs_grammar_match(grammar, "1", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH, srgs_grammar_match(grammar, "12", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "123", &interpretation));
 }
 
 static const char *repeat_item_range_optional_pound_grammar =
@@ -722,14 +790,15 @@ static void test_repeat_item_range_optional_pound_grammar(void)
 {
        struct srgs_parser *parser;
        struct srgs_grammar *grammar;
+       const char *interpretation;
 
        parser = srgs_parser_new("1234");
        ASSERT_NOT_NULL((grammar = srgs_parse(parser, repeat_item_range_optional_pound_grammar)));
-       ASSERT_EQUALS(SMT_MATCH, srgs_grammar_match(grammar, "1"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1#"));
-       ASSERT_EQUALS(SMT_MATCH, srgs_grammar_match(grammar, "12"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "12#"));
-       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "123"));
+       ASSERT_EQUALS(SMT_MATCH, srgs_grammar_match(grammar, "1", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH, srgs_grammar_match(grammar, "12", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "12#", &interpretation));
+       ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "123", &interpretation));
 }
 
 /*
@@ -955,6 +1024,7 @@ int main(int argc, char **argv)
        TEST_INIT
        srgs_init();
        TEST(test_parse_grammar);
+       TEST(test_match_adhearsion_menu_grammar);
        TEST(test_match_adhearsion_ask_grammar);
        TEST(test_match_multi_digit_grammar);
        TEST(test_match_multi_rule_grammar);