# | Line 6 | Line 6 | |
---|---|---|
6 | * redistribute this software in source and binary code form, provided | |
7 | * that the following conditions are met: | |
8 | * | |
9 | < | * 1. Acknowledgement of the program authors must be made in any |
10 | < | * publication of scientific results based in part on use of the |
11 | < | * program. An acceptable form of acknowledgement is citation of |
12 | < | * the article in which the program was described (Matthew |
13 | < | * A. Meineke, Charles F. Vardeman II, Teng Lin, Christopher |
14 | < | * J. Fennell and J. Daniel Gezelter, "OOPSE: An Object-Oriented |
15 | < | * Parallel Simulation Engine for Molecular Dynamics," |
16 | < | * J. Comput. Chem. 26, pp. 252-271 (2005)) |
17 | < | * |
18 | < | * 2. Redistributions of source code must retain the above copyright |
9 | > | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * | |
12 | < | * 3. Redistributions in binary form must reproduce the above copyright |
12 | > | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the | |
15 | * distribution. | |
# | Line 37 | Line 28 | |
28 | * arising out of the use of or inability to use software, even if the | |
29 | * University of Notre Dame has been advised of the possibility of | |
30 | * such damages. | |
31 | + | * |
32 | + | * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your |
33 | + | * research, please cite the appropriate papers when you publish your |
34 | + | * work. Good starting points are: |
35 | + | * |
36 | + | * [1] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005). |
37 | + | * [2] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006). |
38 | + | * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 24107 (2008). |
39 | + | * [4] Vardeman & Gezelter, in progress (2009). |
40 | */ | |
41 | ||
42 | #include "selection/SelectionCompiler.hpp" | |
43 | < | namespace oopse { |
43 | > | #include "utils/StringUtils.hpp" |
44 | > | namespace OpenMD { |
45 | ||
46 | < | bool SelectionCompiler::compile(const std::string& filename, const std::string& script) { |
46 | > | bool SelectionCompiler::compile(const std::string& filename, |
47 | > | const std::string& script) { |
48 | ||
49 | this->filename = filename; | |
50 | this->script = script; | |
# | Line 50 | Line 52 | bool SelectionCompiler::compile(const std::string& fil | |
52 | lineIndices.clear(); | |
53 | aatokenCompiled.clear(); | |
54 | ||
55 | < | if (internalcompile()) { |
56 | < | return true; |
55 | > | if (internalCompile()) { |
56 | > | return true; |
57 | } | |
58 | ||
59 | int icharEnd; | |
60 | < | if ((icharEnd = script.find('\r', ichCurrentCommand)) == std::string:npos && |
61 | < | (icharEnd = script.find('\n', ichCurrentCommand)) == std::string:npos) { |
62 | < | icharEnd = script.size(); |
60 | > | if ((icharEnd = script.find('\r', ichCurrentCommand)) == std::string::npos && |
61 | > | (icharEnd = script.find('\n', ichCurrentCommand)) == std::string::npos) { |
62 | > | icharEnd = script.size(); |
63 | } | |
64 | errorLine = script.substr(ichCurrentCommand, icharEnd); | |
65 | return false; | |
66 | < | } |
66 | > | } |
67 | ||
68 | < | bool SelectionCompiler::internalCompile(){ |
68 | > | bool SelectionCompiler::internalCompile(){ |
69 | ||
70 | cchScript = script.size(); | |
71 | ichToken = 0; | |
# | Line 71 | Line 73 | bool SelectionCompiler::internalCompile(){ | |
73 | ||
74 | error = false; | |
75 | ||
76 | < | std::vector<Token> lltoken; |
76 | > | //std::vector<Token> lltoken; |
77 | > | aatokenCompiled.clear(); |
78 | std::vector<Token> ltoken; | |
79 | ||
80 | < | //Token tokenCommand = null; |
81 | < | int tokCommand = Token.nada; |
80 | > | Token tokenCommand; |
81 | > | int tokCommand = Token::nada; |
82 | ||
83 | for ( ; true; ichToken += cchToken) { | |
84 | < | if (lookingAtLeadingWhitespace()) |
85 | < | continue; |
86 | < | if (lookingAtComment()) |
87 | < | continue; |
88 | < | boolean endOfLine = lookingAtEndOfLine(); |
89 | < | if (endOfLine || lookingAtEndOfStatement()) { |
90 | < | if (tokCommand != Token.nada) { |
91 | < | if (! compileCommand(ltoken)) { |
92 | < | return false; |
93 | < | } |
94 | < | lltoken.push_back(atokenCommand); |
95 | < | /** @todo*/ |
96 | < | int iCommand = lltoken.size(); |
97 | < | lineNumbers[iCommand] = lineCurrent; |
98 | < | lineIndices[iCommand] = (short) ichCurrentCommand; |
99 | < | ltoken.clear(); |
97 | < | tokCommand = Token.nada; |
98 | < | } |
84 | > | if (lookingAtLeadingWhitespace()) |
85 | > | continue; |
86 | > | //if (lookingAtComment()) |
87 | > | // continue; |
88 | > | bool endOfLine = lookingAtEndOfLine(); |
89 | > | if (endOfLine || lookingAtEndOfStatement()) { |
90 | > | if (tokCommand != Token::nada) { |
91 | > | if (! compileCommand(ltoken)) { |
92 | > | return false; |
93 | > | } |
94 | > | aatokenCompiled.push_back(atokenCommand); |
95 | > | lineNumbers.push_back(lineCurrent); |
96 | > | lineIndices.push_back(ichCurrentCommand); |
97 | > | ltoken.clear(); |
98 | > | tokCommand = Token::nada; |
99 | > | } |
100 | ||
101 | < | if (ichToken < cchScript) { |
102 | < | if (endOfLine) |
103 | < | ++lineCurrent; |
104 | < | continue; |
105 | < | } |
106 | < | break; |
107 | < | } |
101 | > | if (ichToken < cchScript) { |
102 | > | if (endOfLine) |
103 | > | ++lineCurrent; |
104 | > | continue; |
105 | > | } |
106 | > | break; |
107 | > | } |
108 | ||
109 | < | if (tokCommand != Token.nada) { |
110 | < | if (lookingAtString()) { |
111 | < | std::string str = getUnescapedStringLiteral(); |
112 | < | ltoken.push_back(Token(Token.string, str)); |
113 | < | continue; |
114 | < | } |
115 | < | if ((tokCommand & Token.specialstring) != 0 && |
116 | < | lookingAtSpecialString()) { |
117 | < | std::string str = script.substr(ichToken, ichToken + cchToken); |
118 | < | ltoken.push_back(Token(Token.string, str)); |
119 | < | continue; |
120 | < | } |
121 | < | if (lookingAtDecimal((tokCommand & Token.negnums) != 0)) { |
122 | < | float value = lexi_cast<float>((script.substr(ichToken, ichToken + cchToken)); |
123 | < | ltoken.push_back(Token(Token.decimal, new Float(value)));/**@todo*/ |
124 | < | continue; |
125 | < | } |
126 | < | if (lookingAtInteger((tokCommand & Token.negnums) != 0)) { |
126 | < | std::string intString = script.substr(ichToken, ichToken + cchToken); |
127 | < | int val = lexi_cast<int>(intString); |
128 | < | ltoken.push_back(new Token(Token.integer, val, intString));/**@todo*/ |
129 | < | continue; |
130 | < | } |
131 | < | } |
132 | < | |
133 | < | if (lookingAtLookupToken()) { |
134 | < | std::string ident = script.subst(ichToken, ichToken + cchToken); |
135 | < | |
136 | < | /**@todo */ |
137 | < | Token token = (Token) Token.map.get(ident); |
138 | < | if (token == NULL) { |
139 | < | |
140 | < | } |
141 | < | Token token(Token.identifier, ident); |
109 | > | if (tokCommand != Token::nada) { |
110 | > | if (lookingAtString()) { |
111 | > | std::string str = getUnescapedStringLiteral(); |
112 | > | ltoken.push_back(Token(Token::string, str)); |
113 | > | continue; |
114 | > | } |
115 | > | //if ((tokCommand & Token::specialstring) != 0 && |
116 | > | // lookingAtSpecialString()) { |
117 | > | // std::string str = script.substr(ichToken, ichToken + cchToken); |
118 | > | // ltoken.push_back(Token(Token::string, str)); |
119 | > | // continue; |
120 | > | //} |
121 | > | if (lookingAtDecimal((tokCommand & Token::negnums) != 0)) { |
122 | > | float value = lexi_cast<float>(script.substr(ichToken, cchToken)); |
123 | > | ltoken.push_back(Token(Token::decimal, boost::any(value))); |
124 | > | continue; |
125 | > | } |
126 | > | if (lookingAtInteger((tokCommand & Token::negnums) != 0)) { |
127 | ||
128 | + | int val = lexi_cast<int>(script.substr(ichToken, cchToken)); |
129 | + | ltoken.push_back(Token(Token::integer, boost::any(val))); |
130 | + | continue; |
131 | + | } |
132 | + | } |
133 | + | |
134 | + | if (lookingAtLookupToken()) { |
135 | + | std::string ident = script.substr(ichToken, cchToken); |
136 | + | Token token; |
137 | + | Token* pToken = TokenMap::getInstance()->getToken(ident); |
138 | + | if (pToken != NULL) { |
139 | + | token = *pToken; |
140 | + | } else { |
141 | + | token = Token(Token::identifier, ident); |
142 | + | } |
143 | ||
144 | < | int tok = token.tok; |
144 | > | int tok = token.tok; |
145 | ||
146 | < | switch (tokCommand) { |
147 | < | case Token.nada: |
148 | < | ichCurrentCommand = ichToken; |
149 | < | //tokenCommand = token; |
150 | < | tokCommand = tok; |
151 | < | if ((tokCommand & Token.command) == 0) |
152 | < | return commandExpected(); |
153 | < | break; |
146 | > | switch (tokCommand) { |
147 | > | case Token::nada: |
148 | > | ichCurrentCommand = ichToken; |
149 | > | //tokenCommand = token; |
150 | > | tokCommand = tok; |
151 | > | if ((tokCommand & Token::command) == 0) |
152 | > | return commandExpected(); |
153 | > | break; |
154 | ||
155 | < | case Token.define: |
156 | < | if (ltoken.size() == 1) { |
157 | < | // we are looking at the variable name |
158 | < | if (tok != Token.identifier && |
159 | < | (tok & Token.predefinedset) != Token.predefinedset) |
160 | < | return invalidExpressionToken(ident); |
161 | < | } else { |
162 | < | // we are looking at the expression |
163 | < | if (tok != Token.identifier && tok != Token.set && |
164 | < | (tok & (Token.expression | Token.predefinedset)) == 0) |
165 | < | return invalidExpressionToken(ident); |
166 | < | } |
155 | > | case Token::define: |
156 | > | if (ltoken.size() == 1) { |
157 | > | // we are looking at the variable name |
158 | > | if (tok != Token::identifier && |
159 | > | (tok & Token::predefinedset) != Token::predefinedset) |
160 | > | return invalidExpressionToken(ident); |
161 | > | } else { |
162 | > | // we are looking at the expression |
163 | > | if (tok != Token::identifier && |
164 | > | (tok & (Token::expression | Token::predefinedset)) == 0) |
165 | > | return invalidExpressionToken(ident); |
166 | > | } |
167 | ||
168 | < | break; |
168 | > | break; |
169 | ||
170 | < | case Token.select: |
171 | < | if (tok != Token.identifier && (tok & Token.expression) == 0) |
172 | < | return invalidExpressionToken(ident); |
173 | < | break; |
174 | < | } |
175 | < | ltoken.push_back(token); |
176 | < | continue; |
177 | < | } |
170 | > | case Token::select: |
171 | > | if (tok != Token::identifier && (tok & Token::expression) == 0) |
172 | > | return invalidExpressionToken(ident); |
173 | > | break; |
174 | > | } |
175 | > | ltoken.push_back(token); |
176 | > | continue; |
177 | > | } |
178 | ||
179 | < | if (ltoken.size() == 0) { |
180 | < | return commandExpected(); |
181 | < | } |
179 | > | if (ltoken.size() == 0) { |
180 | > | return commandExpected(); |
181 | > | } |
182 | ||
183 | < | return unrecognizedToken(); |
183 | > | return unrecognizedToken(); |
184 | } | |
185 | ||
186 | – | aatokenCompiled.push_back(lltoken); |
186 | return true; | |
187 | } | |
188 | ||
# | Line 206 | Line 205 | bool SelectionCompiler::internalCompile(){ | |
205 | if (ch == '\r') { | |
206 | ++ichT; | |
207 | if (ichT < cchScript && script[ichT] == '\n') | |
208 | < | ++ichT; |
208 | > | ++ichT; |
209 | } else if (ch == '\n') { | |
210 | ++ichT; | |
211 | } else { | |
# | Line 236 | Line 235 | bool SelectionCompiler::internalCompile(){ | |
235 | int ichT = ichToken + 1; | |
236 | // while (ichT < cchScript && script.charAt(ichT++) != chFirst) | |
237 | char ch; | |
238 | < | boolean previousCharBackslash = false; |
238 | > | bool previousCharBackslash = false; |
239 | while (ichT < cchScript) { | |
240 | < | ch = script.[ichT++]; |
240 | > | ch = script[ichT++]; |
241 | if (ch == '"' && !previousCharBackslash) | |
242 | break; | |
243 | previousCharBackslash = ch == '\\' ? !previousCharBackslash : false; | |
244 | } | |
245 | cchToken = ichT - ichToken; | |
246 | + | |
247 | return true; | |
248 | } | |
249 | ||
250 | ||
251 | < | std::string SelectionCompiler::getUnescapedStringLiteral() { |
252 | < | StringBuffer sb = new StringBuffer(cchToken - 2); |
251 | > | std::string SelectionCompiler::getUnescapedStringLiteral() { |
252 | > | /** @todo */ |
253 | > | std::string sb(cchToken - 2, ' '); |
254 | > | |
255 | int ichMax = ichToken + cchToken - 1; | |
256 | int ich = ichToken + 1; | |
257 | ||
258 | while (ich < ichMax) { | |
259 | < | char ch = script[ich++]; |
260 | < | if (ch == '\\' && ich < ichMax) { |
261 | < | ch = script[ich++]; |
262 | < | switch (ch) { |
263 | < | case 'b': |
264 | < | ch = '\b'; |
265 | < | break; |
266 | < | case 'n': |
267 | < | ch = '\n'; |
268 | < | break; |
269 | < | case 't': |
270 | < | ch = '\t'; |
271 | < | break; |
272 | < | case 'r': |
273 | < | ch = '\r'; |
274 | < | // fall into |
275 | < | case '"': |
276 | < | case '\\': |
277 | < | case '\'': |
278 | < | break; |
279 | < | case 'x': |
280 | < | case 'u': |
281 | < | int digitCount = ch == 'x' ? 2 : 4; |
282 | < | if (ich < ichMax) { |
283 | < | int unicode = 0; |
284 | < | for (int k = digitCount; --k >= 0 && ich < ichMax; ) { |
285 | < | char chT = script[ich]; |
286 | < | int hexit = getHexitValue(chT); |
287 | < | if (hexit < 0) |
288 | < | break; |
289 | < | unicode <<= 4; |
290 | < | unicode += hexit; |
291 | < | ++ich; |
292 | < | } |
293 | < | ch = (char)unicode; |
294 | < | } |
295 | < | } |
296 | < | } |
297 | < | sb.append(ch); |
259 | > | char ch = script[ich++]; |
260 | > | if (ch == '\\' && ich < ichMax) { |
261 | > | ch = script[ich++]; |
262 | > | switch (ch) { |
263 | > | case 'b': |
264 | > | ch = '\b'; |
265 | > | break; |
266 | > | case 'n': |
267 | > | ch = '\n'; |
268 | > | break; |
269 | > | case 't': |
270 | > | ch = '\t'; |
271 | > | break; |
272 | > | case 'r': |
273 | > | ch = '\r'; |
274 | > | // fall into |
275 | > | case '"': |
276 | > | case '\\': |
277 | > | case '\'': |
278 | > | break; |
279 | > | case 'x': |
280 | > | case 'u': |
281 | > | int digitCount = ch == 'x' ? 2 : 4; |
282 | > | if (ich < ichMax) { |
283 | > | int unicode = 0; |
284 | > | for (int k = digitCount; --k >= 0 && ich < ichMax; ) { |
285 | > | char chT = script[ich]; |
286 | > | int hexit = getHexitValue(chT); |
287 | > | if (hexit < 0) |
288 | > | break; |
289 | > | unicode <<= 4; |
290 | > | unicode += hexit; |
291 | > | ++ich; |
292 | > | } |
293 | > | ch = (char)unicode; |
294 | > | } |
295 | > | } |
296 | > | } |
297 | > | sb.append(1, ch); |
298 | } | |
299 | ||
300 | < | return "" + sb; |
301 | < | } |
300 | > | return sb; |
301 | > | } |
302 | ||
303 | < | static int SelectionCompiler::getHexitValue(char ch) { |
303 | > | int SelectionCompiler::getHexitValue(char ch) { |
304 | if (ch >= '0' && ch <= '9') | |
305 | < | return ch - '0'; |
305 | > | return ch - '0'; |
306 | else if (ch >= 'a' && ch <= 'f') | |
307 | < | return 10 + ch - 'a'; |
307 | > | return 10 + ch - 'a'; |
308 | else if (ch >= 'A' && ch <= 'F') | |
309 | < | return 10 + ch - 'A'; |
309 | > | return 10 + ch - 'A'; |
310 | else | |
311 | < | return -1; |
312 | < | } |
311 | > | return -1; |
312 | > | } |
313 | ||
314 | < | bool SelectionCompiler::lookingAtSpecialString() { |
314 | > | bool SelectionCompiler::lookingAtSpecialString() { |
315 | int ichT = ichToken; | |
316 | char ch = script[ichT]; | |
317 | while (ichT < cchScript && ch != ';' && ch != '\r' && ch != '\n') { | |
318 | < | ++ichT; |
318 | > | ++ichT; |
319 | } | |
320 | cchToken = ichT - ichToken; | |
321 | return cchToken > 0; | |
322 | < | } |
322 | > | } |
323 | ||
324 | < | bool SelectionCompiler::lookingAtDecimal(boolean allowNegative) { |
324 | > | bool SelectionCompiler::lookingAtDecimal(bool allowNegative) { |
325 | if (ichToken == cchScript) { | |
326 | < | return false; |
326 | > | return false; |
327 | } | |
328 | ||
329 | int ichT = ichToken; | |
330 | if (script[ichT] == '-') { | |
331 | < | ++ichT; |
331 | > | ++ichT; |
332 | } | |
333 | < | boolean digitSeen = false; |
333 | > | bool digitSeen = false; |
334 | char ch = 'X'; | |
335 | while (ichT < cchScript && std::isdigit(ch = script[ichT])) { | |
336 | < | ++ichT; |
337 | < | digitSeen = true; |
336 | > | ++ichT; |
337 | > | digitSeen = true; |
338 | } | |
339 | ||
340 | if (ichT == cchScript || ch != '.') { | |
341 | < | return false; |
341 | > | return false; |
342 | } | |
343 | ||
344 | < | // to support 1.ca, let's check the character after the dot |
345 | < | // to determine if it is an alpha |
346 | < | if (ch == '.' && (ichT + 1 < cchScript) && std::isalpha(script[ichT + 1])) { |
345 | < | return false; |
344 | > | // to support DMPC.1, let's check the character before the dot |
345 | > | if (ch == '.' && (ichT > 0) && std::isalpha(script[ichT - 1])) { |
346 | > | return false; |
347 | } | |
348 | ||
349 | ++ichT; | |
350 | while (ichT < cchScript && std::isdigit(script[ichT])) { | |
351 | < | ++ichT; |
352 | < | digitSeen = true; |
351 | > | ++ichT; |
352 | > | digitSeen = true; |
353 | } | |
354 | cchToken = ichT - ichToken; | |
355 | return digitSeen; | |
356 | < | } |
356 | > | } |
357 | ||
358 | < | bool SelectionCompiler::lookingAtInteger(boolean allowNegative) { |
358 | > | bool SelectionCompiler::lookingAtInteger(bool allowNegative) { |
359 | if (ichToken == cchScript) { | |
360 | < | return false; |
360 | > | return false; |
361 | } | |
362 | int ichT = ichToken; | |
363 | if (allowNegative && script[ichToken] == '-') { | |
364 | < | ++ichT; |
364 | > | ++ichT; |
365 | } | |
366 | int ichBeginDigits = ichT; | |
367 | while (ichT < cchScript && std::isdigit(script[ichT])) { | |
368 | < | ++ichT; |
368 | > | ++ichT; |
369 | } | |
370 | if (ichBeginDigits == ichT) { | |
371 | < | return false; |
371 | > | return false; |
372 | } | |
373 | cchToken = ichT - ichToken; | |
374 | return true; | |
375 | < | } |
375 | > | } |
376 | ||
377 | < | bool SelectionCompiler::lookingAtLookupToken() { |
377 | > | bool SelectionCompiler::lookingAtLookupToken() { |
378 | if (ichToken == cchScript) { | |
379 | < | return false; |
379 | > | return false; |
380 | } | |
381 | ||
382 | int ichT = ichToken; | |
383 | char ch; | |
384 | switch (ch = script[ichT++]) { | |
385 | < | case '(': |
386 | < | case ')': |
387 | < | case ',': |
388 | < | case '*': |
389 | < | case '-': |
390 | < | case '[': |
391 | < | case ']': |
392 | < | case '+': |
393 | < | case ':': |
394 | < | case '@': |
395 | < | case '.': |
396 | < | case '%': |
397 | < | break; |
398 | < | case '&': |
399 | < | case '|': |
400 | < | if (ichT < cchScript && script[ichT] == ch) { |
401 | < | ++ichT; |
402 | < | } |
403 | < | break; |
404 | < | case '<': |
405 | < | case '=': |
406 | < | case '>': |
407 | < | if (ichT < cchScript && ((ch = script[ichT]) == '<' || ch == '=' || ch == '>')) { |
408 | < | ++ichT; |
409 | < | } |
410 | < | break; |
411 | < | case '/': |
412 | < | case '!': |
413 | < | if (ichT < cchScript && script[ichT] == '=') { |
414 | < | ++ichT; |
415 | < | } |
416 | < | break; |
417 | < | default: |
418 | < | if ((ch < 'a' || ch > 'z') && (ch < 'A' && ch > 'Z') && ch != '_') { |
419 | < | return false; |
420 | < | } |
421 | < | case '?': // include question marks in identifier for atom expressions |
421 | < | while (ichT < cchScript && (std::isalpha(ch = script[ichT]) ||std::isdigit(ch) || |
422 | < | ch == '_' || ch == '?') ||(ch == '^' && ichT > ichToken && std::isdigit(script[ichT - 1]))) { |
423 | < | // hack for insertion codes embedded in an atom expression :-( |
424 | < | // select c3^a |
425 | < | ++ichT; |
426 | < | } |
427 | < | break; |
385 | > | case '(': |
386 | > | case ')': |
387 | > | case ',': |
388 | > | case '[': |
389 | > | case ']': |
390 | > | break; |
391 | > | case '&': |
392 | > | case '|': |
393 | > | if (ichT < cchScript && script[ichT] == ch) { |
394 | > | ++ichT; |
395 | > | } |
396 | > | break; |
397 | > | case '<': |
398 | > | case '=': |
399 | > | case '>': |
400 | > | if (ichT < cchScript && ((ch = script[ichT]) == '<' || ch == '=' || ch == '>')) { |
401 | > | ++ichT; |
402 | > | } |
403 | > | break; |
404 | > | case '/': |
405 | > | case '!': |
406 | > | if (ichT < cchScript && script[ichT] == '=') { |
407 | > | ++ichT; |
408 | > | } |
409 | > | break; |
410 | > | default: |
411 | > | if ((ch < 'a' || ch > 'z') && (ch < 'A' && ch > 'Z') && ch != '_') { |
412 | > | return false; |
413 | > | } |
414 | > | case '*': |
415 | > | case '?': // include question marks in identifier for atom expressions |
416 | > | while (ichT < cchScript && !std::isspace(ch = script[ichT]) && |
417 | > | (std::isalpha(ch) ||std::isdigit(ch) || ch == '_' || ch == '.' || ch == '*' || ch == '?' || ch == '+' || ch == '-' || ch == '[' || ch == ']') ){ |
418 | > | |
419 | > | ++ichT; |
420 | > | } |
421 | > | break; |
422 | } | |
423 | + | |
424 | cchToken = ichT - ichToken; | |
425 | + | |
426 | return true; | |
427 | < | } |
427 | > | } |
428 | ||
429 | < | bool SelectionCompiler::compileCommand(Vector ltoken) { |
430 | < | /** todo */ |
435 | < | Token tokenCommand = (Token)ltoken.firstElement(); |
429 | > | bool SelectionCompiler::compileCommand(const std::vector<Token>& ltoken) { |
430 | > | const Token& tokenCommand = ltoken[0]; |
431 | int tokCommand = tokenCommand.tok; | |
432 | < | |
433 | < | atokenCommand = new Token[ltoken.size()]; |
434 | < | ltoken.copyInto(atokenCommand); |
435 | < | if ((tokCommand & Token.expressionCommand) != 0 && !compileExpression()) { |
441 | < | return false; |
432 | > | |
433 | > | atokenCommand = ltoken; |
434 | > | if ((tokCommand & Token::expressionCommand) != 0 && !compileExpression()) { |
435 | > | return false; |
436 | } | |
437 | + | |
438 | return true; | |
439 | < | } |
439 | > | } |
440 | ||
441 | < | bool SelectionCompiler::compileExpression() { |
441 | > | bool SelectionCompiler::compileExpression() { |
442 | /** todo */ | |
443 | int i = 1; | |
444 | int tokCommand = atokenCommand[0].tok; | |
445 | < | if (tokCommand == Token.define) |
445 | > | if (tokCommand == Token::define) { |
446 | i = 2; | |
447 | < | else if ((tokCommand & Token.embeddedExpression) != 0) { |
447 | > | } else if ((tokCommand & Token::embeddedExpression) != 0) { |
448 | // look for the open parenthesis | |
449 | < | while (i < atokenCommand.length && |
450 | < | atokenCommand[i].tok != Token.leftparen) |
449 | > | while (i < atokenCommand.size() && |
450 | > | atokenCommand[i].tok != Token::leftparen) |
451 | ++i; | |
452 | } | |
453 | < | if (i >= atokenCommand.length) |
453 | > | |
454 | > | if (i >= atokenCommand.size()) { |
455 | return true; | |
456 | + | } |
457 | return compileExpression(i); | |
458 | } | |
459 | ||
460 | ||
461 | < | bool SelectionCompiler::addTokenToPostfix(Token token) { |
461 | > | bool SelectionCompiler::addTokenToPostfix(const Token& token) { |
462 | ltokenPostfix.push_back(token); | |
463 | return true; | |
464 | < | } |
464 | > | } |
465 | ||
466 | < | bool SelectionCompiler::compileExpression(int itoken) { |
467 | < | ltokenPostfix = new Vector(); |
468 | < | for (int i = 0; i < itoken; ++i) |
469 | < | addTokenToPostfix(atokenCommand[i]); |
470 | < | |
466 | > | bool SelectionCompiler::compileExpression(int itoken) { |
467 | > | ltokenPostfix.clear(); |
468 | > | for (int i = 0; i < itoken; ++i) { |
469 | > | addTokenToPostfix(atokenCommand[i]); |
470 | > | } |
471 | > | |
472 | atokenInfix = atokenCommand; | |
473 | itokenInfix = itoken; | |
474 | ||
475 | < | addTokenToPostfix(Token.tokenExpressionBegin); |
475 | > | addTokenToPostfix(Token::tokenExpressionBegin); |
476 | if (!clauseOr()) { | |
477 | < | return false; |
477 | > | return false; |
478 | } | |
479 | ||
480 | < | addTokenToPostfix(Token.tokenExpressionEnd); |
481 | < | if (itokenInfix != atokenInfix.length) { |
482 | < | return endOfExpressionExpected(); |
480 | > | addTokenToPostfix(Token::tokenExpressionEnd); |
481 | > | if (itokenInfix != atokenInfix.size()) { |
482 | > | return endOfExpressionExpected(); |
483 | } | |
484 | ||
485 | atokenCommand = ltokenPostfix; | |
486 | return true; | |
487 | < | } |
487 | > | } |
488 | ||
489 | < | Token SelectionCompiler::tokenNext() { |
490 | < | if (itokenInfix == atokenInfix.length) |
491 | < | return null; |
492 | < | return atokenInfix[itokenInfix++]; |
493 | < | } |
489 | > | Token SelectionCompiler::tokenNext() { |
490 | > | if (itokenInfix == atokenInfix.size()) { |
491 | > | return Token(); |
492 | > | } |
493 | > | return atokenInfix[itokenInfix++]; |
494 | > | } |
495 | ||
496 | < | Object SelectionCompiler::valuePeek() { |
497 | < | if (itokenInfix == atokenInfix.length) { |
498 | < | return null; |
496 | > | boost::any SelectionCompiler::valuePeek() { |
497 | > | if (itokenInfix == atokenInfix.size()) { |
498 | > | return boost::any(); |
499 | } else { | |
500 | < | return atokenInfix[itokenInfix].value; |
500 | > | return atokenInfix[itokenInfix].value; |
501 | } | |
502 | < | } |
502 | > | } |
503 | ||
504 | < | int SelectionCompiler::tokPeek() { |
505 | < | if (itokenInfix == atokenInfix.length) { |
506 | < | return 0; |
504 | > | int SelectionCompiler::tokPeek() { |
505 | > | if (itokenInfix == atokenInfix.size()) { |
506 | > | return 0; |
507 | }else { | |
508 | < | return atokenInfix[itokenInfix].tok; |
508 | > | return atokenInfix[itokenInfix].tok; |
509 | } | |
510 | < | } |
510 | > | } |
511 | ||
512 | < | bool SelectionCompiler::clauseOr() { |
512 | > | bool SelectionCompiler::clauseOr() { |
513 | if (!clauseAnd()) { | |
514 | < | return false; |
514 | > | return false; |
515 | } | |
516 | ||
517 | < | while (tokPeek() == Token.opOr) { |
518 | < | Token tokenOr = tokenNext(); |
519 | < | if (!clauseAnd()) { |
520 | < | return false; |
521 | < | } |
522 | < | addTokenToPostfix(tokenOr); |
517 | > | while (tokPeek() == Token::opOr) { |
518 | > | Token tokenOr = tokenNext(); |
519 | > | if (!clauseAnd()) { |
520 | > | return false; |
521 | > | } |
522 | > | addTokenToPostfix(tokenOr); |
523 | } | |
524 | return true; | |
525 | < | } |
525 | > | } |
526 | ||
527 | < | bool SelectionCompiler::clauseAnd() { |
527 | > | bool SelectionCompiler::clauseAnd() { |
528 | if (!clauseNot()) { | |
529 | < | return false; |
529 | > | return false; |
530 | } | |
531 | ||
532 | < | while (tokPeek() == Token.opAnd) { |
533 | < | Token tokenAnd = tokenNext(); |
534 | < | if (!clauseNot()) { |
535 | < | return false; |
536 | < | } |
537 | < | addTokenToPostfix(tokenAnd); |
532 | > | while (tokPeek() == Token::opAnd) { |
533 | > | Token tokenAnd = tokenNext(); |
534 | > | if (!clauseNot()) { |
535 | > | return false; |
536 | > | } |
537 | > | addTokenToPostfix(tokenAnd); |
538 | } | |
539 | return true; | |
540 | < | } |
540 | > | } |
541 | ||
542 | < | bool SelectionCompiler::clauseNot() { |
543 | < | if (tokPeek() == Token.opNot) { |
544 | < | Token tokenNot = tokenNext(); |
545 | < | if (!clauseNot()) { |
546 | < | return false; |
547 | < | } |
548 | < | return addTokenToPostfix(tokenNot); |
542 | > | bool SelectionCompiler::clauseNot() { |
543 | > | if (tokPeek() == Token::opNot) { |
544 | > | Token tokenNot = tokenNext(); |
545 | > | if (!clauseNot()) { |
546 | > | return false; |
547 | > | } |
548 | > | return addTokenToPostfix(tokenNot); |
549 | } | |
550 | return clausePrimitive(); | |
551 | < | } |
551 | > | } |
552 | ||
553 | < | bool SelectionCompiler::clausePrimitive() { |
553 | > | bool SelectionCompiler::clausePrimitive() { |
554 | int tok = tokPeek(); | |
555 | switch (tok) { | |
556 | < | case Token.within: |
557 | < | return clauseWithin(); |
559 | < | case Token.hyphen: // selecting a negative residue spec |
560 | < | case Token.integer: |
561 | < | case Token.seqcode: |
562 | < | case Token.asterisk: |
563 | < | case Token.leftsquare: |
564 | < | case Token.identifier: |
565 | < | case Token.x: |
566 | < | case Token.y: |
567 | < | case Token.z: |
568 | < | case Token.colon: |
569 | < | return clauseResidueSpec(); |
570 | < | default: |
571 | < | if ((tok & Token.atomproperty) == Token.atomproperty) { |
572 | < | return clauseComparator(); |
573 | < | } |
574 | < | if ((tok & Token.predefinedset) != Token.predefinedset) { |
575 | < | break; |
576 | < | } |
577 | < | // fall into the code and below and just add the token |
578 | < | case Token.all: |
579 | < | case Token.none: |
580 | < | return addTokenToPostfix(tokenNext()); |
581 | < | case Token.leftparen: |
582 | < | tokenNext(); |
583 | < | if (!clauseOr()) { |
584 | < | return false; |
585 | < | } |
586 | < | if (tokenNext().tok != Token.rightparen) { |
587 | < | return rightParenthesisExpected(); |
588 | < | } |
589 | < | return true; |
590 | < | } |
591 | < | return unrecognizedExpressionToken(); |
592 | < | } |
556 | > | case Token::within: |
557 | > | return clauseWithin(); |
558 | ||
559 | < | bool SelectionCompiler::clauseComparator() { |
559 | > | case Token::asterisk: |
560 | > | case Token::identifier: |
561 | > | return clauseChemObjName(); |
562 | > | |
563 | > | case Token::integer : |
564 | > | return clauseIndex(); |
565 | > | default: |
566 | > | if ((tok & Token::atomproperty) == Token::atomproperty) { |
567 | > | return clauseComparator(); |
568 | > | } |
569 | > | if ((tok & Token::predefinedset) != Token::predefinedset) { |
570 | > | break; |
571 | > | } |
572 | > | // fall into the code and below and just add the token |
573 | > | case Token::all: |
574 | > | case Token::none: |
575 | > | return addTokenToPostfix(tokenNext()); |
576 | > | case Token::leftparen: |
577 | > | tokenNext(); |
578 | > | if (!clauseOr()) { |
579 | > | return false; |
580 | > | } |
581 | > | if (tokenNext().tok != Token::rightparen) { |
582 | > | return rightParenthesisExpected(); |
583 | > | } |
584 | > | return true; |
585 | > | } |
586 | > | return unrecognizedExpressionToken(); |
587 | > | } |
588 | > | |
589 | > | bool SelectionCompiler::clauseComparator() { |
590 | Token tokenAtomProperty = tokenNext(); | |
591 | Token tokenComparator = tokenNext(); | |
592 | < | if ((tokenComparator.tok & Token.comparator) == 0) { |
593 | < | return comparisonOperatorExpected(); |
592 | > | if ((tokenComparator.tok & Token::comparator) == 0) { |
593 | > | return comparisonOperatorExpected(); |
594 | } | |
595 | ||
596 | Token tokenValue = tokenNext(); | |
597 | < | if (tokenValue.tok != Token.integer) { |
598 | < | return integerExpected(); |
597 | > | if (tokenValue.tok != Token::integer && tokenValue.tok != Token::decimal) { |
598 | > | return numberExpected(); |
599 | } | |
600 | < | int val = tokenValue.intValue; |
601 | < | // note that a comparator instruction is a complicated instruction |
602 | < | // int intValue is the tok of the property you are comparing |
603 | < | // the value against which you are comparing is stored as an Integer |
604 | < | // in the object value |
605 | < | return addTokenToPostfix(new Token(tokenComparator.tok, |
606 | < | tokenAtomProperty.tok, |
607 | < | new Integer(val))); |
608 | < | } |
600 | > | |
601 | > | float val; |
602 | > | if (tokenValue.value.type() == typeid(int)) { |
603 | > | val = boost::any_cast<int>(tokenValue.value); |
604 | > | } else if (tokenValue.value.type() == typeid(float)) { |
605 | > | val = boost::any_cast<float>(tokenValue.value); |
606 | > | } else { |
607 | > | return false; |
608 | > | } |
609 | ||
610 | < | bool SelectionCompiler::clauseWithin() { |
610 | > | boost::any floatVal; |
611 | > | floatVal = val; |
612 | > | return addTokenToPostfix(Token(tokenComparator.tok, |
613 | > | tokenAtomProperty.tok, floatVal)); |
614 | > | } |
615 | > | |
616 | > | bool SelectionCompiler::clauseWithin() { |
617 | tokenNext(); // WITHIN | |
618 | < | if (tokenNext().tok != Token.leftparen) { // ( |
619 | < | return leftParenthesisExpected(); |
618 | > | if (tokenNext().tok != Token::leftparen) { // ( |
619 | > | return leftParenthesisExpected(); |
620 | } | |
621 | ||
622 | < | Object distance; |
622 | > | boost::any distance; |
623 | Token tokenDistance = tokenNext(); // distance | |
624 | switch(tokenDistance.tok) { | |
625 | < | case Token.integer: |
626 | < | distance = new Float((tokenDistance.intValue * 4) / 1000f); |
627 | < | break; |
628 | < | case Token.decimal: |
629 | < | distance = tokenDistance.value; |
630 | < | break; |
630 | < | default: |
631 | < | return numberOrKeywordExpected(); |
625 | > | case Token::integer: |
626 | > | case Token::decimal: |
627 | > | distance = tokenDistance.value; |
628 | > | break; |
629 | > | default: |
630 | > | return numberOrKeywordExpected(); |
631 | } | |
632 | ||
633 | < | if (tokenNext().tok != Token.opOr) { // , |
634 | < | return commaExpected(); |
633 | > | if (tokenNext().tok != Token::opOr) { // , |
634 | > | return commaExpected(); |
635 | } | |
636 | ||
637 | if (! clauseOr()) { // *expression* | |
638 | < | return false; |
638 | > | return false; |
639 | } | |
640 | ||
641 | < | if (tokenNext().tok != Token.rightparen) { // )T |
642 | < | return rightParenthesisExpected(); |
641 | > | if (tokenNext().tok != Token::rightparen) { // )T |
642 | > | return rightParenthesisExpected(); |
643 | } | |
644 | ||
645 | < | return addTokenToPostfix(new Token(Token.within, distance)); |
646 | < | } |
645 | > | return addTokenToPostfix(Token(Token::within, distance)); |
646 | > | } |
647 | ||
648 | < | bool SelectionCompiler:: clauseChemObject() { |
649 | < | } |
648 | > | bool SelectionCompiler::clauseChemObjName() { |
649 | > | Token token = tokenNext(); |
650 | > | if (token.tok == Token::identifier && token.value.type() == typeid(std::string)) { |
651 | ||
652 | < | bool SelectionCompiler:: clauseMolecule() { |
653 | < | } |
652 | > | std::string name = boost::any_cast<std::string>(token.value); |
653 | > | if (isNameValid(name)) { |
654 | > | return addTokenToPostfix(Token(Token::name, name)); |
655 | > | } else { |
656 | > | return compileError("invalid name: " + name); |
657 | > | } |
658 | > | } |
659 | ||
660 | < | bool SelectionCompiler:: clauseMolName() { |
661 | < | } |
660 | > | return false; |
661 | > | |
662 | > | } |
663 | ||
664 | < | bool SelectionCompiler:: clauseMolIndex() { |
665 | < | } |
664 | > | bool SelectionCompiler::isNameValid(const std::string& name) { |
665 | > | int nbracket = 0; |
666 | > | int ndot = 0; |
667 | > | for (int i =0 ; i < name.size(); ++i) { |
668 | > | switch(name[i]) { |
669 | ||
670 | < | bool SelectionCompiler:: clauseName() { |
671 | < | } |
670 | > | case '[' : |
671 | > | ++nbracket; |
672 | > | break; |
673 | > | case ']' : |
674 | > | --nbracket; |
675 | > | break; |
676 | > | case '.' : |
677 | > | ++ndot; |
678 | > | break; |
679 | > | } |
680 | > | } |
681 | ||
682 | < | bool SelectionCompiler:: clauseIndex() { |
683 | < | } |
682 | > | //only allow 3 dots at most |
683 | > | return (ndot <=3 && nbracket == 0) ? true : false; |
684 | > | } |
685 | ||
686 | < | bool SelectionCompiler:: clauseStuntDoubleName() { |
687 | < | } |
686 | > | bool SelectionCompiler::clauseIndex(){ |
687 | > | Token token = tokenNext(); |
688 | > | if (token.tok == Token::integer) { |
689 | > | int index = boost::any_cast<int>(token.value); |
690 | > | int tok = tokPeek(); |
691 | > | std::cout << "Token::to is " << Token::to << ", tok = " << tok << std::endl; |
692 | > | if (tok == Token::to) { |
693 | > | tokenNext(); |
694 | > | tok = tokPeek(); |
695 | > | if (tok != Token::integer) { |
696 | > | return numberExpected(); |
697 | > | } |
698 | > | |
699 | > | boost::any intVal = tokenNext().value; |
700 | > | int first = index; |
701 | > | if (intVal.type() != typeid(int)){ |
702 | > | return false; |
703 | > | } |
704 | > | int second = boost::any_cast<int>(intVal); |
705 | ||
706 | < | bool SelectionCompiler:: clauseStuntDoubleIndex() { |
707 | < | } |
706 | > | return addTokenToPostfix(Token(Token::index, boost::any(std::make_pair(first, second)))); |
707 | > | |
708 | > | }else { |
709 | > | return addTokenToPostfix(Token(Token::index, boost::any(index))); |
710 | > | } |
711 | > | } else { |
712 | > | return numberExpected(); |
713 | > | } |
714 | > | } |
715 | ||
716 | } |
– | Removed lines |
+ | Added lines |
< | Changed lines |
> | Changed lines |