1 /*=============================================================================
2 Copyright (c) 2001-2015 Joel de Guzman
3 Copyright (c) 2015 Ahmed Charles
4
5 Distributed under the Boost Software License, Version 1.0. (See accompanying
6 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 =============================================================================*/
8 ///////////////////////////////////////////////////////////////////////////////
9 //
10 // A Roman Numerals Parser (demonstrating the symbol table). This is
11 // discussed in the "Symbols" chapter in the Spirit User's Guide.
12 //
13 // [ JDG August 22, 2002 ] spirit1
14 // [ JDG March 13, 2007 ] spirit2
15 // [ JDG May 13, 2015 ] spirit X3
16 //
17 ///////////////////////////////////////////////////////////////////////////////
18
19 #include <boost/config/warning_disable.hpp>
20 #include <boost/spirit/home/x3.hpp>
21
22 #include <iostream>
23 #include <string>
24
25 namespace client
26 {
27 namespace x3 = boost::spirit::x3;
28 namespace ascii = boost::spirit::x3::ascii;
29
30 ///////////////////////////////////////////////////////////////////////////////
31 // Parse roman hundreds (100..900) numerals using the symbol table.
32 // Notice that the data associated with each slot is the parser's attribute
33 // (which is passed to attached semantic actions).
34 ///////////////////////////////////////////////////////////////////////////////
35 struct hundreds_ : x3::symbols<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 // Parse roman tens (10..90) numerals using the symbol table.
56 ///////////////////////////////////////////////////////////////////////////////
57 struct tens_ : x3::symbols<unsigned>
58 {
tens_client::tens_59 tens_()
60 {
61 add
62 ("X" , 10)
63 ("XX" , 20)
64 ("XXX" , 30)
65 ("XL" , 40)
66 ("L" , 50)
67 ("LX" , 60)
68 ("LXX" , 70)
69 ("LXXX" , 80)
70 ("XC" , 90)
71 ;
72 }
73
74 } tens;
75
76 ///////////////////////////////////////////////////////////////////////////////
77 // Parse roman ones (1..9) numerals using the symbol table.
78 ///////////////////////////////////////////////////////////////////////////////
79 struct ones_ : x3::symbols<unsigned>
80 {
ones_client::ones_81 ones_()
82 {
83 add
84 ("I" , 1)
85 ("II" , 2)
86 ("III" , 3)
87 ("IV" , 4)
88 ("V" , 5)
89 ("VI" , 6)
90 ("VII" , 7)
91 ("VIII" , 8)
92 ("IX" , 9)
93 ;
94 }
95
96 } ones;
97
98 ///////////////////////////////////////////////////////////////////////////////
99 // roman (numerals) grammar
100 //
101 // Note the use of the || operator. The expression
102 // a || b reads match a or b and in sequence. Try
103 // defining the roman numerals grammar in YACC or
104 // PCCTS. Spirit rules! :-)
105 ///////////////////////////////////////////////////////////////////////////////
106 namespace parser
107 {
108 using x3::eps;
109 using x3::lit;
110 using x3::_val;
111 using x3::_attr;
112 using ascii::char_;
113
__anona45750fe0102(auto& ctx)114 auto set_zero = [](auto& ctx){ _val(ctx) = 0; };
__anona45750fe0202(auto& ctx)115 auto add1000 = [](auto& ctx){ _val(ctx) += 1000; };
__anona45750fe0302(auto& ctx)116 auto add = [](auto& ctx){ _val(ctx) += _attr(ctx); };
117
118 x3::rule<class roman, unsigned> const roman = "roman";
119
120 auto const roman_def =
121 eps [set_zero]
122 >>
123 (
124 -(+lit('M') [add1000])
125 >> -hundreds [add]
126 >> -tens [add]
127 >> -ones [add]
128 )
129 ;
130
131 BOOST_SPIRIT_DEFINE(roman);
132 }
133 }
134
135 ///////////////////////////////////////////////////////////////////////////////
136 // Main program
137 ///////////////////////////////////////////////////////////////////////////////
138 int
main()139 main()
140 {
141 std::cout << "/////////////////////////////////////////////////////////\n\n";
142 std::cout << "\t\tRoman Numerals Parser\n\n";
143 std::cout << "/////////////////////////////////////////////////////////\n\n";
144 std::cout << "Type a Roman Numeral ...or [q or Q] to quit\n\n";
145
146 typedef std::string::const_iterator iterator_type;
147 using client::parser::roman; // Our parser
148
149 std::string str;
150 unsigned result;
151 while (std::getline(std::cin, str))
152 {
153 if (str.empty() || str[0] == 'q' || str[0] == 'Q')
154 break;
155
156 iterator_type iter = str.begin();
157 iterator_type const end = str.end();
158 bool r = parse(iter, end, roman, result);
159
160 if (r && iter == end)
161 {
162 std::cout << "-------------------------\n";
163 std::cout << "Parsing succeeded\n";
164 std::cout << "result = " << result << std::endl;
165 std::cout << "-------------------------\n";
166 }
167 else
168 {
169 std::string rest(iter, end);
170 std::cout << "-------------------------\n";
171 std::cout << "Parsing failed\n";
172 std::cout << "stopped at: \": " << rest << "\"\n";
173 std::cout << "-------------------------\n";
174 }
175 }
176
177 std::cout << "Bye... :-) \n\n";
178 return 0;
179 }
180