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 }