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 &copy)
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 }