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