Mercurial > hg > Members > nobuyasu > SampleSource
comparison boost-spirit/CALC/AST/EUC/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/core.hpp> | |
2 #include <boost/spirit/utility/confix.hpp> | |
3 #include <boost/spirit/tree/ast.hpp> | |
4 #include <boost/spirit/utility/escape_char.hpp> | |
5 #include <boost/spirit/iterator/position_iterator.hpp> | |
6 #include <boost/spirit/iterator/file_iterator.hpp> | |
7 #include <boost/spirit/utility/functor_parser.hpp> | |
8 #include <iostream> | |
9 #include <map> | |
10 #include <string> | |
11 #include <cassert> | |
12 #include <algorithm> | |
13 | |
14 using namespace std; | |
15 using namespace boost::spirit; | |
16 | |
17 // ノードのID | |
18 enum { | |
19 ID_NEG = 1, | |
20 ID_PLUS, | |
21 ID_MINUS, | |
22 ID_TIMES, | |
23 ID_DIVIDE, | |
24 ID_SUBST, | |
25 ID_VALUE, | |
26 ID_CONST, | |
27 ID_PRIME, | |
28 ID_UNARY, | |
29 ID_MUL_EXPR, | |
30 ID_ADD_EXPR, | |
31 ID_STATEMENT, | |
32 ID_INPUT, | |
33 ID_ASSIGN, | |
34 ID_PRINT, | |
35 ID_LIST, | |
36 } ; | |
37 | |
38 typedef file_iterator<> iterator_t; | |
39 typedef tree_match<iterator_t>::tree_iterator tree_iter_t; | |
40 | |
41 map<string, int> values; // 変数テーブル | |
42 | |
43 struct error_parser { | |
44 typedef nil_t result_t; // パーサーの結果型(nil_t) | |
45 | |
46 error_parser(char const *msg) | |
47 : msg_(msg) | |
48 { | |
49 } | |
50 | |
51 template <typename ScannerT> | |
52 int operator()(ScannerT const &scan, result_t &result) const | |
53 { | |
54 // 終わりまで来たら-1を返す | |
55 if (scan.at_end()) { | |
56 return -1; | |
57 } | |
58 | |
59 cout << msg_ << endl; | |
60 // 解釈した「長さ」を返すと、その分スキップするので | |
61 // 改行までをスキャンし、その分をスキップ | |
62 return (int)(*(anychar_p - '\n') >> ch_p('\n')).parse(scan).length(); | |
63 } | |
64 | |
65 private: | |
66 const char *msg_; | |
67 } ; | |
68 | |
69 typedef functor_parser<error_parser> error_p; | |
70 | |
71 // エラー処理パーサー定義 | |
72 error_p syntax_error_p = error_parser("文法エラー"); | |
73 | |
74 // 文法定義 | |
75 struct calc_grammer: public grammar<calc_grammer> { | |
76 template <typename ScannerT> | |
77 struct definition { | |
78 rule< ScannerT, parser_context<>, parser_tag<ID_VALUE> > identifier; | |
79 rule< ScannerT, parser_context<>, parser_tag<ID_CONST> > number; | |
80 rule< ScannerT, parser_context<>, parser_tag<ID_NEG> > minus; | |
81 rule< ScannerT, parser_context<>, parser_tag<ID_PLUS> > add; | |
82 rule< ScannerT, parser_context<>, parser_tag<ID_MINUS> > sub; | |
83 rule< ScannerT, parser_context<>, parser_tag<ID_TIMES> > mul; | |
84 rule< ScannerT, parser_context<>, parser_tag<ID_DIVIDE> > div; | |
85 rule< ScannerT, parser_context<>, parser_tag<ID_SUBST> > subst; | |
86 rule< ScannerT, parser_context<>, parser_tag<ID_PRIME> > prime; | |
87 rule< ScannerT, parser_context<>, parser_tag<ID_UNARY> > unary; | |
88 rule< ScannerT, parser_context<>, parser_tag<ID_MUL_EXPR> > mul_expr; | |
89 rule< ScannerT, parser_context<>, parser_tag<ID_ADD_EXPR> > add_expr; | |
90 rule< ScannerT, parser_context<>, parser_tag<ID_ASSIGN> > assign; | |
91 rule< ScannerT, parser_context<>, parser_tag<ID_PRINT> > print; | |
92 rule< ScannerT, parser_context<>, parser_tag<ID_LIST> > list; | |
93 rule< ScannerT, parser_context<>, parser_tag<ID_STATEMENT> > statement; | |
94 rule< ScannerT, parser_context<>, parser_tag<ID_INPUT> > input; | |
95 | |
96 definition(calc_grammer const& self) | |
97 { | |
98 identifier = lexeme_d[leaf_node_d[alpha_p >> *alnum_p]]; | |
99 number = uint_p; | |
100 | |
101 minus = ch_p('-'); | |
102 add = ch_p('+'); | |
103 sub = ch_p('-'); | |
104 mul = ch_p('*'); | |
105 div = ch_p('/'); | |
106 subst = ch_p('='); | |
107 | |
108 prime = identifier | |
109 | number | |
110 | inner_node_d['(' >> add_expr >> ')'] | |
111 ; | |
112 | |
113 unary = prime | |
114 | root_node_d[minus] >> prime | |
115 ; | |
116 | |
117 mul_expr = unary >> *(root_node_d[mul | div] >> unary); | |
118 | |
119 add_expr = mul_expr >> *(root_node_d[add | sub] >> mul_expr); | |
120 | |
121 assign = identifier >> root_node_d[subst] >> add_expr; | |
122 print = str_p("print") >> add_expr; | |
123 list = str_p("list"); | |
124 | |
125 statement = root_node_d[assign | print | list] >> discard_node_d[ch_p('\n')]; | |
126 | |
127 // 入力は、「文」、「空行」もしくは「エラー」 | |
128 input = *(statement | discard_node_d[ch_p('\n')] | syntax_error_p); | |
129 } | |
130 | |
131 rule< ScannerT, parser_context<>, parser_tag<ID_INPUT> > const& start() const | |
132 { | |
133 return input; | |
134 } | |
135 }; | |
136 } ; | |
137 | |
138 // ツリーのイテレータから、変数を取り出す | |
139 | |
140 int &value_ref(const tree_iter_t &it) | |
141 { | |
142 return values[string(it->value.begin(), it->value.end())]; | |
143 } | |
144 | |
145 // リストコマンドの関数オブジェクト | |
146 | |
147 struct list_action { | |
148 void operator()(const std::pair<std::string, int> &it) | |
149 { | |
150 cout << it.first << " = " << it.second << endl; | |
151 } | |
152 } ; | |
153 | |
154 int eval(const tree_iter_t &it) | |
155 { | |
156 if (it->value.id() == ID_NEG) { | |
157 assert(it->children.size() == 1); | |
158 return -eval(it->children.begin()); | |
159 } | |
160 else if (it->value.id() == ID_PLUS) { | |
161 assert(it->children.size() == 2); | |
162 return eval(it->children.begin()) + eval(it->children.begin() + 1); | |
163 } | |
164 else if (it->value.id() == ID_MINUS) { | |
165 assert(it->children.size() == 2); | |
166 return eval(it->children.begin()) - eval(it->children.begin() + 1); | |
167 } | |
168 else if (it->value.id() == ID_TIMES) { | |
169 assert(it->children.size() == 2); | |
170 return eval(it->children.begin()) * eval(it->children.begin() + 1); | |
171 } | |
172 else if (it->value.id() == ID_DIVIDE) { | |
173 assert(it->children.size() == 2); | |
174 return eval(it->children.begin()) / eval(it->children.begin() + 1); | |
175 } | |
176 else if (it->value.id() == ID_SUBST) { | |
177 assert(it->children.size() == 2); | |
178 return value_ref(it->children.begin()) = eval(it->children.begin() + 1); | |
179 } | |
180 else if (it->value.id() == ID_VALUE) { | |
181 return values[string(it->value.begin(), it->value.end())]; | |
182 } | |
183 else if (it->value.id() == ID_CONST) { | |
184 return atoi(string(it->value.begin(), it->value.end()).c_str()); | |
185 } | |
186 else if (it->value.id() == ID_PRINT) { | |
187 cout << eval(it->children.begin() + 1) << endl; | |
188 } | |
189 else if (it->value.id() == ID_LIST) { | |
190 for_each(values.begin(), values.end(), list_action()); | |
191 } | |
192 else { | |
193 cout << "エラー" << endl; | |
194 } | |
195 return 0; | |
196 } | |
197 | |
198 // main | |
199 | |
200 int main(int argc, char *argv[]) | |
201 { | |
202 // ファイルの読み込みに、file_iteratorを使用する | |
203 file_iterator<> first("input.txt"); | |
204 if (!first) { | |
205 cout << "ファイルがオープンできません。" << endl; | |
206 return 1; | |
207 } | |
208 file_iterator<> last = first.make_end(); | |
209 | |
210 // 抽象構文木作成 | |
211 calc_grammer gr; | |
212 tree_parse_info<iterator_t> info; // 解析情報を保持する変数 | |
213 info = ast_parse(first, last, gr, ch_p(' ') | ch_p('\t') | ch_p('\r')); | |
214 | |
215 if (info.full) { | |
216 const tree_iter_t &root = info.trees.begin(); | |
217 size_t size = root->children.size(); | |
218 for(size_t i=0; i<size; i++) { | |
219 eval(root->children.begin() + i); | |
220 } | |
221 } | |
222 else { | |
223 // エラー処理が入っているので、エラー処理されるとここには来ない | |
224 // エラー処理パーサーで、エラー処理を行ったら失敗としたほうが | |
225 // 良い。 | |
226 cout << "構文解析失敗" << endl; | |
227 } | |
228 | |
229 return 0; | |
230 } |