• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()99 int 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