996
|
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 }
|