| Home | Libraries | People | FAQ | More

#### Keyword List Operator

###### Description

The keyword list operator, `kwd("k1")[a] / kwd("k2")[b]`, works tightly with the kwd, ikwd directives to effeciently match keyword lists. As long as one of the keywords specified through the kwd or ikwd directive matches, the keyword will be immediatly followed by the the keyword's associated subject parser. The parser will continue parsing input as long as the one of the keywords and it's associated parser succeed. Writing : (kwd("k1")[a] / kwd("k2")[b] / ... ) is equivalent to: *( "k1" > a | "k2" > b ... ).

###### Header

    // forwards to <boost/spirit/repository/home/qi/operator/keywords.hpp>
    #include <boost/spirit/repository/include/qi_keywords.hpp>

###### Expression Semantics

Expression | Semantics
--- | ---
`kwd(k1)[a] / kwd(k2)[b]` | Match `lit(k1) > a` or `lit(k2) > b`, equivalent to `lit(k1) > a | lit(k2) > b`

###### Attributes

Expression | Attribute
--- | ---
`kwd("k1")[a] / kwd("k2")[b]` |
    a: A, b: B --> (kwd(k1)[a] / kwd(k2)[b]): tuple<A, B>
    a: A, b: Unused --> (kwd(k1)[a] / kwd(k2)[b]): optional<A>
    a: Unused, b: B --> (kwd("k1")[a] / kwd(k2)[b]): optional<B>
    a: Unused, b: Unused --> (kwd(k1)[a] / kwd(k2)[b]): Unused

    a: A, b: A -->(kwd(k1)[a] / kwd(k2)[b]): tuple<A, A>

| Note
The keyword list parser works tightly with the kwd and ikwd directives and can't be used without it. A compile time error will warn you of any mistakes. This parser collects all the kwd directives and extracts the keyword literals from the directives to internaly build a Ternary Search Tree (TST) to effectively parse the keywords. Because you we can't mix character types inside a TST you must take care not to mix wide strings with normal strings in the keyword you supply to a keyword list. Should it happen the compiler will trap the mistake for you.

| Note
The kwd directive also works a bit like the repeat directive and can be used to formulate additional contraints on the number of times a keyword can occur while parsing a keyword list.

| Note
The kwd and ikwd directives can be mixed inside a keyword list. This has however a small overhead and should be avoided when possible.

###### Complexity

> The overall complexity of the keyword list parser is defined by the sum of the complexities of its elements. The complexity of the keyword list itself is determined by the complexity of the internal TST contents :

> O(log n+k)

> Where k is the length of the string to be searched in a TST with n strings.

###### Example

| Note
The test harness for the example(s) below is presented in the Basics Examples section.

Declare a small data structure representing a person:

    // Data structure definitions to test the kwd directive
    // and the keywords list operator

    struct person {
        std::string name;
        int age;
        double size;
        std::vector<std::string> favorite_colors;

    };

    std::ostream &operator<<(std::ostream &os, const person &p)
    {
        os<<"Person : "<<p.name<<", "<<p.age<<", "<<p.size<<std::endl;
        std::copy(p.favorite_colors.begin(),p.favorite_colors.end(),std::ostream_iterator<std::string>(os,"\n"));
        return os;
    }

    BOOST_FUSION_ADAPT_STRUCT( person,
        (std::string, name)
        (int, age)
        (double, size)
        (std::vector<std::string>, favorite_colors)
    )

Some using declarations:

    using boost::spirit::repository::qi::kwd;
    using boost::spirit::qi::inf;
    using boost::spirit::ascii::space_type;
    using boost::spirit::ascii::char_;
    using boost::spirit::qi::double_;
    using boost::spirit::qi::int_;
    using boost::spirit::qi::rule;

Now let's declare a keyword parser:

    no_constraint_person_rule %=
        kwd("name")['=' > parse_string ]
      / kwd("age")   ['=' > int_]
      / kwd("size")   ['=' > double_ > 'm']
      ;

A couple of input string variations run on the same parser:

Parsing a keyword list:

    // Let's declare a small list of people for which we want to collect information.
    person John,Mary,Mike,Hellen,Johny;
    test_phrase_parser_attr(
                    "name = \"John\" \n age = 10 \n size = 1.69m "
                    ,no_constraint_person_rule
                    ,John);  // full in orginal order
    std::cout<<John;

    test_phrase_parser_attr(
                    "age = 10 \n size = 1.69m \n name = \"Mary\""
                    ,no_constraint_person_rule
                    ,Mary);  // keyword oder doesn't matter
    std::cout<<Mary;

    test_phrase_parser_attr(
                     "size = 1.69m \n name = \"Mike\" \n age = 10 "
                    ,no_constraint_person_rule
                    ,Mike);  // still the same result

    std::cout<<Mike;

The code above will print:

    Person : John, 10, 1.69
    Person : Mary, 10, 1.69
    Person : Mike, 10, 1.69

Now let's delcare a parser with some occurence constraints:

The parser definition below uses the kwd directive occurence constraint variants to make sure that the name and age keyword occur only once and allows the favorite color entry to appear 0 or more times.

    constraint_person_rule %=
        kwd("name",1)                 ['=' > parse_string ]
      / kwd("age"   ,1)                 ['=' > int_]
      / kwd("size"   ,1)                 ['=' > double_ > 'm']
      / kwd("favorite color",0,inf) [ '=' > parse_string ]
      ;

And see how it works in these two cases:

     // Here all the give constraint are resepected : parsing will succeed.
     test_phrase_parser_attr(
         "name = \"Hellen\" \n age = 10 \n size = 1.80m \n favorite color = \"blue\" \n favorite color = \"green\" "
         ,constraint_person_rule
         ,Hellen);
     std::cout<<Hellen;

    // Parsing this string will fail because the age and size minimum occurence requirements aren't met.
    test_phrase_parser_attr(
         "name = \"Johny\"  \n favorite color = \"blue\" \n favorite color = \"green\" "
         ,constraint_person_rule
         ,Johny );

Parsing the first string will succeed but fail for the second string as the occurence constraints aren't met. This code should print:

    Person : Hellen, 10, 1.8
    blue
    green