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

source code of boost/libs/spirit/example/qi/roman.cpp