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 }