Imported Upstream version 1.63.0
[platform/upstream/boost.git] / libs / context / example / v2 / parser.cpp
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 <cstdlib>
8 #include <exception>
9 #include <functional>
10 #include <iostream>
11 #include <memory>
12 #include <sstream>
13
14 #include <boost/context/all.hpp>
15
16 namespace ctx = boost::context;
17
18 /*
19  * grammar:
20  *   P ---> E '\0'
21  *   E ---> T {('+'|'-') T}
22  *   T ---> S {('*'|'/') S}
23  *   S ---> digit | '(' E ')'
24  */
25 class Parser{
26    char next;
27    std::istream& is;
28    std::function<void(char)> cb;
29
30    char pull(){
31         return std::char_traits<char>::to_char_type(is.get());
32    }
33
34    void scan(){
35        do{
36            next=pull();
37        }
38        while(isspace(next));
39    }
40
41 public:
42    Parser(std::istream& is_,std::function<void(char)> cb_) :
43       next(), is(is_), cb(cb_)
44     {}
45
46    void run() {
47       scan();
48       E();
49    }
50
51 private:
52    void E(){
53       T();
54       while (next=='+'||next=='-'){
55          cb(next);
56          scan();
57          T();
58       }
59    }
60
61    void T(){
62       S();
63       while (next=='*'||next=='/'){
64          cb(next);
65          scan();
66          S();
67       }
68    }
69
70    void S(){
71       if (isdigit(next)){
72          cb(next);
73          scan();
74       }
75       else if(next=='('){
76          cb(next);
77          scan();
78          E();
79          if (next==')'){
80              cb(next);
81              scan();
82          }else{
83              throw std::runtime_error("parsing failed");
84          }
85       }
86       else{
87          throw std::runtime_error("parsing failed");
88       }
89    }
90 };
91
92 int main() {
93     try {
94         std::istringstream is("1+1");
95         bool done=false;
96         std::exception_ptr except;
97
98         // execute parser in new execution context
99         boost::context::execution_context<char> source(
100                 [&is,&done,&except](ctx::execution_context<char> && sink,char){
101                 // create parser with callback function
102                 Parser p( is,
103                           [&sink](char ch){
104                                 // resume main execution context
105                                 auto result = sink(ch);
106                                 sink = std::move(std::get<0>(result));
107                         });
108                     try {
109                         // start recursive parsing
110                         p.run();
111                     } catch (...) {
112                         // store other exceptions in exception-pointer
113                         except = std::current_exception();
114                     }
115                     // set termination flag
116                     done=true;
117                     // resume main execution context
118                     return std::move( sink);
119                 });
120
121         // user-code pulls parsed data from parser
122         // invert control flow
123         auto result = source('\0');
124         source = std::move(std::get<0>(result));
125         char c = std::get<1>(result);
126         if ( except) {
127             std::rethrow_exception(except);
128         }
129         while( ! done) {
130             printf("Parsed: %c\n",c);
131             std::tie(source,c) = source('\0');
132             if (except) {
133                 std::rethrow_exception(except);
134             }
135         }
136
137         std::cout << "main: done" << std::endl;
138
139         return EXIT_SUCCESS;
140     } catch ( std::exception const& e) {
141         std::cerr << "exception: " << e.what() << std::endl;
142     }
143     return EXIT_FAILURE;
144 }