• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Copyright (c) 2002-2003 Joel de Guzman
3     http://spirit.sourceforge.net/
4 
5     Use, modification and distribution is subject to the Boost Software
6     License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7     http://www.boost.org/LICENSE_1_0.txt)
8 =============================================================================*/
9 ///////////////////////////////////////////////////////////////////////////////
10 //
11 //  A Roman Numerals Parser (demonstrating the symbol table). This is
12 //  discussed in the "Symbols" chapter in the Spirit User's Guide.
13 //
14 //  [ JDG 8/22/2002 ]
15 //
16 ///////////////////////////////////////////////////////////////////////////////
17 #include <boost/spirit/include/classic_core.hpp>
18 #include <boost/spirit/include/classic_symbols.hpp>
19 #include <iostream>
20 #include <string>
21 
22 ///////////////////////////////////////////////////////////////////////////////
23 using namespace std;
24 using namespace BOOST_SPIRIT_CLASSIC_NS;
25 
26 ///////////////////////////////////////////////////////////////////////////////
27 //
28 //  Parse roman hundreds (100..900) numerals using the symbol table.
29 //  Notice that the data associated with each slot is passed
30 //  to attached semantic actions.
31 //
32 ///////////////////////////////////////////////////////////////////////////////
33 struct hundreds : symbols<unsigned>
34 {
hundredshundreds35     hundreds()
36     {
37         add
38             ("C"    , 100)
39             ("CC"   , 200)
40             ("CCC"  , 300)
41             ("CD"   , 400)
42             ("D"    , 500)
43             ("DC"   , 600)
44             ("DCC"  , 700)
45             ("DCCC" , 800)
46             ("CM"   , 900)
47         ;
48     }
49 
50 } hundreds_p;
51 
52 ///////////////////////////////////////////////////////////////////////////////
53 //
54 //  Parse roman tens (10..90) numerals using the symbol table.
55 //
56 ///////////////////////////////////////////////////////////////////////////////
57 struct tens : symbols<unsigned>
58 {
tenstens59     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_p;
75 
76 ///////////////////////////////////////////////////////////////////////////////
77 //
78 //  Parse roman ones (1..9) numerals using the symbol table.
79 //
80 ///////////////////////////////////////////////////////////////////////////////
81 struct ones : symbols<unsigned>
82 {
onesones83     ones()
84     {
85         add
86             ("I"    , 1)
87             ("II"   , 2)
88             ("III"  , 3)
89             ("IV"   , 4)
90             ("V"    , 5)
91             ("VI"   , 6)
92             ("VII"  , 7)
93             ("VIII" , 8)
94             ("IX"   , 9)
95         ;
96     }
97 
98 } ones_p;
99 
100 ///////////////////////////////////////////////////////////////////////////////
101 //
102 //  Semantic actions
103 //
104 ///////////////////////////////////////////////////////////////////////////////
105 struct add_1000
106 {
add_1000add_1000107     add_1000(unsigned& r_) : r(r_) {}
operator ()add_1000108     void operator()(char) const { r += 1000; }
109     unsigned& r;
110 };
111 
112 struct add_roman
113 {
add_romanadd_roman114     add_roman(unsigned& r_) : r(r_) {}
operator ()add_roman115     void operator()(unsigned n) const { r += n; }
116     unsigned& r;
117 };
118 
119 ///////////////////////////////////////////////////////////////////////////////
120 //
121 //  roman (numerals) grammar
122 //
123 ///////////////////////////////////////////////////////////////////////////////
124 struct roman : public grammar<roman>
125 {
126     template <typename ScannerT>
127     struct definition
128     {
definitionroman::definition129         definition(roman const& self)
130         {
131             first
132                 =   +ch_p('M')  [add_1000(self.r)]
133                 ||  hundreds_p  [add_roman(self.r)]
134                 ||  tens_p      [add_roman(self.r)]
135                 ||  ones_p      [add_roman(self.r)];
136 
137             //  Note the use of the || operator. The expression
138             //  a || b reads match a or b and in sequence. Try
139             //  defining the roman numerals grammar in YACC or
140             //  PCCTS. Spirit rules! :-)
141         }
142 
143         rule<ScannerT> first;
144         rule<ScannerT> const&
startroman::definition145         start() const { return first; }
146     };
147 
romanroman148     roman(unsigned& r_) : r(r_) {}
149     unsigned& r;
150 };
151 
152 ///////////////////////////////////////////////////////////////////////////////
153 //
154 //  Main driver code
155 //
156 ///////////////////////////////////////////////////////////////////////////////
157 int
main()158 main()
159 {
160     cout << "/////////////////////////////////////////////////////////\n\n";
161     cout << "\t\tRoman Numerals Parser\n\n";
162     cout << "/////////////////////////////////////////////////////////\n\n";
163     cout << "Type a Roman Numeral ...or [q or Q] to quit\n\n";
164 
165     //  Start grammar definition
166 
167     string str;
168     while (getline(cin, str))
169     {
170         if (str.empty() || str[0] == 'q' || str[0] == 'Q')
171             break;
172 
173         unsigned n = 0;
174         roman roman_p(n);
175         if (parse(str.c_str(), roman_p).full)
176         {
177             cout << "parsing succeeded\n";
178             cout << "result = " << n << "\n\n";
179         }
180         else
181         {
182             cout << "parsing failed\n\n";
183         }
184     }
185 
186     cout << "Bye... :-) \n\n";
187 
188     return 0;
189 }
190