Mercurial > hg > Members > nobuyasu > SampleSource
comparison Bison-Flex/CALC/discrete-parser/EUC/parser.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 // | |
2 // 四則演算パーサー | |
3 // | |
4 // Chihiro.SAKAMOTO | |
5 // | |
6 #include <climits> | |
7 #include <cstdio> | |
8 #include "parser.h" | |
9 | |
10 cparser::cparser() | |
11 : token_type(OP_EOF) | |
12 { | |
13 } | |
14 | |
15 cparser::~cparser() | |
16 { | |
17 } | |
18 | |
19 // 構文解析 | |
20 // | |
21 // statement ::= <value> "=" <expr> | |
22 // | "print" <expr> | |
23 // | "list" | |
24 // | |
25 bool cparser::parse(calc_driver *driver, const std::string &f) | |
26 { | |
27 if ((fp = std::fopen(f.c_str(), "r")) == NULL) | |
28 return false; | |
29 | |
30 int token; | |
31 std::string str; | |
32 while ((token = get_token(str)) != OP_EOF) { | |
33 if (token == OP_LIST) { // listコマンド | |
34 driver->list(); | |
35 } | |
36 else if (token == OP_PRINT) { // printコマンド | |
37 cnode *node = add_sub_expr(); | |
38 driver->print(node); | |
39 delete node; | |
40 } | |
41 else if (token == OP_VALUE) { // 代入 | |
42 std::string equ; | |
43 if (get_token(equ) != OP_EQU) | |
44 return false; | |
45 cnode *node = add_sub_expr(); | |
46 driver->assign(str, node); | |
47 delete node; | |
48 } | |
49 else if (token != OP_NEWLINE) { // 空行以外はエラー | |
50 return false; | |
51 } | |
52 | |
53 token = get_token(str); | |
54 if (token != OP_NEWLINE) // 行末の\nを読み捨てる | |
55 unget_token(token, str); | |
56 } | |
57 | |
58 std::fclose(fp); | |
59 | |
60 return true; | |
61 } | |
62 | |
63 // +−の処理 | |
64 // expr ::= <muldiv> (("+" | "-") <muldiv>)* | |
65 | |
66 cnode *cparser::add_sub_expr() | |
67 { | |
68 cnode *left = mul_div_expr(); | |
69 if (left == NULL) | |
70 return NULL; | |
71 | |
72 for (;;) { | |
73 std::string str; | |
74 int token = get_token(str); | |
75 if (token != OP_PLUS && token != OP_MINUS) { | |
76 unget_token(token, str); | |
77 break; | |
78 } | |
79 | |
80 cnode *right = mul_div_expr(); | |
81 if (right == NULL) { | |
82 delete left; | |
83 return NULL; | |
84 } | |
85 left = new cnode(token, left, right); | |
86 } | |
87 return left; | |
88 } | |
89 | |
90 // */の処理 | |
91 // muldiv ::= <term> (("*" | "/") <term>)* | |
92 | |
93 cnode *cparser::mul_div_expr() | |
94 { | |
95 cnode *left = term(); | |
96 if (left == NULL) | |
97 return NULL; | |
98 | |
99 for (;;) { | |
100 std::string str; | |
101 int token = get_token(str); | |
102 if (token != OP_TIMES && token != OP_DIVIDE) { | |
103 unget_token(token, str); | |
104 break; | |
105 } | |
106 | |
107 cnode *right = term(); | |
108 if (right == NULL) { | |
109 delete left; | |
110 return NULL; | |
111 } | |
112 left = new cnode(token, left, right); | |
113 } | |
114 return left; | |
115 } | |
116 | |
117 // 終端 | |
118 // term ::= "-" <term> | "(" <expr> ")" | <number> | <value> | |
119 | |
120 cnode *cparser::term() | |
121 { | |
122 std::string str; | |
123 int token = get_token(str); | |
124 | |
125 if (token == OP_MINUS) { | |
126 return new cnode(OP_NEG, term()); | |
127 } | |
128 if (token == OP_OPAR) { | |
129 cnode *node = add_sub_expr(); | |
130 if (node == NULL) | |
131 return NULL; | |
132 | |
133 token = get_token(str); | |
134 if (token != OP_CPAR) { | |
135 delete node; | |
136 unget_token(token, str); | |
137 return NULL; | |
138 } | |
139 return node; | |
140 } | |
141 if (token == OP_CONST) { | |
142 return new cnode(OP_CONST, atoi(str.c_str())); | |
143 } | |
144 if (token == OP_VALUE) { | |
145 return new cnode(OP_VALUE, new std::string(str)); | |
146 } | |
147 return NULL; | |
148 } | |
149 | |
150 // ロケール無視の文字判定 | |
151 | |
152 inline bool _isspace(int c) | |
153 { | |
154 return c == ' ' || c == '\t'; | |
155 } | |
156 | |
157 inline bool _isnum(int c) | |
158 { | |
159 return c >= '0' && c <= '9'; | |
160 } | |
161 | |
162 inline bool _isalpha(int c) | |
163 { | |
164 return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'; | |
165 } | |
166 | |
167 // 字句解析 | |
168 // | |
169 // トークン トークン種別 | |
170 // | |
171 // '+' OP_PLUS | |
172 // '-' OP_MINUS | |
173 // '*' OP_TIMES | |
174 // '/' OP_DIVIDE | |
175 // '(' OP_OPAR | |
176 // ')' OP_CPAR | |
177 // '=' OP_EQU | |
178 // '\n' OP_NEWLINE | |
179 // EOF OP_EOF | |
180 // | |
181 // "print" OP_PRINT | |
182 // "list" OP_LIST | |
183 // [0-9]+ OP_CONST | |
184 // [a-zA-Z_][a-zA-Z0-9_]* OP_VALUE | |
185 // | |
186 int cparser::_get_token(std::string &str) | |
187 { | |
188 int c; | |
189 | |
190 // 先行する空白類を読み飛ばす。 | |
191 do { | |
192 c = std::fgetc(fp); | |
193 } while (_isspace(c)) ; | |
194 | |
195 // strは再利用されているかもしれないので、クリアしておく | |
196 str.clear(); | |
197 | |
198 // 記号の場合は、1文字で1トークンなので、種別を返す。 | |
199 switch (c) { | |
200 case '+': return OP_PLUS; | |
201 case '-': return OP_MINUS; | |
202 case '*': return OP_TIMES; | |
203 case '/': return OP_DIVIDE; | |
204 case '(': return OP_OPAR; | |
205 case ')': return OP_CPAR; | |
206 case '=': return OP_EQU; | |
207 case '\n': return OP_NEWLINE; | |
208 case EOF: return OP_EOF; | |
209 } | |
210 | |
211 // 1文字目が数字の場合は、数字文字列としてトークンを切り出す。 | |
212 if (_isnum(c)) { | |
213 while (_isnum(c)) { | |
214 str += c; | |
215 c = std::fgetc(fp); | |
216 } | |
217 std::ungetc(c, fp); | |
218 return OP_CONST; | |
219 } | |
220 | |
221 // 1文字目が英字の場合は、「識別子」としてトークンを切り出す。 | |
222 if (_isalpha(c)) { | |
223 while (_isalpha(c) || _isnum(c)) { | |
224 str += c; | |
225 c = fgetc(fp); | |
226 } | |
227 std::ungetc(c, fp); | |
228 | |
229 // 切り出したトークンが「予約語」の場合は、対応したトークン種別を返す。 | |
230 if (str == "print") | |
231 return OP_PRINT; | |
232 if (str == "list") | |
233 return OP_LIST; | |
234 return OP_VALUE; | |
235 } | |
236 | |
237 // その他の文字はエラーとする。 | |
238 return OP_ERROR; | |
239 } |