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