• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Copyright (c) 2001-2010 Joel de Guzman
3 
4     Distributed under the Boost Software License, Version 1.0. (See accompanying
5     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 =============================================================================*/
7 ///////////////////////////////////////////////////////////////////////////////
8 //
9 //  A Roman Numerals Parser (demonstrating the symbol table). This is
10 //  discussed in the "Symbols" chapter in the Spirit User's Guide.
11 //
12 //  [ JDG August 22, 2002 ] spirit1
13 //  [ JDG March 13, 2007 ]  spirit2
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16 
17 #include <boost/config/warning_disable.hpp>
18 #include <boost/spirit/include/qi.hpp>
19 #include <boost/spirit/include/phoenix_operator.hpp>
20 
21 #include <iostream>
22 #include <string>
23 
24 namespace client
25 {
26     namespace qi = boost::spirit::qi;
27     namespace ascii = boost::spirit::ascii;
28 
29     ///////////////////////////////////////////////////////////////////////////////
30     //  Parse roman hundreds (100..900) numerals using the symbol table.
31     //  Notice that the data associated with each slot is the parser's attribute
32     //  (which is passed to attached semantic actions).
33     ///////////////////////////////////////////////////////////////////////////////
34     //[tutorial_roman_hundreds
35     struct hundreds_ : qi::symbols<char, unsigned>
36     {
hundreds_client::hundreds_37         hundreds_()
38         {
39             add
40                 ("C"    , 100)
41                 ("CC"   , 200)
42                 ("CCC"  , 300)
43                 ("CD"   , 400)
44                 ("D"    , 500)
45                 ("DC"   , 600)
46                 ("DCC"  , 700)
47                 ("DCCC" , 800)
48                 ("CM"   , 900)
49             ;
50         }
51 
52     } hundreds;
53     //]
54 
55     ///////////////////////////////////////////////////////////////////////////////
56     //  Parse roman tens (10..90) numerals using the symbol table.
57     ///////////////////////////////////////////////////////////////////////////////
58     //[tutorial_roman_tens
59     struct tens_ : qi::symbols<char, unsigned>
60     {
tens_client::tens_61         tens_()
62         {
63             add
64                 ("X"    , 10)
65                 ("XX"   , 20)
66                 ("XXX"  , 30)
67                 ("XL"   , 40)
68                 ("L"    , 50)
69                 ("LX"   , 60)
70                 ("LXX"  , 70)
71                 ("LXXX" , 80)
72                 ("XC"   , 90)
73             ;
74         }
75 
76     } tens;
77     //]
78 
79     ///////////////////////////////////////////////////////////////////////////////
80     //  Parse roman ones (1..9) numerals using the symbol table.
81     ///////////////////////////////////////////////////////////////////////////////
82     //[tutorial_roman_ones
83     struct ones_ : qi::symbols<char, unsigned>
84     {
ones_client::ones_85         ones_()
86         {
87             add
88                 ("I"    , 1)
89                 ("II"   , 2)
90                 ("III"  , 3)
91                 ("IV"   , 4)
92                 ("V"    , 5)
93                 ("VI"   , 6)
94                 ("VII"  , 7)
95                 ("VIII" , 8)
96                 ("IX"   , 9)
97             ;
98         }
99 
100     } ones;
101     //]
102 
103     ///////////////////////////////////////////////////////////////////////////////
104     //  roman (numerals) grammar
105     //
106     //      Note the use of the || operator. The expression
107     //      a || b reads match a or b and in sequence. Try
108     //      defining the roman numerals grammar in YACC or
109     //      PCCTS. Spirit rules! :-)
110     ///////////////////////////////////////////////////////////////////////////////
111     //[tutorial_roman_grammar
112     template <typename Iterator>
113     struct roman : qi::grammar<Iterator, unsigned()>
114     {
romanclient::roman115         roman() : roman::base_type(start)
116         {
117             using qi::eps;
118             using qi::lit;
119             using qi::_val;
120             using qi::_1;
121             using ascii::char_;
122 
123             start = eps             [_val = 0] >>
124                 (
125                     +lit('M')       [_val += 1000]
126                     ||  hundreds    [_val += _1]
127                     ||  tens        [_val += _1]
128                     ||  ones        [_val += _1]
129                 )
130             ;
131         }
132 
133         qi::rule<Iterator, unsigned()> start;
134     };
135     //]
136 }
137 
138 ///////////////////////////////////////////////////////////////////////////////
139 //  Main program
140 ///////////////////////////////////////////////////////////////////////////////
141 int
main()142 main()
143 {
144     std::cout << "/////////////////////////////////////////////////////////\n\n";
145     std::cout << "\t\tRoman Numerals Parser\n\n";
146     std::cout << "/////////////////////////////////////////////////////////\n\n";
147     std::cout << "Type a Roman Numeral ...or [q or Q] to quit\n\n";
148 
149     typedef std::string::const_iterator iterator_type;
150     typedef client::roman<iterator_type> roman;
151 
152     roman roman_parser; // Our grammar
153 
154     std::string str;
155     unsigned result;
156     while (std::getline(std::cin, str))
157     {
158         if (str.empty() || str[0] == 'q' || str[0] == 'Q')
159             break;
160 
161         std::string::const_iterator iter = str.begin();
162         std::string::const_iterator end = str.end();
163         //[tutorial_roman_grammar_parse
164         bool r = parse(iter, end, roman_parser, result);
165 
166         if (r && iter == end)
167         {
168             std::cout << "-------------------------\n";
169             std::cout << "Parsing succeeded\n";
170             std::cout << "result = " << result << std::endl;
171             std::cout << "-------------------------\n";
172         }
173         else
174         {
175             std::string rest(iter, end);
176             std::cout << "-------------------------\n";
177             std::cout << "Parsing failed\n";
178             std::cout << "stopped at: \": " << rest << "\"\n";
179             std::cout << "-------------------------\n";
180         }
181         //]
182     }
183 
184     std::cout << "Bye... :-) \n\n";
185     return 0;
186 }
187 
188 
189