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 
__anon9ef4f84d0102(auto& ctx)114         auto set_zero = [](auto& ctx){ _val(ctx) = 0; };
__anon9ef4f84d0202(auto& ctx)115         auto add1000 = [](auto& ctx){ _val(ctx) += 1000; };
__anon9ef4f84d0302(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