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