roman.cpp 5.6 KB

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