Mercurial > hg > Members > nobuyasu > SampleSource
comparison boost-spirit/CALC/closure2/calc.cpp @ 0:db40c85cad7a default tip
upload sample source
author | nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 09 May 2011 03:11:59 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:db40c85cad7a |
---|---|
1 #include <boost/spirit.hpp> | |
2 #include <boost/spirit/phoenix.hpp> | |
3 #include <boost/shared_ptr.hpp> | |
4 #include <boost/mem_fn.hpp> | |
5 #include <iostream> | |
6 #include <map> | |
7 #include <vector> | |
8 #include <string> | |
9 #include <cassert> | |
10 #include <algorithm> | |
11 #include <functional> | |
12 #include "node.h" | |
13 | |
14 using namespace std; | |
15 using namespace boost::spirit; | |
16 | |
17 typedef file_iterator<> iterator_t; | |
18 | |
19 map<string, int> values; // 変数テーブル | |
20 | |
21 // 文の実行関数定義 | |
22 class caction { | |
23 public: | |
24 virtual ~caction() | |
25 { | |
26 } | |
27 | |
28 virtual void action() const = 0; | |
29 } ; | |
30 | |
31 typedef boost::shared_ptr<caction> caction_t; | |
32 | |
33 // 代入文 | |
34 class cassign_action: public caction { | |
35 public: | |
36 cassign_action(const string &value, cnode_t node) | |
37 : value_(value), node_(node) | |
38 { | |
39 } | |
40 | |
41 virtual void action() const; | |
42 | |
43 protected: | |
44 string value_; | |
45 cnode_t node_; | |
46 } ; | |
47 | |
48 // 代入文の実行関数 | |
49 void cassign_action::action() const | |
50 { | |
51 values[value_] = node_->expr(values); | |
52 } | |
53 | |
54 // print文 | |
55 class cprint_action: public caction { | |
56 public: | |
57 cprint_action(cnode_t node) | |
58 : node_(node) | |
59 { | |
60 } | |
61 | |
62 virtual void action() const; | |
63 | |
64 protected: | |
65 cnode_t node_; | |
66 } ; | |
67 | |
68 // print文の実行関数 | |
69 void cprint_action::action() const | |
70 { | |
71 std::cout << node_->expr(values) << std::endl; | |
72 } | |
73 | |
74 // list文 | |
75 class clist_action: public caction { | |
76 public: | |
77 clist_action() | |
78 { | |
79 } | |
80 | |
81 virtual void action() const; | |
82 } ; | |
83 | |
84 // list文の実行関数 | |
85 struct print_value { | |
86 void operator()(const std::pair<std::string, int> &it) | |
87 { | |
88 std::cout << it.first << " = " << it.second << std::endl; | |
89 } | |
90 } ; | |
91 | |
92 void clist_action::action() const | |
93 { | |
94 for_each(values.begin(), values.end(), print_value()); | |
95 } | |
96 | |
97 // エラー処理パーサー定義 | |
98 struct error_parser { | |
99 typedef nil_t result_t; // パーサーの結果型(nil_t) | |
100 | |
101 error_parser(char const *msg) | |
102 : msg_(msg) | |
103 { | |
104 } | |
105 | |
106 template <typename ScannerT> | |
107 int operator()(ScannerT const &scan, result_t &result) const | |
108 { | |
109 // 終わりまで来たら-1を返す | |
110 if (scan.at_end()) { | |
111 return -1; | |
112 } | |
113 | |
114 // 解釈した「長さ」を返すと、その分スキップするので | |
115 // 改行までをスキャンし、その分をスキップ | |
116 | |
117 iterator_t b = scan.first; | |
118 size_t length = (*(anychar_p - '\n')).parse(scan).length(); | |
119 cout << msg_ << " : " << string(b, scan.first) << endl; | |
120 return (int)length + 1; | |
121 } | |
122 | |
123 private: | |
124 const char *msg_; | |
125 } ; | |
126 | |
127 // エラー処理パーサー | |
128 typedef functor_parser<error_parser> error_p; | |
129 | |
130 // 文法エラー処理パーサー | |
131 error_p syntax_error_p = error_parser("文法エラー"); | |
132 | |
133 // 単項演算子ノードを生成する | |
134 struct unary_node_impl { | |
135 template <typename Ty1, typename Ty2> | |
136 struct result { typedef cnode_t type; } ; | |
137 | |
138 template <typename Ty1, typename Ty2> | |
139 cnode_t operator()(Ty1 op, const Ty2 &left) const | |
140 { | |
141 return cnode_t(new cnode(op, left)); | |
142 } | |
143 } ; | |
144 | |
145 // 二項演算子ノードを生成する | |
146 struct binary_node_impl { | |
147 template <typename Ty1, typename Ty2, typename Ty3> | |
148 struct result { typedef cnode_t type; } ; | |
149 | |
150 template <typename Ty1, typename Ty2, typename Ty3> | |
151 cnode_t operator()(Ty1 op, const Ty2 &left, const Ty3 &right) const | |
152 { | |
153 return cnode_t(new cnode(op, left, right)); | |
154 } | |
155 } ; | |
156 | |
157 // phoenixが使用する「無名関数」用の関数 | |
158 phoenix::function<binary_node_impl> const binary_node = binary_node_impl(); | |
159 phoenix::function<unary_node_impl> const unary_node = unary_node_impl(); | |
160 | |
161 // 文法定義 | |
162 struct calc_grammer: public grammar<calc_grammer> { | |
163 calc_grammer(vector<caction_t> &statements) | |
164 :statements_(statements) | |
165 { | |
166 } | |
167 | |
168 // 文を登録しておくvector | |
169 vector<caction_t> &statements_; | |
170 | |
171 // 変数名のクロージャ | |
172 struct ident_val: closure<ident_val, std::string> { | |
173 member1 str; | |
174 } ; | |
175 // 数字のクロージャ | |
176 struct number_val: closure<number_val, unsigned int> { | |
177 member1 number; | |
178 } ; | |
179 // ノードのクロージャ | |
180 struct node_val: closure<node_val, cnode_t> { | |
181 member1 node; | |
182 } ; | |
183 // 代入文のクロージャ | |
184 struct assign_val: closure<assign_val, caction_t, std::string> { | |
185 member1 action; | |
186 member2 value; | |
187 } ; | |
188 // (代入以外の)文のクロージャ | |
189 struct state_val: closure<state_val, caction_t> { | |
190 member1 action; | |
191 } ; | |
192 | |
193 template <typename ScannerT> | |
194 struct definition { | |
195 rule<ScannerT, ident_val::context_t> identifier; | |
196 rule<ScannerT, number_val::context_t> number; | |
197 rule<ScannerT, node_val::context_t> prime; | |
198 rule<ScannerT, node_val::context_t> unary; | |
199 rule<ScannerT, node_val::context_t> mul_expr; | |
200 rule<ScannerT, node_val::context_t> add_expr; | |
201 rule<ScannerT, assign_val::context_t> assign; | |
202 rule<ScannerT, state_val::context_t> print; | |
203 rule<ScannerT, state_val::context_t> list; | |
204 rule<ScannerT, state_val::context_t> statement; | |
205 rule<ScannerT> input; | |
206 rule<ScannerT> ident; | |
207 | |
208 symbols<> keywords; | |
209 dynamic_distinct_parser<ScannerT> keyword_p; | |
210 | |
211 definition(calc_grammer const& self) | |
212 :keyword_p(alnum_p | '_') | |
213 { | |
214 using phoenix::arg1; | |
215 using phoenix::arg2; | |
216 using phoenix::var; | |
217 using phoenix::new_; | |
218 using phoenix::construct_; | |
219 | |
220 keywords = "print", "list"; | |
221 ident = lexeme_d[ | |
222 ((alpha_p | '_') >> *(alnum_p | '_')) - (keywords >> anychar_p - (alnum_p | '_')) | |
223 ]; | |
224 | |
225 identifier = ident[identifier.str = construct_<string>(arg1, arg2)]; | |
226 number = uint_p[number.number = arg1]; | |
227 | |
228 prime = identifier[prime.node = unary_node(OP_IDENT, arg1)] | |
229 | number[prime.node = unary_node(OP_NUMBER, arg1)] | |
230 | '(' >> add_expr[prime.node = arg1] >> ')' | |
231 ; | |
232 | |
233 unary = prime[unary.node = arg1] | |
234 | '-' >> prime[unary.node = unary_node(OP_NEG, arg1)] | |
235 ; | |
236 | |
237 mul_expr = unary[mul_expr.node = arg1] | |
238 >> *('*' >> unary[mul_expr.node = binary_node(OP_TIMES, mul_expr.node, arg1)] | |
239 | '/' >> unary[mul_expr.node = binary_node(OP_DIVIDE, mul_expr.node, arg1)]); | |
240 | |
241 add_expr = mul_expr[add_expr.node = arg1] | |
242 >> *('+' >> mul_expr[add_expr.node = binary_node(OP_PLUS, add_expr.node, arg1)] | |
243 | '-' >> mul_expr[add_expr.node = binary_node(OP_MINUS, add_expr.node, arg1)]); | |
244 | |
245 assign = identifier[assign.value = arg1] >> '=' | |
246 >> add_expr[assign.action = construct_<caction_t>(new_<cassign_action>(assign.value, arg1))] >> '\n'; | |
247 //print = lexeme_d[str_p("print") >> eps_p(anychar_p - (alnum_p | '_'))] >> add_expr[print.action = construct_<caction_t>(new_<cprint_action>(arg1))] >> '\n'; | |
248 //list = lexeme_d[str_p("list") >> eps_p(anychar_p - (alnum_p | '_'))][list.action = construct_<caction_t>(new_<clist_action>())] >> '\n'; | |
249 | |
250 print = keyword_p("print") >> add_expr[print.action = construct_<caction_t>(new_<cprint_action>(arg1))] >> '\n'; | |
251 list = keyword_p("list")[list.action = construct_<caction_t>(new_<clist_action>())] >> '\n'; | |
252 | |
253 statement = assign[statement.action = arg1] | |
254 | print[statement.action = arg1] | |
255 | list[statement.action = arg1] | |
256 ; | |
257 | |
258 input = *(statement[push_back_a(self.statements_)] | |
259 | '\n' | |
260 | syntax_error_p); | |
261 } | |
262 | |
263 rule<ScannerT> const& start() const | |
264 { | |
265 return input; | |
266 } | |
267 }; | |
268 } ; | |
269 | |
270 // main | |
271 | |
272 int main(int argc, char *argv[]) | |
273 { | |
274 // ファイルの読み込みに、file_iteratorを使用する | |
275 file_iterator<> first("input.txt"); | |
276 if (!first) { | |
277 cout << "ファイルがオープンできません。" << endl; | |
278 return 1; | |
279 } | |
280 file_iterator<> last = first.make_end(); | |
281 | |
282 vector<caction_t> statements; | |
283 calc_grammer gr(statements); | |
284 if (parse(first, last, gr, ch_p(' ') | ch_p('\t') | ch_p('\r')).full) { | |
285 // 解析成功した文を実行 | |
286 for_each(statements.begin(), statements.end(), boost::mem_fn(&caction::action)); | |
287 } | |
288 else { | |
289 // エラー処理が入っているので、エラー処理されるとここには来ない | |
290 // エラー処理パーサーで、エラー処理を行ったら失敗としたほうが | |
291 // 良い。 | |
292 cout << "構文解析失敗" << endl; | |
293 } | |
294 | |
295 return 0; | |
296 } |