1 2 // Copyright Oliver Kowalke 2014. 3 // Distributed under the Boost Software License, Version 1.0. 4 // (See accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt) 6 7 #include <cctype> 8 #include <cstdio> 9 #include <exception> 10 #include <functional> 11 #include <iostream> 12 #include <sstream> 13 14 #include <boost/coroutine2/all.hpp> 15 16 class parser_error : public std::runtime_error { 17 public: parser_error()18 parser_error() : 19 std::runtime_error("parsing failed") { 20 } 21 }; 22 23 /* 24 * grammar: 25 * P ---> E '\0' 26 * E ---> T {('+'|'-') T} 27 * T ---> S {('*'|'/') S} 28 * S ---> digit | '(' E ')' 29 */ 30 class Parser{ 31 char next; 32 std::istream& is; 33 std::function<void(char)> cb; 34 pull()35 char pull(){ 36 return std::char_traits<char>::to_char_type(is.get()); 37 } 38 scan()39 void scan(){ 40 do{ 41 next=pull(); 42 } 43 while(isspace(next)); 44 } 45 46 public: Parser(std::istream & is_,std::function<void (char)> cb_)47 Parser(std::istream& is_,std::function<void(char)> cb_) : 48 next(), is(is_), cb(cb_) 49 {} 50 run()51 void run() { 52 scan(); 53 E(); 54 } 55 56 private: E()57 void E(){ 58 T(); 59 while (next=='+'||next=='-'){ 60 cb(next); 61 scan(); 62 T(); 63 } 64 } 65 T()66 void T(){ 67 S(); 68 while (next=='*'||next=='/'){ 69 cb(next); 70 scan(); 71 S(); 72 } 73 } 74 S()75 void S(){ 76 if (std::isdigit(next)){ 77 cb(next); 78 scan(); 79 } 80 else if(next=='('){ 81 cb(next); 82 scan(); 83 E(); 84 if (next==')'){ 85 cb(next); 86 scan(); 87 }else{ 88 throw parser_error(); 89 } 90 } 91 else{ 92 throw parser_error(); 93 } 94 } 95 }; 96 97 typedef boost::coroutines2::coroutine< char > coro_t; 98 main()99int main() { 100 try { 101 std::istringstream is("1+1"); 102 // invert control flow 103 coro_t::pull_type seq( 104 [&is]( coro_t::push_type & yield) { 105 Parser p( is, 106 [&yield](char ch){ 107 yield(ch); 108 }); 109 p.run(); 110 }); 111 // user-code pulls parsed data from parser 112 for(char c:seq){ 113 printf("Parsed: %c\n",c); 114 } 115 std::cout << "\nDone" << std::endl; 116 return EXIT_SUCCESS; 117 } catch ( std::exception const& ex) { 118 std::cerr << "exception: " << ex.what() << std::endl; 119 } 120 return EXIT_FAILURE; 121 } 122 123