Mercurial > repo
comparison interps/glass/parseq.cc @ 996:859f9b4339e6
<Gregor> tar xf egobot.tar.xz
author | HackBot |
---|---|
date | Sun, 09 Dec 2012 19:30:08 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
995:6883f5911eb7 | 996:859f9b4339e6 |
---|---|
1 /* | |
2 * Copyright (c) 2005 Gregor Richards | |
3 * | |
4 * This file is part of Glass. | |
5 * | |
6 * Glass is free software; you can redistribute it and/or modify | |
7 * it under the terms of the GNU General Public License as published by | |
8 * the Free Software Foundation; either version 2 of the License, or | |
9 * (at your option) any later version. | |
10 * | |
11 * Glass is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 * GNU General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public License | |
17 * along with Glass; if not, write to the Free Software | |
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
19 */ | |
20 | |
21 #include <iostream> | |
22 #include <map> | |
23 #include <string> | |
24 using namespace std; | |
25 | |
26 #include <stdlib.h> | |
27 | |
28 #include "builtins.h" | |
29 #include "func.h" | |
30 #include "glass.h" | |
31 #include "klass.h" | |
32 #include "klassi.h" | |
33 #include "parseq.h" | |
34 #include "variable.h" | |
35 | |
36 ParseQElement::ParseQElement() | |
37 { | |
38 type = PQT_GLOBAL; | |
39 value = ""; | |
40 next = NULL; | |
41 } | |
42 | |
43 ParseQElement::ParseQElement(int st, string sv) | |
44 { | |
45 type = st; | |
46 value = sv; | |
47 next = NULL; | |
48 } | |
49 | |
50 ParseQElement::ParseQElement(int st, char sv) | |
51 { | |
52 string svs; | |
53 svs += sv; | |
54 | |
55 type = st; | |
56 value = svs; | |
57 next = NULL; | |
58 } | |
59 | |
60 ParseQElement::ParseQElement(ParseQElement ©) | |
61 { | |
62 type = copy.type; | |
63 value = copy.value; | |
64 next = NULL; | |
65 } | |
66 | |
67 ParseQ::ParseQ() | |
68 { | |
69 head = NULL; | |
70 } | |
71 | |
72 ParseQ::~ParseQ() | |
73 { | |
74 ParseQElement *cur, *pre; | |
75 cur = head; | |
76 pre = head; | |
77 while (cur) { | |
78 cur = cur->next; | |
79 delete pre; | |
80 pre = cur; | |
81 } | |
82 } | |
83 | |
84 int ParseQ::len() | |
85 { | |
86 int i; | |
87 ParseQElement *cur; | |
88 | |
89 cur = head; | |
90 i = 0; | |
91 while (cur) { | |
92 i++; | |
93 cur = cur->next; | |
94 } | |
95 | |
96 return i; | |
97 } | |
98 | |
99 ParseQElement *ParseQ::get(int n) | |
100 { | |
101 ParseQElement *cur = head; | |
102 | |
103 for (; cur && n; n--) cur = cur->next; | |
104 return cur; | |
105 } | |
106 | |
107 void ParseQ::add(ParseQElement *a) | |
108 { | |
109 ParseQElement *cur; | |
110 | |
111 if (!head) { | |
112 head = a; | |
113 } else { | |
114 cur = head; | |
115 while (cur->next) cur = cur->next; | |
116 | |
117 cur->next = a; | |
118 a->next = NULL; | |
119 } | |
120 } | |
121 | |
122 string ParseQ::dump() | |
123 { | |
124 string toret; | |
125 ParseQElement *cur = head; | |
126 | |
127 while (cur) { | |
128 switch (cur->type) { | |
129 case PQT_GLOBAL: | |
130 case PQT_CLASSWIDE: | |
131 case PQT_LOCAL: | |
132 case PQT_STACK: | |
133 if (cur->value.length() == 1) { | |
134 toret += cur->value; | |
135 } else { | |
136 toret += "(" + cur->value + ")"; | |
137 } | |
138 break; | |
139 | |
140 case PQT_NUMBER: | |
141 toret += "<" + cur->value + ">"; | |
142 break; | |
143 | |
144 case PQT_STRING: | |
145 toret += "\"" + cur->value + "\""; | |
146 break; | |
147 | |
148 case PQT_COMMAND: | |
149 toret += cur->value; | |
150 break; | |
151 | |
152 case PQT_BUILTIN: | |
153 toret += "~" + cur->value + "~"; | |
154 break; | |
155 } | |
156 | |
157 cur = cur->next; | |
158 } | |
159 | |
160 return toret; | |
161 } | |
162 | |
163 ParseQ *ParseQ::cutParseQ(int s, int l) | |
164 { | |
165 ParseQ *toret = new ParseQ; | |
166 ParseQElement *cur; | |
167 int i; | |
168 | |
169 // there are two very different cases: | |
170 // 1) s is 0 (need to change head) | |
171 // 2) s is >0 (need to find it, not change head) | |
172 if (s == 0) { | |
173 cur = head; | |
174 for (i = 1; cur && i < l; i++) cur = cur->next; | |
175 if (!cur) return toret; | |
176 // now we're on top of the last element | |
177 toret->head = head; | |
178 head = cur->next; | |
179 cur->next = NULL; | |
180 return toret; | |
181 } else { | |
182 ParseQElement *top; | |
183 | |
184 cur = head; | |
185 for (i = 1; cur && i < s; i++) cur = cur->next; | |
186 if (!cur) return toret; | |
187 // now we're immediately before the first element | |
188 top = cur; | |
189 cur = cur->next; | |
190 | |
191 // now find the last element | |
192 for (i = 1; cur && i < l; i++) cur = cur->next; | |
193 if (!cur) return toret; | |
194 // now we're on top of the last element | |
195 toret->head = top->next; | |
196 top->next = cur->next; | |
197 cur->next = NULL; | |
198 return toret; | |
199 } | |
200 } | |
201 | |
202 void ParseQ::parseKlasses() | |
203 { | |
204 int i, topi; | |
205 ParseQElement *cur, *top; | |
206 ParseQ *klass; | |
207 | |
208 // look for a { | |
209 while (true) { | |
210 cur = head; | |
211 for (i = 0; | |
212 cur && | |
213 (cur->type != PQT_COMMAND || cur->value != "{"); | |
214 i++) cur = cur->next; | |
215 if (!cur) break; | |
216 // we are now on top of the {, one further is the actual start point | |
217 cur->value = ""; | |
218 i++; cur = cur->next; | |
219 if (!cur) break; | |
220 topi = i; | |
221 top = cur; | |
222 | |
223 // now find the end | |
224 for (; | |
225 cur && | |
226 (cur->type != PQT_COMMAND || cur->value != "}"); | |
227 i++) cur = cur->next; | |
228 if (!cur) break; | |
229 // we are now on top of the } | |
230 klass = cutParseQ(topi, i - topi); | |
231 klass->parseKlass(); | |
232 delete klass; | |
233 } | |
234 } | |
235 | |
236 void ParseQ::parseKlass() | |
237 { | |
238 ParseQElement *origh, *cur, *top; | |
239 Func *func; | |
240 ParseQ *funcpq; | |
241 string var; | |
242 Klass *klass; | |
243 Variable *kvar; | |
244 int i, topi; | |
245 | |
246 // the first element should be a global variable name | |
247 if (!head || head->type != PQT_GLOBAL) return; | |
248 | |
249 // get rid of the current head | |
250 var = head->value; | |
251 origh = head; | |
252 head = head->next; | |
253 delete origh; | |
254 | |
255 // now start making the actual class | |
256 klass = new Klass(); | |
257 kvar = new Variable(); | |
258 | |
259 klass->name = var; | |
260 | |
261 kvar->type = VAR_KLASS; | |
262 kvar->kval = klass; | |
263 | |
264 // delete the current one if necessary | |
265 if (globalVars.find(var) != globalVars.end()) { | |
266 if (globalVars[var]->type == VAR_KLASS) { | |
267 delete globalVars[var]->kval; | |
268 } | |
269 delete globalVars[var]; | |
270 globalVars.erase(var); | |
271 } | |
272 | |
273 while (true) { | |
274 // look for a [ | |
275 cur = head; | |
276 for (i = 0; | |
277 cur && | |
278 (cur->type != PQT_COMMAND || cur->value != "["); | |
279 i++) cur = cur->next; | |
280 if (!cur) break; | |
281 // we are now on top of the [, one further is the actual start point | |
282 cur->value = ""; | |
283 i++; cur = cur->next; | |
284 if (!cur) break; | |
285 topi = i; | |
286 top = cur; | |
287 | |
288 // now find the end | |
289 for (; | |
290 cur && | |
291 (cur->type != PQT_COMMAND || cur->value != "]"); | |
292 i++) cur = cur->next; | |
293 if (!cur) break; | |
294 // we are now on top of the ] | |
295 funcpq = cutParseQ(topi, i - topi); | |
296 | |
297 // turn it into a function | |
298 if (!funcpq->head || funcpq->head->type != PQT_CLASSWIDE) { | |
299 delete funcpq; | |
300 continue; | |
301 } | |
302 func = new Func(); | |
303 func->name = funcpq->head->value; | |
304 origh = funcpq->head; | |
305 funcpq->head = origh->next; | |
306 func->contents = funcpq; | |
307 klass->functions[origh->value] = func; | |
308 delete origh; | |
309 } | |
310 | |
311 // only add this to the class list if there are functions | |
312 if (klass->functions.size() > 0) { | |
313 globalVars[var] = kvar; | |
314 } else { | |
315 delete kvar; | |
316 delete klass; | |
317 } | |
318 } | |
319 | |
320 #define POP \ | |
321 { \ | |
322 if (mainStack.size() != 0) { \ | |
323 delete mainStack[0]; \ | |
324 mainStack.pop_front(); \ | |
325 } \ | |
326 } | |
327 | |
328 | |
329 void ParseQ::runFunc(KlassI *of, Func *which) | |
330 { | |
331 map<string,Variable *> locals; | |
332 map<string,Variable *>::iterator locali; | |
333 | |
334 vector<KlassI *> localInstant; | |
335 ParseQElement *cur; | |
336 unsigned int sloc; | |
337 int depth; | |
338 Variable *toset, *kvar, *fvar; | |
339 KlassI *klassi; | |
340 Func *funci; | |
341 bool doadvance; | |
342 char fchar; | |
343 | |
344 // just run through the elements | |
345 int i; | |
346 cur = head; | |
347 for (i = 0; cur; i++) { | |
348 doadvance = true; | |
349 | |
350 //cout << cur->type << " " << cur->value << endl; | |
351 | |
352 // do something different for each type | |
353 switch (cur->type) { | |
354 case PQT_GLOBAL: | |
355 case PQT_CLASSWIDE: | |
356 case PQT_LOCAL: | |
357 mainStack.push_front(new Variable(VAR_VARIABLEP, cur->value)); | |
358 break; | |
359 | |
360 case PQT_STACK: | |
361 // copy a stack location | |
362 sloc = atoi(cur->value.c_str()); | |
363 if (mainStack.size() <= sloc) { | |
364 mainStack.push_front(new Variable()); | |
365 } else { | |
366 mainStack.push_front(new Variable(*mainStack[sloc])); | |
367 } | |
368 break; | |
369 | |
370 case PQT_NUMBER: | |
371 mainStack.push_front(new Variable(VAR_NUMBER, atof(cur->value.c_str()))); | |
372 break; | |
373 | |
374 case PQT_STRING: | |
375 mainStack.push_front(new Variable(VAR_STRING, cur->value)); | |
376 break; | |
377 | |
378 case PQT_BUILTIN: | |
379 doBuiltin(cur->value); | |
380 break; | |
381 | |
382 case PQT_COMMAND: | |
383 // now we have to switch for each command | |
384 if (cur->value == ",") { // pop | |
385 if (mainStack.size() > 0) POP; | |
386 break; | |
387 } else if (cur->value == "^") { // return | |
388 goto runFuncReturn; | |
389 } else if (cur->value == "=") { // set | |
390 if (mainStack.size() > 1) { | |
391 toset = mainStack[1]; | |
392 if (toset->type != VAR_VARIABLEP) { | |
393 // ERROR | |
394 return; | |
395 } | |
396 toset = getVar(of, &locals, toset->sval); | |
397 toset->mkcopy(*mainStack[0]); | |
398 POP; POP; | |
399 } | |
400 } else if (cur->value == "!") { // instantiate | |
401 if (mainStack.size() > 1) { | |
402 // two variable pointers ... | |
403 if (mainStack[0]->type != VAR_VARIABLEP || | |
404 mainStack[1]->type != VAR_VARIABLEP) { | |
405 // ERROR | |
406 return; | |
407 } | |
408 | |
409 // the second should be to a class | |
410 kvar = getVar(of, &locals, mainStack[0]->sval); | |
411 if (kvar->type != VAR_KLASS) { | |
412 // ERROR | |
413 return; | |
414 } | |
415 | |
416 // now make a klassi ... | |
417 klassi = new KlassI(); | |
418 klassi->of = kvar->kval; | |
419 | |
420 // and set up the reference | |
421 toset = getVar(of, &locals, mainStack[1]->sval); | |
422 toset->type = VAR_KLASSI; | |
423 toset->kival = klassi; | |
424 | |
425 // mark the ownership of the klassi | |
426 fchar = mainStack[1]->sval[0]; | |
427 if (fchar == '_') { | |
428 localInstant.push_back(klassi); | |
429 } else if (fchar >= 'a' && fchar <= 'z') { | |
430 of->localInstant.push_back(klassi); | |
431 } else if (fchar >= 'A' && fchar <= 'Z') { | |
432 globalInstant.push_back(klassi); | |
433 } | |
434 | |
435 POP; POP; | |
436 | |
437 // run the constructor | |
438 if (kvar->kval->functions.find("c__") != kvar->kval->functions.end()) { | |
439 kvar->kval->functions["c__"]->contents->runFunc(klassi, kvar->kval->functions["c__"]); | |
440 } | |
441 } | |
442 break; | |
443 } else if (cur->value == ".") { // function pointer | |
444 if (mainStack.size() > 1) { | |
445 // two variable pointers ... | |
446 if (mainStack[0]->type != VAR_VARIABLEP || | |
447 mainStack[1]->type != VAR_VARIABLEP) { | |
448 // ERROR | |
449 return; | |
450 } | |
451 | |
452 // the first should be a klassi | |
453 kvar = getVar(of, &locals, mainStack[1]->sval); | |
454 if (kvar->type != VAR_KLASSI) { | |
455 // ERROR | |
456 return; | |
457 } | |
458 | |
459 // the second should be a function in that klassi | |
460 fvar = getVar(kvar->kival, &locals, mainStack[0]->sval); | |
461 if (fvar->type != VAR_FUNC) { | |
462 // ERROR | |
463 return; | |
464 } | |
465 | |
466 // now make the pointer to the funci | |
467 toset = new Variable(VAR_FUNCI, kvar->kival, fvar->fval); | |
468 POP; POP; | |
469 mainStack.push_front(toset); | |
470 } | |
471 break; | |
472 } else if (cur->value == "?") { // execute | |
473 if (mainStack.size() > 0) { | |
474 // one funci pointer | |
475 if (mainStack[0]->type != VAR_FUNCI) { | |
476 // ERROR | |
477 return; | |
478 } | |
479 | |
480 funci = mainStack[0]->fval; | |
481 klassi = mainStack[0]->kival; | |
482 POP; | |
483 funci->contents->runFunc(klassi, funci); | |
484 } | |
485 break; | |
486 } else if (cur->value == "*") { // dereference | |
487 if (mainStack.size() > 0) { | |
488 // one variable pointer | |
489 if (mainStack[0]->type != VAR_VARIABLEP) { | |
490 // ERROR | |
491 return; | |
492 } | |
493 toset = new Variable(*getVar(of, &locals, mainStack[0]->sval)); | |
494 POP; | |
495 mainStack.push_front(toset); | |
496 } | |
497 break; | |
498 } else if (cur->value == "$") { // make a variable point to "this" | |
499 if (mainStack.size() > 0) { | |
500 // one variable pointer | |
501 if (mainStack[0]->type != VAR_VARIABLEP) { | |
502 // ERROR | |
503 return; | |
504 } | |
505 toset = getVar(of, &locals, mainStack[0]->sval); | |
506 toset->type = VAR_KLASSI; | |
507 toset->kival = of; | |
508 POP; | |
509 } | |
510 break; | |
511 } else if (cur->value == "/") { // loop open, one of the most difficult ones | |
512 i++; | |
513 cur = cur->next; | |
514 if (cur->type > PQT_LOCAL) { | |
515 // ERROR | |
516 return; | |
517 } | |
518 | |
519 // skip if the value of this variable is 0/"" | |
520 toset = getVar(of, &locals, cur->value); | |
521 if ((toset->type == VAR_NUMBER && toset->nval == 0.0) || | |
522 (toset->type == VAR_STRING && toset->sval == "") || | |
523 (toset->type != VAR_NUMBER && toset->type != VAR_STRING)) { | |
524 // the really hard part: find the matching backslash | |
525 depth = 0; | |
526 i++; | |
527 cur = cur->next; | |
528 for (; i < len(); i++) { | |
529 if (cur->type == PQT_COMMAND) { | |
530 if (cur->value == "/") { | |
531 depth++; | |
532 } else if (cur->value == "\\") { | |
533 if (depth == 0) { | |
534 break; | |
535 } else { | |
536 depth--; | |
537 } | |
538 } | |
539 } | |
540 cur = cur->next; | |
541 } | |
542 if (i == len()) { | |
543 // ERROR | |
544 return; | |
545 } | |
546 } | |
547 break; | |
548 } else if (cur->value == "\\") { // end of loop | |
549 // just jump back (very inefficient) | |
550 depth = 0; | |
551 i--; | |
552 for (; i >= 0; i--) { | |
553 cur = get(i); | |
554 if (cur->type == PQT_COMMAND) { | |
555 if (cur->value == "\\") { | |
556 depth++; | |
557 } else if (cur->value == "/") { | |
558 if (depth == 0) { | |
559 break; | |
560 } else { | |
561 depth--; | |
562 } | |
563 } | |
564 } | |
565 } | |
566 if (i == -1) { | |
567 // ERROR | |
568 return; | |
569 } | |
570 | |
571 // we are now pointing to the beginning - so don't advance yet | |
572 doadvance = false; | |
573 } | |
574 } | |
575 | |
576 if (doadvance) { | |
577 cur = cur->next; | |
578 } else { | |
579 i--; | |
580 } | |
581 | |
582 #ifdef IRC | |
583 // IRC users have a maximum alotted time | |
584 if (progTimer <= 1) { | |
585 progTimer = 0; | |
586 IRC_o = "Maximum time exceeded."; | |
587 goto runFuncReturn; | |
588 } | |
589 progTimer--; | |
590 #endif | |
591 } | |
592 runFuncReturn: | |
593 | |
594 // clean up garbage | |
595 for (locali = locals.begin(); locali != locals.end(); locali++) { | |
596 delete locali->second; | |
597 } | |
598 for (unsigned int ui = 0; ui < localInstant.size(); ui++) { | |
599 delete localInstant[ui]; | |
600 } | |
601 } |