Mercurial > repo
comparison interps/sadol/BDSM2.cpp @ 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 * BDSM2 | |
3 * Author: Adam Sawicki | |
4 * http://www.regedit.risp.pl | |
5 * mailto:regedit@risp.pl | |
6 */ | |
7 #include "pch.hpp" | |
8 #include <iostream> | |
9 #include <cstdio> | |
10 #include "Console.hpp" | |
11 #include "Source.hpp" | |
12 | |
13 // array of elements of type T indexed by 'A'..'Z' or 'a'..'z' | |
14 // 'A' and 'a' means the same elements etc. | |
15 template <typename T> | |
16 class CharIndexedArray | |
17 { | |
18 private: | |
19 T m_Arr[26]; | |
20 | |
21 public: | |
22 T & operator [] (char ch) | |
23 { | |
24 if (ch >= 'a' && ch <= 'z') | |
25 return m_Arr[ch-'a']; | |
26 else if (ch >= 'A' && ch <= 'Z') | |
27 return m_Arr[ch-'A']; | |
28 else | |
29 Error("Invalid char array index: "+CharToStr(ch)); | |
30 return m_Arr[0]; | |
31 } | |
32 const T & operator [] (char ch) const | |
33 { | |
34 if (ch >= 'a' && ch <= 'z') | |
35 return m_Arr[ch-'a']; | |
36 else if (ch >= 'A' && ch <= 'Z') | |
37 return m_Arr[ch-'A']; | |
38 else | |
39 Error("Invalid char array index: "+CharToStr(ch)); | |
40 return m_Arr[0]; | |
41 } | |
42 }; | |
43 | |
44 //============================================================================== | |
45 | |
46 class Value | |
47 { | |
48 public: | |
49 enum TYPE { | |
50 TYPE_NONE, | |
51 TYPE_INTEGER, | |
52 TYPE_DOUBLE, | |
53 TYPE_STRING, | |
54 TYPE_LIST, | |
55 }; | |
56 | |
57 typedef std::vector<Value> ValueVector; | |
58 | |
59 // return: | |
60 // value < 0 if v1 < v2 | |
61 // value == 0 if v1 == v2 | |
62 // value > 0 if v1 > v2 | |
63 static int ValueCmp(const Value &v1, const Value &v2); | |
64 | |
65 private: | |
66 struct StringRealValue | |
67 { | |
68 private: | |
69 int m_ReferenceCounter; | |
70 | |
71 public: | |
72 string m_String; | |
73 | |
74 // create new value with counter 1, empty | |
75 StringRealValue() : m_ReferenceCounter(1) { } | |
76 // create new value with counter 1, initialized | |
77 StringRealValue(const string &String) : m_ReferenceCounter(1), m_String(String) { } | |
78 // create new value with counter 1 based on existing value | |
79 StringRealValue(const StringRealValue &v) : m_ReferenceCounter(1), m_String(v.m_String) { } | |
80 void AddReference() { m_ReferenceCounter++; } | |
81 int GetReferenceCount() { return m_ReferenceCounter; } | |
82 // dec reference counter, free object if 0 | |
83 static void Destroy(StringRealValue *v); | |
84 }; | |
85 | |
86 struct ListRealValue | |
87 { | |
88 private: | |
89 int m_ReferenceCounter; | |
90 | |
91 public: | |
92 ValueVector m_List; | |
93 | |
94 // create new value with counter 1, empty | |
95 ListRealValue() : m_ReferenceCounter(1) { } | |
96 // create new value with counter 1, initialized | |
97 ListRealValue(const ValueVector &List) : m_ReferenceCounter(1), m_List(List) { } | |
98 // create new value with counter 1 based on existing value | |
99 ListRealValue(const ListRealValue &v) : m_ReferenceCounter(1), m_List(v.m_List) { } | |
100 void AddReference() { m_ReferenceCounter++; } | |
101 int GetReferenceCount() { return m_ReferenceCounter; } | |
102 // dec reference counter, free object if 0 | |
103 static void Destroy(ListRealValue *v); | |
104 }; | |
105 | |
106 TYPE m_Type; | |
107 union { | |
108 int m_Integer; | |
109 double m_Double; | |
110 StringRealValue *m_String; | |
111 ListRealValue *m_List; | |
112 }; | |
113 | |
114 void CreateCopy(const Value &v); | |
115 void Destroy(); | |
116 | |
117 void ConvertToInteger(Value *v) const; | |
118 void ConvertToDouble(Value *v) const; | |
119 void ConvertToString(Value *v) const; | |
120 void ConvertToList(Value *v) const; | |
121 | |
122 public: | |
123 // create uninitialized value | |
124 Value() : m_Type(TYPE_NONE) { } | |
125 // create initialized, empty value with given type | |
126 // Integer or Double has undefined value, String or List is empty. | |
127 Value(TYPE Type); | |
128 // copy constructor | |
129 Value(const Value &v); | |
130 // create initialized value | |
131 Value(int Integer) : m_Type(TYPE_INTEGER), m_Integer(Integer) { } | |
132 Value(double Double) : m_Type(TYPE_DOUBLE), m_Double(Double) { } | |
133 Value(const string &String) : m_Type(TYPE_STRING), m_String(new StringRealValue(String)) { } | |
134 Value(const ValueVector &List) : m_Type(TYPE_STRING), m_List(new ListRealValue(List)) { } | |
135 ~Value(); | |
136 | |
137 Value & operator = (const Value &v); | |
138 Value & operator = (TYPE Type); | |
139 Value & operator = (int Integer); | |
140 Value & operator = (double Double); | |
141 Value & operator = (const ValueVector &List); | |
142 Value & operator = (const string &String); | |
143 | |
144 TYPE GetType() const { return m_Type; } | |
145 string GetTypeName() const; | |
146 // only if type is Integer | |
147 const int & ReadInteger() const { return m_Integer; } | |
148 int & AcceessInteger() { return m_Integer; } | |
149 // only if type is Double | |
150 const double & ReadDouble() const { return m_Double; } | |
151 double & AccessDouble() { return m_Double; } | |
152 // only if type is List | |
153 // use if don't want to modify - performance! | |
154 const ValueVector & ReadList() const { return m_List->m_List; } | |
155 // only if type is String | |
156 // use if don't want to modify - performance! | |
157 const string & ReadString() const { return m_String->m_String; } | |
158 // only if type is List | |
159 ValueVector & AccessList(); | |
160 // only if type is String | |
161 string & AccessString(); | |
162 | |
163 void ConsoleOut() const; | |
164 | |
165 void ConvertTo(Value *v, TYPE Type) const; | |
166 bool ConvertToBool() const; | |
167 int ConvertToInteger() const; | |
168 double ConvertToDouble() const; | |
169 void ConvertToString(string *s) const; | |
170 }; | |
171 | |
172 int Value::ValueCmp(const Value &v1, const Value &v2) | |
173 { | |
174 // list comparison | |
175 if (v1.GetType() == Value::TYPE_LIST || v2.GetType() == Value::TYPE_LIST) | |
176 { | |
177 Value w1, w2; | |
178 v1.ConvertTo(&w1, Value::TYPE_LIST); | |
179 v2.ConvertTo(&w2, Value::TYPE_LIST); | |
180 | |
181 int R; | |
182 for (size_t i = 0; true; i++) | |
183 { | |
184 if (i == w1.ReadList().size() && i == w2.ReadList().size()) | |
185 return 0; | |
186 else if (i == w1.ReadList().size()) | |
187 return -1; | |
188 else if (i == w2.ReadList().size()) | |
189 return +1; | |
190 else | |
191 { | |
192 R = ValueCmp(w1.ReadList()[i], w2.ReadList()[i]); | |
193 if (R != 0) | |
194 return R; | |
195 } | |
196 } | |
197 } | |
198 // string comparison | |
199 else if (v1.GetType() == Value::TYPE_STRING || v2.GetType() == Value::TYPE_STRING) | |
200 { | |
201 Value w1, w2; | |
202 v1.ConvertTo(&w1, Value::TYPE_STRING); | |
203 v2.ConvertTo(&w2, Value::TYPE_STRING); | |
204 | |
205 if (w1.ReadString() == w2.ReadString()) | |
206 return 0; | |
207 else if (w1.ReadString() < w2.ReadString()) | |
208 return -1; | |
209 else | |
210 return +1; | |
211 } | |
212 // double comparison | |
213 else if (v1.GetType() == Value::TYPE_DOUBLE || v2.GetType() == Value::TYPE_DOUBLE) | |
214 { | |
215 Value w1, w2; | |
216 v1.ConvertTo(&w1, Value::TYPE_DOUBLE); | |
217 v2.ConvertTo(&w2, Value::TYPE_DOUBLE); | |
218 | |
219 if (w1.ReadDouble() == w2.ReadDouble()) | |
220 return 0; | |
221 else if (w1.ReadDouble() < w2.ReadDouble()) | |
222 return -1; | |
223 else | |
224 return +1; | |
225 } | |
226 // integer comparison | |
227 else | |
228 { | |
229 // both must be integer | |
230 return v1.ReadInteger() - v2.ReadInteger(); | |
231 } | |
232 } | |
233 | |
234 void Value::StringRealValue::Destroy(StringRealValue *v) | |
235 { | |
236 v->m_ReferenceCounter--; | |
237 if (v->m_ReferenceCounter == 0) | |
238 delete v; | |
239 } | |
240 | |
241 void Value::ListRealValue::Destroy(ListRealValue *v) | |
242 { | |
243 v->m_ReferenceCounter--; | |
244 if (v->m_ReferenceCounter == 0) | |
245 delete v; | |
246 } | |
247 | |
248 void Value::CreateCopy(const Value &v) | |
249 { | |
250 m_Type = v.m_Type; | |
251 | |
252 switch (v.m_Type) | |
253 { | |
254 case TYPE_INTEGER: | |
255 m_Integer = v.m_Integer; | |
256 break; | |
257 case TYPE_DOUBLE: | |
258 m_Double = v.m_Double; | |
259 break; | |
260 // add reference to the same real value object | |
261 case TYPE_STRING: | |
262 m_String = v.m_String; | |
263 m_String->AddReference(); | |
264 break; | |
265 case TYPE_LIST: | |
266 m_List = v.m_List; | |
267 m_List->AddReference(); | |
268 break; | |
269 } | |
270 } | |
271 | |
272 void Value::Destroy() | |
273 { | |
274 // dec reference, destroy if needed | |
275 switch (m_Type) | |
276 { | |
277 case TYPE_STRING: | |
278 StringRealValue::Destroy(m_String); | |
279 break; | |
280 case TYPE_LIST: | |
281 ListRealValue::Destroy(m_List); | |
282 break; | |
283 } | |
284 } | |
285 | |
286 void Value::ConvertToInteger(Value *v) const | |
287 { | |
288 *v = ConvertToInteger(); | |
289 } | |
290 | |
291 void Value::ConvertToDouble(Value *v) const | |
292 { | |
293 *v = ConvertToDouble(); | |
294 } | |
295 | |
296 void Value::ConvertToString(Value *v) const | |
297 { | |
298 switch (m_Type) | |
299 { | |
300 case TYPE_INTEGER: | |
301 { | |
302 string s; | |
303 IntToStr(ReadInteger(), &s); | |
304 *v = s; | |
305 } | |
306 break; | |
307 case TYPE_DOUBLE: | |
308 *v = DoubleToStr(ReadDouble(), 'g'); | |
309 break; | |
310 case TYPE_STRING: | |
311 *v = *this; | |
312 break; | |
313 case TYPE_LIST: | |
314 Error("Cannot convert list to string"); | |
315 break; | |
316 case TYPE_NONE: | |
317 Error("Cannot convert uninitialized value to string"); | |
318 } | |
319 } | |
320 | |
321 void Value::ConvertToList(Value *v) const | |
322 { | |
323 switch (m_Type) | |
324 { | |
325 case TYPE_INTEGER: | |
326 case TYPE_DOUBLE: | |
327 case TYPE_STRING: | |
328 *v = Value::TYPE_LIST; | |
329 v->AccessList().push_back(*this); | |
330 break; | |
331 case TYPE_LIST: | |
332 *v = *this; | |
333 break; | |
334 case TYPE_NONE: | |
335 Error("Cannot convert uninitialized value to list"); | |
336 } | |
337 } | |
338 | |
339 Value::Value(TYPE Type) : m_Type(Type) | |
340 { | |
341 switch (Type) | |
342 { | |
343 case TYPE_STRING: | |
344 m_String = new StringRealValue(); | |
345 break; | |
346 case TYPE_LIST: | |
347 m_List = new ListRealValue(); | |
348 break; | |
349 } | |
350 } | |
351 | |
352 Value::Value(const Value &v) | |
353 { | |
354 CreateCopy(v); | |
355 } | |
356 | |
357 Value::~Value() | |
358 { | |
359 Destroy(); | |
360 } | |
361 | |
362 Value & Value::operator = (const Value &v) | |
363 { | |
364 if (&v != this) | |
365 { | |
366 // as destructor | |
367 Destroy(); | |
368 // as constructor | |
369 CreateCopy(v); | |
370 } | |
371 return *this; | |
372 } | |
373 | |
374 Value & Value::operator = (TYPE Type) | |
375 { | |
376 // as destructor | |
377 Destroy(); | |
378 // as constructor | |
379 m_Type = Type; | |
380 switch (Type) | |
381 { | |
382 case TYPE_STRING: | |
383 m_String = new StringRealValue(); | |
384 break; | |
385 case TYPE_LIST: | |
386 m_List = new ListRealValue(); | |
387 break; | |
388 } | |
389 | |
390 return *this; | |
391 } | |
392 | |
393 Value & Value::operator = (int Integer) | |
394 { | |
395 // as destructor | |
396 Destroy(); | |
397 // as constructor | |
398 m_Type = TYPE_INTEGER; | |
399 m_Integer = Integer; | |
400 | |
401 return *this; | |
402 } | |
403 | |
404 Value & Value::operator = (double Double) | |
405 { | |
406 // as destructor | |
407 Destroy(); | |
408 // as constructor | |
409 m_Type = TYPE_DOUBLE; | |
410 m_Double = Double; | |
411 | |
412 return *this; | |
413 } | |
414 | |
415 Value & Value::operator = (const ValueVector &List) | |
416 { | |
417 // as destructor | |
418 Destroy(); | |
419 // as constructor | |
420 m_Type = TYPE_LIST; | |
421 m_List = new ListRealValue(List); | |
422 | |
423 return *this; | |
424 } | |
425 | |
426 Value & Value::operator = (const string &String) | |
427 { | |
428 // as destructor | |
429 Destroy(); | |
430 // as constructor | |
431 m_Type = TYPE_STRING; | |
432 m_String = new StringRealValue(String); | |
433 | |
434 return *this; | |
435 } | |
436 | |
437 string Value::GetTypeName() const | |
438 { | |
439 switch (m_Type) | |
440 { | |
441 case TYPE_NONE: | |
442 return "none"; | |
443 case TYPE_INTEGER: | |
444 return "integer"; | |
445 case TYPE_DOUBLE: | |
446 return "double"; | |
447 case TYPE_STRING: | |
448 return "string"; | |
449 case TYPE_LIST: | |
450 return "list"; | |
451 default: | |
452 return "unknown"; | |
453 } | |
454 } | |
455 | |
456 Value::ValueVector & Value::AccessList() | |
457 { | |
458 if (m_List->GetReferenceCount() > 1) | |
459 { | |
460 // copy on write! | |
461 ListRealValue *l = new ListRealValue(*m_List); | |
462 ListRealValue::Destroy(m_List); | |
463 m_List = l; | |
464 } | |
465 return m_List->m_List; | |
466 } | |
467 | |
468 string & Value::AccessString() | |
469 { | |
470 if (m_String->GetReferenceCount() > 1) | |
471 { | |
472 // copy on write! | |
473 StringRealValue *s = new StringRealValue(*m_String); | |
474 StringRealValue::Destroy(m_String); | |
475 m_String = s; | |
476 } | |
477 return m_String->m_String; | |
478 } | |
479 | |
480 void Value::ConsoleOut() const | |
481 { | |
482 switch (m_Type) | |
483 { | |
484 case TYPE_INTEGER: | |
485 g_Console.OutInteger(ReadInteger()); | |
486 break; | |
487 case TYPE_DOUBLE: | |
488 g_Console.OutDouble(ReadDouble()); | |
489 break; | |
490 case TYPE_STRING: | |
491 g_Console.OutString(ReadString()); | |
492 break; | |
493 case TYPE_LIST: | |
494 { | |
495 g_Console.OutString("("); | |
496 for (size_t i = 0; i < ReadList().size(); i++) | |
497 { | |
498 if (i > 0) | |
499 g_Console.OutString(","); | |
500 ReadList()[i].ConsoleOut(); | |
501 } | |
502 g_Console.OutString(")"); | |
503 } | |
504 break; | |
505 case TYPE_NONE: | |
506 Error("Cannot print uninitialized value", ERR_IO); | |
507 } | |
508 } | |
509 | |
510 void Value::ConvertTo(Value *v, TYPE Type) const | |
511 { | |
512 switch (Type) | |
513 { | |
514 case TYPE_INTEGER: | |
515 ConvertToInteger(v); | |
516 break; | |
517 case TYPE_DOUBLE: | |
518 ConvertToDouble(v); | |
519 break; | |
520 case TYPE_STRING: | |
521 ConvertToString(v); | |
522 break; | |
523 case TYPE_LIST: | |
524 ConvertToList(v); | |
525 break; | |
526 case TYPE_NONE: | |
527 Error("Cannot convert to uninitialized value"); | |
528 } | |
529 } | |
530 | |
531 bool Value::ConvertToBool() const | |
532 { | |
533 switch (m_Type) | |
534 { | |
535 case TYPE_INTEGER: | |
536 return (m_Integer >= 1); | |
537 case TYPE_DOUBLE: | |
538 return (m_Double >= 1.0); | |
539 case TYPE_STRING: | |
540 return !ReadString().empty(); | |
541 case TYPE_LIST: | |
542 return !ReadList().empty(); | |
543 case TYPE_NONE: | |
544 Error("Cannot convert uninitialized value to bool"); | |
545 } | |
546 return false; | |
547 } | |
548 | |
549 int Value::ConvertToInteger() const | |
550 { | |
551 switch (m_Type) | |
552 { | |
553 case TYPE_INTEGER: | |
554 return ReadInteger(); | |
555 case TYPE_DOUBLE: | |
556 return Round(ReadDouble()); | |
557 case TYPE_STRING: | |
558 return (int)ReadString().size(); | |
559 case TYPE_LIST: | |
560 return (int)ReadList().size(); | |
561 case TYPE_NONE: | |
562 Error("Cannot convert uninitialized value to integer"); | |
563 } | |
564 return 0; | |
565 } | |
566 | |
567 double Value::ConvertToDouble() const | |
568 { | |
569 switch (m_Type) | |
570 { | |
571 case TYPE_INTEGER: | |
572 return (double)ReadInteger(); | |
573 case TYPE_DOUBLE: | |
574 return ReadDouble(); | |
575 case TYPE_STRING: | |
576 return (double)ReadString().size(); | |
577 case TYPE_LIST: | |
578 return (double)ReadList().size(); | |
579 case TYPE_NONE: | |
580 Error("Cannot convert uninitialized value to double"); | |
581 } | |
582 return 0.0; | |
583 } | |
584 | |
585 void Value::ConvertToString(string *s) const | |
586 { | |
587 switch (m_Type) | |
588 { | |
589 case TYPE_INTEGER: | |
590 IntToStr(ReadInteger(), s); | |
591 break; | |
592 case TYPE_DOUBLE: | |
593 *s = DoubleToStr(ReadDouble(), 'g'); | |
594 break; | |
595 case TYPE_STRING: | |
596 *s = ReadString(); | |
597 break; | |
598 case TYPE_LIST: | |
599 { | |
600 string s2; | |
601 *s = "("; | |
602 for (size_t i = 0; i < ReadList().size(); i++) | |
603 { | |
604 if (i > 0) | |
605 *s += ","; | |
606 ReadList()[i].ConvertToString(&s2); | |
607 *s += s2; | |
608 } | |
609 *s += ")"; | |
610 } | |
611 break; | |
612 case TYPE_NONE: | |
613 Error("Cannot convert uninitialized value to string"); | |
614 } | |
615 } | |
616 | |
617 //============================================================================== | |
618 | |
619 struct LValue | |
620 { | |
621 enum TYPE | |
622 { | |
623 TYPE_VALUE, | |
624 TYPE_STRCHAR, | |
625 }; | |
626 | |
627 TYPE m_Type; | |
628 union | |
629 { | |
630 // only if value | |
631 Value *m_Value; | |
632 // only if str char | |
633 string *m_String; | |
634 }; | |
635 // only if str char | |
636 size_t m_StringIndex; | |
637 | |
638 LValue() { } | |
639 LValue(Value *a_Value) : m_Type(TYPE_VALUE), m_Value(a_Value) { } | |
640 LValue(string *a_String, size_t a_StringIndex) : m_Type(TYPE_STRCHAR), m_String(a_String), m_StringIndex(a_StringIndex) { } | |
641 }; | |
642 | |
643 //============================================================================== | |
644 | |
645 // Contains char indexed array of value pointers. | |
646 // Auto-init and auto-destroy. | |
647 struct VarContext | |
648 { | |
649 CharIndexedArray<Value*> m_Values; | |
650 | |
651 VarContext() | |
652 { | |
653 for (char ch = 'A'; ch < 'Z'; ch++) | |
654 m_Values[ch] = 0; | |
655 } | |
656 ~VarContext() | |
657 { | |
658 for (char ch = 'A'; ch < 'Z'; ch++) | |
659 delete m_Values[ch]; | |
660 } | |
661 }; | |
662 | |
663 // Stack of var contexts | |
664 class VarContextStack | |
665 { | |
666 private: | |
667 std::vector<VarContext*> m_Stack; | |
668 Value m_DefaultValue; | |
669 | |
670 public: | |
671 VarContextStack(); | |
672 | |
673 void PushNew(); | |
674 void Pop(); | |
675 | |
676 const Value & ReadVar(char ch) const; | |
677 Value & AccessVar(char ch); | |
678 }; | |
679 | |
680 VarContextStack::VarContextStack() : m_DefaultValue((int)0) | |
681 { | |
682 } | |
683 | |
684 void VarContextStack::PushNew() | |
685 { | |
686 m_Stack.push_back(new VarContext); | |
687 } | |
688 | |
689 void VarContextStack::Pop() | |
690 { | |
691 delete m_Stack.back(); | |
692 m_Stack.pop_back(); | |
693 } | |
694 | |
695 const Value & VarContextStack::ReadVar(char ch) const | |
696 { | |
697 for (std::vector<VarContext*>::const_reverse_iterator rit = m_Stack.rbegin(); rit != m_Stack.rend(); ++rit) | |
698 if ((*rit)->m_Values[ch]) | |
699 return *((*rit)->m_Values[ch]); | |
700 return m_DefaultValue; | |
701 } | |
702 | |
703 Value & VarContextStack::AccessVar(char ch) | |
704 { | |
705 if (m_Stack.back()->m_Values[ch] == 0) | |
706 m_Stack.back()->m_Values[ch] = new Value(m_DefaultValue); | |
707 return *m_Stack.back()->m_Values[ch]; | |
708 } | |
709 | |
710 // Only in Execute call sequence. | |
711 VarContextStack g_VarContextStack; | |
712 VarContext g_GlobalVars; | |
713 | |
714 //============================================================================== | |
715 | |
716 struct Function; | |
717 struct Node; | |
718 | |
719 struct Scope | |
720 { | |
721 private: | |
722 // zero pointer list | |
723 void InitLocalFunctions(); | |
724 | |
725 public: | |
726 Scope *m_Parent; | |
727 Node *m_Node; | |
728 CharIndexedArray<Function*> m_LocalFunctions; | |
729 | |
730 Scope(Scope *a_Parent, Node *a_Node) : m_Parent(a_Parent), m_Node(a_Node) { InitLocalFunctions(); } | |
731 virtual ~Scope(); | |
732 | |
733 void ParseToEnd(Source &src); | |
734 // Parse given source as single expression, fill in this structure's fields | |
735 void Parse(Source &src); | |
736 // Value is list of arguments | |
737 void Execute(Value *result, Value *args); | |
738 void Optimize(); | |
739 }; | |
740 | |
741 struct Function : public Scope | |
742 { | |
743 // -1 means variable arg count | |
744 int m_ArgCount; | |
745 | |
746 Function(Scope *a_Parent, Node *a_Node, int a_ArgCount) : Scope(a_Parent, a_Node), m_ArgCount(a_ArgCount) { } | |
747 }; | |
748 | |
749 | |
750 | |
751 void Scope::InitLocalFunctions() | |
752 { | |
753 for (char ch = 'a'; ch <= 'z'; ch++) | |
754 m_LocalFunctions[ch] = 0; | |
755 } | |
756 | |
757 | |
758 | |
759 // Used only in Parse call sequence. | |
760 std::vector<Scope*> g_ScopeStack; | |
761 CharIndexedArray<Function*> g_GlobalFunctions; | |
762 | |
763 //============================================================================== | |
764 | |
765 struct Node | |
766 { | |
767 private: | |
768 void NodeError(const string &msg, ERR_PLACE place = ERR_GENERAL); | |
769 // free subnodes and clear subnode list | |
770 void ClearSubnodes(); | |
771 | |
772 int Parse_Integer(Source &src); | |
773 // does + | |
774 void OpAdd(Value *result, const Value &v1, const Value &v2); | |
775 // does - * % | |
776 void OpSubMulMod(char Op, Value *result, const Value &v1, const Value &v2); | |
777 // does / ^ | |
778 void OpDivPow(char Op, Value *result, const Value &v1, const Value &v2); | |
779 // does \ { blablabla - placeholder not to end line with \ } | |
780 void OpFloor(Value *result, const Value &v); | |
781 // does ' | |
782 void OpAposConverter(int Kind, Value *result, const Value &v); | |
783 // does = < > | |
784 void OpComparison(char Op, Value *result, const Value &v1, const Value &v2); | |
785 | |
786 public: | |
787 enum TYPE { | |
788 TYPE_SYMBOL, | |
789 TYPE_CONSTANT, | |
790 }; | |
791 | |
792 TYPE m_Type; | |
793 Source::Iterator m_SrcIterator; | |
794 | |
795 // only if symbol: | |
796 // If 'A'..'Z' or 'a'..'z', m_Function == 0 means variable, != 0 means function call. | |
797 char m_Ch; | |
798 std::vector<Node*> m_Sub; | |
799 union { | |
800 // only if m_Ch == 'a'..'z' or 'A'..'Z' and this is a function call: | |
801 // Function that should be called (weak pointer). | |
802 Function *m_Function; | |
803 // only if m_Ch == ';' => 0, 1, 2, 3 | |
804 // or m_Ch == '\'' => 1, 2 | |
805 int m_ExtraInt; | |
806 }; | |
807 | |
808 // only if constant: | |
809 Value m_Value; | |
810 | |
811 Node(); | |
812 ~Node(); | |
813 // Parse given source to the end as sequence of commands, fill in this structure's fields | |
814 void ParseToEnd(Source &src); | |
815 // Parse given source as single expression, fill in this structure's fields | |
816 void Parse(Source &src); | |
817 // Value is list of arguments. | |
818 void Execute(Value *result, Value *args); | |
819 LValue GetLValue(Value *args); | |
820 void Optimize(); | |
821 }; | |
822 | |
823 Scope::~Scope() | |
824 { | |
825 for (char ch = 'a'; ch <= 'z'; ch++) | |
826 delete m_LocalFunctions[ch]; | |
827 delete m_Node; | |
828 } | |
829 | |
830 void Scope::ParseToEnd(Source &src) | |
831 { | |
832 g_ScopeStack.push_back(this); | |
833 | |
834 m_Node = new Node; | |
835 m_Node->ParseToEnd(src); | |
836 | |
837 g_ScopeStack.pop_back(); | |
838 } | |
839 | |
840 void Scope::Parse(Source &src) | |
841 { | |
842 g_ScopeStack.push_back(this); | |
843 | |
844 m_Node = new Node; | |
845 m_Node->Parse(src); | |
846 | |
847 g_ScopeStack.pop_back(); | |
848 } | |
849 | |
850 void Scope::Execute(Value *result, Value *args) | |
851 { | |
852 g_ScopeStack.push_back(this); | |
853 g_VarContextStack.PushNew(); | |
854 | |
855 m_Node->Execute(result, args); | |
856 | |
857 g_VarContextStack.Pop(); | |
858 g_ScopeStack.pop_back(); | |
859 } | |
860 | |
861 void Scope::Optimize() | |
862 { | |
863 // TODO - scope stack | |
864 m_Node->Optimize(); | |
865 } | |
866 | |
867 void Node::NodeError(const string &msg, ERR_PLACE place) | |
868 { | |
869 Error(msg + " (" + m_SrcIterator.ToString() + ')', place); | |
870 } | |
871 | |
872 void Node::ClearSubnodes() | |
873 { | |
874 for (size_t i = 0; i < m_Sub.size(); i++) | |
875 delete m_Sub[i]; | |
876 m_Sub.clear(); | |
877 } | |
878 | |
879 int Node::Parse_Integer(Source &src) | |
880 { | |
881 src.Skip(); | |
882 src.SaveErrPos(); | |
883 Node *node = new Node(); | |
884 node->Parse(src); | |
885 node->Optimize(); | |
886 if (node->m_Type != Node::TYPE_CONSTANT) | |
887 src.SrcError("Cannot evaluate number in compilation time", ERR_PARSE); | |
888 src.DropErrPos(); | |
889 int R = node->m_Value.ConvertToInteger(); | |
890 delete node; | |
891 | |
892 return R; | |
893 } | |
894 | |
895 void Node::OpAdd(Value *result, const Value &v1, const Value &v2) | |
896 { | |
897 // 0 = list cat | |
898 // 1 = add as lists | |
899 // 2 = add as strings | |
900 // 3 = add as double | |
901 // 4 = add as integer | |
902 int Type = -1; | |
903 | |
904 if (v1.GetType() == Value::TYPE_LIST && v2.GetType() == Value::TYPE_LIST) | |
905 Type = 0; | |
906 else if (v1.GetType() == Value::TYPE_LIST || v2.GetType() == Value::TYPE_LIST) | |
907 Type = 1; | |
908 else if (v1.GetType() == Value::TYPE_STRING || v2.GetType() == Value::TYPE_STRING) | |
909 Type = 2; | |
910 else if (v1.GetType() == Value::TYPE_DOUBLE || v2.GetType() == Value::TYPE_DOUBLE) | |
911 Type = 3; | |
912 else | |
913 Type = 4; | |
914 | |
915 switch (Type) | |
916 { | |
917 case 0: | |
918 *result = v1; | |
919 for (size_t i = 0; i < v2.ReadList().size(); i++) | |
920 result->AccessList().push_back(v2.ReadList()[i]); | |
921 break; | |
922 case 1: | |
923 { | |
924 Value w2; | |
925 v1.ConvertTo(result, Value::TYPE_LIST); | |
926 v2.ConvertTo(&w2, Value::TYPE_LIST); | |
927 for (size_t i = 0; i < w2.ReadList().size(); i++) | |
928 result->AccessList().push_back(w2.ReadList()[i]); | |
929 } | |
930 break; | |
931 case 2: | |
932 { | |
933 Value w2; | |
934 v1.ConvertTo(result, Value::TYPE_STRING); | |
935 v2.ConvertTo(&w2, Value::TYPE_STRING); | |
936 result->AccessString() += w2.ReadString(); | |
937 } | |
938 break; | |
939 case 3: | |
940 { | |
941 Value w2; | |
942 v1.ConvertTo(result, Value::TYPE_DOUBLE); | |
943 v2.ConvertTo(&w2, Value::TYPE_DOUBLE); | |
944 result->AccessDouble() += w2.ReadDouble(); | |
945 } | |
946 break; | |
947 case 4: | |
948 *result = v1.ReadInteger() + v2.ReadInteger(); | |
949 break; | |
950 } | |
951 } | |
952 | |
953 void Node::OpSubMulMod(char Op, Value *result, const Value &v1, const Value &v2) | |
954 { | |
955 // integer | |
956 if (v1.GetType() == Value::TYPE_INTEGER && v2.GetType() == Value::TYPE_INTEGER) | |
957 { | |
958 int i1 = v1.ReadInteger(); | |
959 int i2 = v2.ReadInteger(); | |
960 switch (Op) | |
961 { | |
962 case '-': | |
963 *result = i1 - i2; | |
964 break; | |
965 case '*': | |
966 *result = i1 * i2; | |
967 break; | |
968 case '%': | |
969 if (i2 == 0) | |
970 NodeError("Integer division '%' by 0"); | |
971 *result = i1 % i2; | |
972 break; | |
973 } | |
974 } | |
975 // double | |
976 else if ( (v1.GetType() == Value::TYPE_INTEGER || v1.GetType() == Value::TYPE_DOUBLE) && | |
977 (v2.GetType() == Value::TYPE_INTEGER || v2.GetType() == Value::TYPE_DOUBLE) ) | |
978 { | |
979 double d1 = v1.ConvertToDouble(); | |
980 double d2 = v2.ConvertToDouble(); | |
981 switch (Op) | |
982 { | |
983 case '-': | |
984 *result = d1 - d2; | |
985 break; | |
986 case '*': | |
987 *result = d1 * d2; | |
988 break; | |
989 case '%': | |
990 if (d2 == 0.0) | |
991 NodeError("Double division '%' by 0"); | |
992 *result = fmod(d1, d2); | |
993 break; | |
994 } | |
995 } | |
996 else | |
997 NodeError("Invalid argument types for '"+CharToStr(Op)+"': "+v1.GetTypeName()+", "+v2.GetTypeName()); | |
998 } | |
999 | |
1000 void Node::OpDivPow(char Op, Value *result, const Value &v1, const Value &v2) | |
1001 { | |
1002 double d1 = v1.ConvertToDouble(); | |
1003 double d2 = v2.ConvertToDouble(); | |
1004 | |
1005 switch (Op) | |
1006 { | |
1007 case '/': | |
1008 if (d2 == 0.0) | |
1009 NodeError("Double division '/' by 0"); | |
1010 *result = d1 / d2; | |
1011 break; | |
1012 case '^': | |
1013 *result = pow(d1, d2); | |
1014 break; | |
1015 } | |
1016 } | |
1017 | |
1018 void Node::OpFloor(Value *result, const Value &v) | |
1019 { | |
1020 *result = floor(v.ConvertToDouble()); | |
1021 } | |
1022 | |
1023 void Node::OpAposConverter(int Kind, Value *result, const Value &v) | |
1024 { | |
1025 if (Kind == 1) | |
1026 { | |
1027 string s; | |
1028 v.ConvertToString(&s); | |
1029 if (s.empty()) | |
1030 NodeError("Cannot convert empty string to ASCII code in '''"); | |
1031 *result = (int)(unsigned int)(unsigned char)s[0]; | |
1032 } | |
1033 else if (Kind == 2) | |
1034 { | |
1035 int i = v.ConvertToInteger(); | |
1036 if (i < 0 || i >= 256) | |
1037 NodeError("Cannot convert integer value "+IntToStr(i)+" into ASCII character"); | |
1038 *result = Value::TYPE_STRING; | |
1039 result->AccessString() += (char)(unsigned char)(unsigned int)i; | |
1040 } | |
1041 } | |
1042 | |
1043 void Node::OpComparison(char Op, Value *result, const Value &v1, const Value &v2) | |
1044 { | |
1045 int R = Value::ValueCmp(v1, v2); | |
1046 | |
1047 switch (Op) | |
1048 { | |
1049 case '=': | |
1050 *result = (int)( (R == 0) ? 1 : 0 ); | |
1051 break; | |
1052 case '>': | |
1053 *result = (int)( (R > 0) ? 1 : 0 ); | |
1054 break; | |
1055 case '<': | |
1056 *result = (int)( (R < 0) ? 1 : 0 ); | |
1057 break; | |
1058 } | |
1059 } | |
1060 | |
1061 Node::Node() : m_Function(0) | |
1062 { | |
1063 } | |
1064 | |
1065 Node::~Node() | |
1066 { | |
1067 ClearSubnodes(); | |
1068 } | |
1069 | |
1070 void Node::ParseToEnd(Source &src) | |
1071 { | |
1072 // This node is ( symbol | |
1073 m_Type = TYPE_SYMBOL; | |
1074 m_SrcIterator = src.GetIterator(); | |
1075 m_Ch = '('; | |
1076 | |
1077 Node *node; | |
1078 for (;;) | |
1079 { | |
1080 src.Skip(); | |
1081 | |
1082 if (src.End()) | |
1083 break; | |
1084 | |
1085 m_Sub.push_back(node = new Node); | |
1086 node->Parse(src); | |
1087 } | |
1088 } | |
1089 | |
1090 void Node::Parse(Source &src) | |
1091 { | |
1092 src.Skip(); | |
1093 | |
1094 m_Type = TYPE_SYMBOL; | |
1095 m_SrcIterator = src.GetIterator(); | |
1096 m_Ch = src.GetS(); | |
1097 | |
1098 // zero args | |
1099 if (m_Ch >= '0' && m_Ch <= '9' || m_Ch == '_') | |
1100 { | |
1101 } | |
1102 // one arg | |
1103 else if (m_Ch == '[' || m_Ch == '!' || m_Ch == '`' || m_Ch == '\\') | |
1104 { | |
1105 Node *node = new Node; | |
1106 m_Sub.push_back(node); | |
1107 node->Parse(src); | |
1108 } | |
1109 // direct string | |
1110 else if (m_Ch == '"') | |
1111 { | |
1112 int CharCount = Parse_Integer(src); | |
1113 m_Type = TYPE_CONSTANT; | |
1114 m_Value = Value::TYPE_STRING; | |
1115 for (int i = 0; i < CharCount; i++) | |
1116 m_Value.AccessString() += src.GetS(); | |
1117 } | |
1118 // function definition | |
1119 else if (m_Ch == '~') | |
1120 { | |
1121 // name | |
1122 char func_name; | |
1123 src.Skip(); | |
1124 func_name = src.GetS(); | |
1125 if (!( func_name >= 'a' && func_name <= 'z' || func_name >= 'A' && func_name <= 'Z' )) | |
1126 src.SrcError("Invalid function name: '" + CharToStr(func_name) + "'", ERR_PARSE); | |
1127 | |
1128 // argument count | |
1129 int func_arg_count = Parse_Integer(src); | |
1130 if (func_arg_count < -1) | |
1131 NodeError("Invalid argument count for function '"+CharToStr(func_name)+"': "+IntToStr(func_arg_count), ERR_PARSE); | |
1132 | |
1133 // - global | |
1134 if (func_name >= 'A' && func_name <= 'Z') | |
1135 { | |
1136 Function *func = new Function(g_ScopeStack.front(), new Node, func_arg_count); | |
1137 // save function | |
1138 if (g_GlobalFunctions[func_name]) | |
1139 NodeError("Global function redefinition: '"+CharToStr(func_name)+"'", ERR_PARSE); | |
1140 g_GlobalFunctions[func_name] = func; | |
1141 // parse body | |
1142 func->Parse(src); | |
1143 func->Optimize(); | |
1144 } | |
1145 // - local | |
1146 else | |
1147 { | |
1148 Function *func = new Function(g_ScopeStack.back(), new Node, func_arg_count); | |
1149 // save function | |
1150 if (g_ScopeStack.back()->m_LocalFunctions[func_name]) | |
1151 NodeError("Local function redefinition: '"+CharToStr(func_name)+"'", ERR_PARSE); | |
1152 g_ScopeStack.back()->m_LocalFunctions[func_name] = func; | |
1153 // parse body | |
1154 func->Parse(src); | |
1155 func->Optimize(); | |
1156 } | |
1157 | |
1158 // this expression result | |
1159 m_Type = TYPE_CONSTANT; | |
1160 m_Value = (int)1; | |
1161 } | |
1162 // two args | |
1163 else if (m_Ch == '+' || m_Ch == '-' || m_Ch == '*' || m_Ch == '/' || | |
1164 m_Ch == '^' || m_Ch == '%' || m_Ch == ':' || | |
1165 m_Ch == '#' || m_Ch == ']' || m_Ch == '@' || m_Ch == '=' || | |
1166 m_Ch == '>' || m_Ch == '<' || m_Ch == '&' || m_Ch == '|') | |
1167 { | |
1168 Node *node1 = new Node; | |
1169 Node *node2 = new Node; | |
1170 m_Sub.push_back(node1); | |
1171 m_Sub.push_back(node2); | |
1172 node1->Parse(src); | |
1173 node2->Parse(src); | |
1174 } | |
1175 // three args | |
1176 else if (m_Ch == '?') | |
1177 { | |
1178 Node *node1 = new Node; | |
1179 Node *node2 = new Node; | |
1180 Node *node3 = new Node; | |
1181 m_Sub.push_back(node1); | |
1182 m_Sub.push_back(node2); | |
1183 m_Sub.push_back(node3); | |
1184 node1->Parse(src); | |
1185 node2->Parse(src); | |
1186 node3->Parse(src); | |
1187 } | |
1188 // function call or variable | |
1189 else if (m_Ch >= 'a' && m_Ch <= 'z' || m_Ch >= 'A' && m_Ch <= 'Z') | |
1190 { | |
1191 // if function, fill in the m_Function | |
1192 m_Function = 0; | |
1193 // - global | |
1194 if (m_Ch >= 'A' && m_Ch <= 'Z') | |
1195 // assign proper pointer or 0 | |
1196 m_Function = g_GlobalFunctions[m_Ch]; | |
1197 // - local | |
1198 else | |
1199 { | |
1200 Scope *scope = g_ScopeStack.back(); | |
1201 while (scope != 0) | |
1202 { | |
1203 if (scope->m_LocalFunctions[m_Ch]) | |
1204 { | |
1205 m_Function = scope->m_LocalFunctions[m_Ch]; | |
1206 break; | |
1207 } | |
1208 scope = scope->m_Parent; | |
1209 } | |
1210 } | |
1211 | |
1212 // this is function call | |
1213 if (m_Function) | |
1214 { | |
1215 // pointer to function is already saved in m_Function | |
1216 // argument count | |
1217 int arg_count = m_Function->m_ArgCount; | |
1218 if (arg_count == -1) | |
1219 arg_count = Parse_Integer(src); | |
1220 // arguments | |
1221 Node *node; | |
1222 for (int i = 0; i < arg_count; i++) | |
1223 { | |
1224 node = new Node; | |
1225 node->Parse(src); | |
1226 m_Sub.push_back(node); | |
1227 } | |
1228 } | |
1229 // this is variable - do nothing | |
1230 // m_Function stays 0 | |
1231 } | |
1232 // variable arg count | |
1233 else if (m_Ch == ',' || m_Ch == '.' || m_Ch == '(' || m_Ch == '$') { | |
1234 int SubnodeCount = Parse_Integer(src); | |
1235 Node *node; | |
1236 for (int i = 0; i < SubnodeCount; i++) | |
1237 { | |
1238 node = new Node; | |
1239 node->Parse(src); | |
1240 m_Sub.push_back(node); | |
1241 } | |
1242 } | |
1243 else if (m_Ch == ';') | |
1244 { | |
1245 m_ExtraInt = Parse_Integer(src); | |
1246 } | |
1247 else if (m_Ch == '\'') | |
1248 { | |
1249 m_ExtraInt = Parse_Integer(src); | |
1250 if (m_ExtraInt == 0) | |
1251 { | |
1252 m_Type = TYPE_CONSTANT; | |
1253 m_Value = (int)(unsigned int)(unsigned char)src.GetS(); | |
1254 } | |
1255 else if (m_ExtraInt == 1 || m_ExtraInt == 2) | |
1256 { | |
1257 // one subnode | |
1258 Node *node = new Node; | |
1259 node->Parse(src); | |
1260 m_Sub.push_back(node); | |
1261 } | |
1262 else | |
1263 NodeError("Invalid numeric constant in ''': "+IntToStr(m_ExtraInt), ERR_PARSE); | |
1264 } | |
1265 else | |
1266 // Erroneous character | |
1267 src.SrcError("Unsupported character: '" + CharToStr(m_Ch) + "'", ERR_PARSE); | |
1268 } | |
1269 | |
1270 void Node::Execute(Value *result, Value *args) | |
1271 { | |
1272 // Value | |
1273 if (m_Type == TYPE_CONSTANT) | |
1274 { | |
1275 *result = m_Value; | |
1276 return; | |
1277 } | |
1278 | |
1279 // Code symbol | |
1280 if (m_Ch >= '0' && m_Ch <= '9') | |
1281 { | |
1282 *result = (int)(unsigned char)(m_Ch - '0'); | |
1283 } | |
1284 // function call or variable | |
1285 else if (m_Ch >= 'a' && m_Ch <= 'z' || m_Ch >= 'A' && m_Ch <= 'Z') | |
1286 { | |
1287 // function call | |
1288 if (m_Function) | |
1289 { | |
1290 // construct argument list | |
1291 Value CallArgs = Value(Value::TYPE_LIST); | |
1292 Value CallArg; | |
1293 for (size_t i = 0; i < m_Sub.size(); i++) | |
1294 { | |
1295 m_Sub[i]->Execute(&CallArg, args); | |
1296 CallArgs.AccessList().push_back(CallArg); | |
1297 } | |
1298 // call function | |
1299 m_Function->Execute(result, &CallArgs); | |
1300 } | |
1301 // variable | |
1302 else | |
1303 { | |
1304 // global variable | |
1305 if (m_Ch >= 'A' && m_Ch <= 'Z') | |
1306 { | |
1307 if (g_GlobalVars.m_Values[m_Ch]) | |
1308 *result = *g_GlobalVars.m_Values[m_Ch]; | |
1309 else | |
1310 *result = (int)0; | |
1311 } | |
1312 // local variable | |
1313 else | |
1314 *result = g_VarContextStack.ReadVar(m_Ch); | |
1315 } | |
1316 } | |
1317 else if (m_Ch == '$') | |
1318 { | |
1319 Value element; | |
1320 *result = Value::TYPE_LIST; | |
1321 for (size_t i = 0; i < m_Sub.size(); i++) | |
1322 { | |
1323 m_Sub[i]->Execute(&element, args); | |
1324 result->AccessList().push_back(element); | |
1325 } | |
1326 } | |
1327 else if (m_Ch == ':') | |
1328 { | |
1329 m_Sub[1]->Execute(result, args); | |
1330 LValue lval = m_Sub[0]->GetLValue(args); | |
1331 // assign to a value | |
1332 if (lval.m_Type == LValue::TYPE_VALUE) | |
1333 *lval.m_Value = *result; | |
1334 // assign to a string character | |
1335 else | |
1336 { | |
1337 // string with length 1 is expected | |
1338 Value str_val; | |
1339 result->ConvertTo(&str_val, Value::TYPE_STRING); | |
1340 if (str_val.ReadString().length() != 1) | |
1341 NodeError("Cannot assing to string character string with length: "+Size_tToStr(str_val.ReadString().length()), ERR_EXECUTE); | |
1342 (*lval.m_String)[lval.m_StringIndex] = str_val.ReadString()[0]; | |
1343 } | |
1344 } | |
1345 else if (m_Ch == '#') | |
1346 { | |
1347 Value val_l, val_n; | |
1348 m_Sub[1]->Execute(&val_n, args); | |
1349 m_Sub[0]->Execute(&val_l, args); | |
1350 int index = val_n.ConvertToInteger(); | |
1351 if (val_l.GetType() == Value::TYPE_LIST) | |
1352 { | |
1353 if (index == -1) | |
1354 *result = (int)val_l.ReadList().size(); | |
1355 else if (index >= 0 && index < (int)val_l.ReadList().size()) | |
1356 *result = val_l.ReadList()[index]; | |
1357 else | |
1358 NodeError("Cannot extract element from list with '#' on index: "+IntToStr(index)+" - index out of bounds (list size: "+Size_tToStr(val_l.ReadList().size())+")", ERR_EXECUTE); | |
1359 } | |
1360 else if (val_l.GetType() == Value::TYPE_STRING) | |
1361 { | |
1362 if (index == -1) | |
1363 *result = (int)val_l.ReadString().size(); | |
1364 else if (index >= 0 && index < (int)val_l.ReadString().size()) | |
1365 *result = CharToStr(val_l.ReadString()[index]); | |
1366 else | |
1367 NodeError("Cannot extract element from string with '#' on index: "+IntToStr(index)+" - index out of bounds (string size: "+Size_tToStr(val_l.ReadString().size())+")", ERR_EXECUTE); | |
1368 } | |
1369 else | |
1370 NodeError("Cannot extract element from "+val_l.GetTypeName()+" with '#' on index: "+IntToStr(index)+" - invalid type", ERR_EXECUTE); | |
1371 } | |
1372 else if (m_Ch == '(') | |
1373 { | |
1374 *result = (int)0; | |
1375 for (size_t i = 0; i < m_Sub.size(); i++) | |
1376 m_Sub[i]->Execute(result, args); | |
1377 } | |
1378 else if (m_Ch == '@') | |
1379 { | |
1380 *result = (int)0; | |
1381 Value condition_value; | |
1382 for (;;) | |
1383 { | |
1384 m_Sub[0]->Execute(&condition_value, args); | |
1385 if (!condition_value.ConvertToBool()) | |
1386 break; | |
1387 m_Sub[1]->Execute(result, args); | |
1388 } | |
1389 } | |
1390 else if (m_Ch == '?') | |
1391 { | |
1392 Value ConditionValue; | |
1393 m_Sub[0]->Execute(&ConditionValue, args); | |
1394 if (ConditionValue.ConvertToBool()) | |
1395 m_Sub[1]->Execute(result, args); | |
1396 else | |
1397 m_Sub[2]->Execute(result, args); | |
1398 } | |
1399 else if (m_Ch == '!') { | |
1400 m_Sub[0]->Execute(result, args); | |
1401 result->ConsoleOut(); | |
1402 } | |
1403 else if (m_Ch == ';') | |
1404 { | |
1405 switch (m_ExtraInt) | |
1406 { | |
1407 case 0: | |
1408 *result = Value::TYPE_STRING; | |
1409 result->AccessString() += g_Console.InChar(); | |
1410 break; | |
1411 case 1: | |
1412 *result = g_Console.InInteger(); | |
1413 break; | |
1414 case 2: | |
1415 *result = g_Console.InDouble(); | |
1416 break; | |
1417 case 3: | |
1418 *result = Value::TYPE_STRING; | |
1419 g_Console.InString(&result->AccessString()); | |
1420 break; | |
1421 } | |
1422 } | |
1423 else if (m_Ch == '=' || m_Ch == '<' || m_Ch == '>') | |
1424 { | |
1425 Value v1, v2; | |
1426 m_Sub[0]->Execute(&v1, args); | |
1427 m_Sub[1]->Execute(&v2, args); | |
1428 OpComparison(m_Ch, result, v1, v2); | |
1429 } | |
1430 else if (m_Ch == '+') | |
1431 { | |
1432 Value v1, v2; | |
1433 m_Sub[0]->Execute(&v1, args); | |
1434 m_Sub[1]->Execute(&v2, args); | |
1435 OpAdd(result, v1, v2); | |
1436 } | |
1437 else if (m_Ch == '-' || m_Ch == '*' || m_Ch == '%') | |
1438 { | |
1439 Value v1, v2; | |
1440 m_Sub[0]->Execute(&v1, args); | |
1441 m_Sub[1]->Execute(&v2, args); | |
1442 OpSubMulMod(m_Ch, result, v1, v2); | |
1443 } | |
1444 else if (m_Ch == '/' || m_Ch == '^') | |
1445 { | |
1446 Value v1, v2; | |
1447 m_Sub[0]->Execute(&v1, args); | |
1448 m_Sub[1]->Execute(&v2, args); | |
1449 OpDivPow(m_Ch, result, v1, v2); | |
1450 } | |
1451 else if (m_Ch == '\\') | |
1452 { | |
1453 Value v; | |
1454 m_Sub[0]->Execute(&v, args); | |
1455 OpFloor(result, v); | |
1456 } | |
1457 else if (m_Ch == '&') | |
1458 { | |
1459 Value V; | |
1460 bool B; | |
1461 m_Sub[0]->Execute(&V, args); | |
1462 B = V.ConvertToBool(); | |
1463 if (B) | |
1464 { | |
1465 m_Sub[1]->Execute(&V, args); | |
1466 B = V.ConvertToBool(); | |
1467 } | |
1468 *result = (int)(B ? 1 : 0); | |
1469 } | |
1470 else if (m_Ch == '|') | |
1471 { | |
1472 Value V; | |
1473 bool B; | |
1474 m_Sub[0]->Execute(&V, args); | |
1475 B = ! V.ConvertToBool(); | |
1476 if (B) | |
1477 { | |
1478 m_Sub[1]->Execute(&V, args); | |
1479 B = ! V.ConvertToBool(); | |
1480 } | |
1481 *result = (int)(B ? 0 : 1); | |
1482 } | |
1483 else if (m_Ch == '[') | |
1484 { | |
1485 LValue lval = m_Sub[0]->GetLValue(args); | |
1486 if (lval.m_Type != LValue::TYPE_VALUE) | |
1487 NodeError("Tyme mismatch in '[' - list or string expected", ERR_EXECUTE); | |
1488 if (lval.m_Value->GetType() == Value::TYPE_LIST) | |
1489 { | |
1490 if (lval.m_Value->ReadList().empty()) | |
1491 NodeError("Empty list for '['", ERR_EXECUTE); | |
1492 *result = lval.m_Value->ReadList().back(); | |
1493 lval.m_Value->AccessList().pop_back(); | |
1494 } | |
1495 else if (lval.m_Value->GetType() == Value::TYPE_STRING) | |
1496 { | |
1497 if (lval.m_Value->ReadString().empty()) | |
1498 NodeError("Empty string for '['", ERR_EXECUTE); | |
1499 *result = CharToStr(lval.m_Value->ReadString()[lval.m_Value->ReadString().size()-1]); | |
1500 lval.m_Value->AccessString().erase(lval.m_Value->ReadString().size()-1); | |
1501 } | |
1502 else | |
1503 NodeError("Invalid l-value for '[' ("+lval.m_Value->GetTypeName()+") - list or string expected", ERR_EXECUTE); | |
1504 } | |
1505 else if (m_Ch == ']') | |
1506 { | |
1507 Value NewValue; | |
1508 m_Sub[1]->Execute(&NewValue, args); | |
1509 LValue lval = m_Sub[0]->GetLValue(args); | |
1510 | |
1511 if (lval.m_Type != LValue::TYPE_VALUE) | |
1512 NodeError("Type mismatch in ']' - list or string expected", ERR_EXECUTE); | |
1513 | |
1514 if (lval.m_Value->GetType() == Value::TYPE_LIST) | |
1515 lval.m_Value->AccessList().push_back(NewValue); | |
1516 else if (lval.m_Value->GetType() == Value::TYPE_STRING) | |
1517 { | |
1518 if (NewValue.GetType() != Value::TYPE_STRING || NewValue.ReadString().size() != 1) | |
1519 NodeError("Invalid argument for ']' - single character expected", ERR_EXECUTE); | |
1520 lval.m_Value->AccessString() += NewValue.ReadString()[0]; | |
1521 } | |
1522 else | |
1523 NodeError("Invalid l-value for ']' ("+lval.m_Value->GetTypeName()+") - list or string expected", ERR_EXECUTE); | |
1524 | |
1525 *result = *lval.m_Value; | |
1526 } | |
1527 else if (m_Ch == '_') | |
1528 *result = *args; | |
1529 else if (m_Ch == '\'') | |
1530 { | |
1531 Value v; | |
1532 m_Sub[0]->Execute(&v, args); | |
1533 OpAposConverter(m_ExtraInt, result, v); | |
1534 } | |
1535 else if (m_Ch == '`') | |
1536 { | |
1537 // read string | |
1538 Value str; | |
1539 m_Sub[0]->Execute(&str, args); | |
1540 if (str.GetType() != Value::TYPE_STRING) | |
1541 NodeError("String expected for '`' - found: "+str.GetTypeName(), ERR_EXECUTE); | |
1542 // parse code | |
1543 Source src(&str.ReadString()); | |
1544 Node *node = new Node; | |
1545 node->ParseToEnd(src); | |
1546 node->Optimize(); | |
1547 node->Execute(result, args); | |
1548 delete node; | |
1549 } | |
1550 else | |
1551 NodeError("Unknown command: '"+CharToStr(m_Ch)+"'", ERR_EXECUTE); | |
1552 } | |
1553 | |
1554 LValue Node::GetLValue(Value *args) | |
1555 { | |
1556 // variable | |
1557 if (m_Ch >= 'a' && m_Ch <= 'z' || m_Ch >= 'A' && m_Ch <= 'Z') | |
1558 { | |
1559 // function - error | |
1560 if (m_Function) | |
1561 NodeError("Cannot return '"+CharToStr(m_Ch)+"' as l-value - it is a function call", ERR_EXECUTE); | |
1562 // global variable | |
1563 if (m_Ch >= 'A' && m_Ch <= 'Z') | |
1564 { | |
1565 if (!g_GlobalVars.m_Values[m_Ch]) | |
1566 g_GlobalVars.m_Values[m_Ch] = new Value((int)0); | |
1567 return LValue(g_GlobalVars.m_Values[m_Ch]); | |
1568 } | |
1569 // local variable | |
1570 else | |
1571 return LValue(&g_VarContextStack.AccessVar(m_Ch)); | |
1572 } | |
1573 else if (m_Ch == '_') | |
1574 return LValue(args); | |
1575 else if (m_Ch == '(') | |
1576 { | |
1577 if (m_Sub.size() == 0) | |
1578 NodeError("Cannot return empty '(' as l-value", ERR_EXECUTE); | |
1579 return m_Sub.back()->GetLValue(args); | |
1580 } | |
1581 else if (m_Ch == '@') | |
1582 { | |
1583 LValue lval; | |
1584 bool OK = false; | |
1585 Value condition_value; | |
1586 for (;;) | |
1587 { | |
1588 m_Sub[0]->Execute(&condition_value, args); | |
1589 if (!condition_value.ConvertToBool()) | |
1590 break; | |
1591 lval = m_Sub[1]->GetLValue(args); | |
1592 OK = true; | |
1593 } | |
1594 if (!OK) | |
1595 NodeError("Cannot return loop with 0 iterations as l-value", ERR_EXECUTE); | |
1596 return lval; | |
1597 } | |
1598 else if (m_Ch == '#') | |
1599 { | |
1600 LValue result; | |
1601 Value val_n; | |
1602 m_Sub[1]->Execute(&val_n, args); | |
1603 LValue val_l = m_Sub[0]->GetLValue(args); | |
1604 int index = val_n.ConvertToInteger(); | |
1605 | |
1606 if (val_l.m_Type == LValue::TYPE_STRCHAR) | |
1607 { | |
1608 if (index == 0) | |
1609 result = val_l; | |
1610 else | |
1611 NodeError("Cannot return element of string's element as l-value if index "+IntToStr(index)+" is not 0", ERR_EXECUTE); | |
1612 } | |
1613 else | |
1614 { | |
1615 if (val_l.m_Value->GetType() == Value::TYPE_LIST) | |
1616 { | |
1617 if (index >= 0 && index < (int)val_l.m_Value->ReadList().size()) | |
1618 { | |
1619 result.m_Type = LValue::TYPE_VALUE; | |
1620 result.m_Value = &val_l.m_Value->AccessList()[index]; | |
1621 } | |
1622 else | |
1623 NodeError("Cannot return element of list as l-value - index "+IntToStr(index)+" out of bounds", ERR_EXECUTE); | |
1624 } | |
1625 else if (val_l.m_Value->GetType() == Value::TYPE_STRING) | |
1626 { | |
1627 if (index >= 0 && index < (int)val_l.m_Value->ReadString().size()) | |
1628 { | |
1629 result.m_Type = LValue::TYPE_STRCHAR; | |
1630 result.m_String = &val_l.m_Value->AccessString(); | |
1631 result.m_StringIndex = index; | |
1632 } | |
1633 else | |
1634 NodeError("Cannot return element of string as l-value - index "+IntToStr(index)+" out of bounds", ERR_EXECUTE); | |
1635 } | |
1636 else | |
1637 NodeError("Cannot return element of "+val_l.m_Value->GetTypeName()+" as l-value", ERR_EXECUTE); | |
1638 } | |
1639 return result; | |
1640 } | |
1641 else if (m_Ch == ']') | |
1642 { | |
1643 Value NewValue; | |
1644 m_Sub[1]->Execute(&NewValue, args); | |
1645 LValue lval = m_Sub[0]->GetLValue(args); | |
1646 | |
1647 if (lval.m_Type != LValue::TYPE_VALUE) | |
1648 NodeError("Type mismatch in ']' - list or string expected", ERR_EXECUTE); | |
1649 | |
1650 if (lval.m_Value->GetType() == Value::TYPE_LIST) | |
1651 lval.m_Value->AccessList().push_back(NewValue); | |
1652 else if (lval.m_Value->GetType() == Value::TYPE_STRING) | |
1653 { | |
1654 if (NewValue.GetType() != Value::TYPE_STRING || NewValue.ReadString().size() != 1) | |
1655 NodeError("Invalid argument for ']' - single character expected", ERR_EXECUTE); | |
1656 lval.m_Value->AccessString() += NewValue.ReadString()[0]; | |
1657 } | |
1658 else | |
1659 NodeError("Invalid l-value for ']' ("+lval.m_Value->GetTypeName()+") - list or string expected", ERR_EXECUTE); | |
1660 | |
1661 return lval; | |
1662 } | |
1663 else if (m_Ch == '?') | |
1664 { | |
1665 Value ConditionValue; | |
1666 m_Sub[0]->Execute(&ConditionValue, args); | |
1667 if (ConditionValue.ConvertToBool()) | |
1668 return m_Sub[1]->GetLValue(args); | |
1669 else | |
1670 return m_Sub[2]->GetLValue(args); | |
1671 } | |
1672 else | |
1673 { | |
1674 NodeError("Cannot obtain l-value from symbol: '"+CharToStr(m_Ch)+"'", ERR_EXECUTE); | |
1675 return LValue(); | |
1676 } | |
1677 } | |
1678 | |
1679 void Node::Optimize() | |
1680 { | |
1681 if (m_Type == TYPE_CONSTANT) | |
1682 return; | |
1683 | |
1684 // optimize subnodes | |
1685 for (size_t i = 0; i < m_Sub.size(); i++) | |
1686 m_Sub[i]->Optimize(); | |
1687 | |
1688 // optimize this node | |
1689 if (m_Ch >= '0' && m_Ch <= '9') { | |
1690 m_Type = TYPE_CONSTANT; | |
1691 m_Value = (int)(unsigned char)(m_Ch - '0'); | |
1692 } | |
1693 else if (m_Ch == ',') | |
1694 { | |
1695 m_Type = TYPE_CONSTANT; | |
1696 m_Value = (int)0; | |
1697 for (size_t i = 0; i < m_Sub.size(); i++) | |
1698 { | |
1699 if (m_Sub[i]->m_Type != TYPE_CONSTANT) | |
1700 m_Sub[i]->NodeError("Cannot evaluate digit value for ',' in compilation time for digit index: " + Size_tToStr(i), ERR_OPTIMIZE); | |
1701 m_Value.AcceessInteger() = m_Value.AcceessInteger() * 10 + m_Sub[i]->m_Value.ConvertToInteger(); | |
1702 } | |
1703 ClearSubnodes(); | |
1704 } | |
1705 else if (m_Ch == '.') | |
1706 { | |
1707 m_Type = TYPE_CONSTANT; | |
1708 m_Value = (double)0.0; | |
1709 double factor = 0.1; | |
1710 for (size_t i = 0; i < m_Sub.size(); i++) | |
1711 { | |
1712 if (m_Sub[i]->m_Type != Node::TYPE_CONSTANT) | |
1713 m_Sub[i]->NodeError("Cannot evaluate digit value for '.' in compilation time for digit index: " + Size_tToStr(i), ERR_OPTIMIZE); | |
1714 m_Value.AccessDouble() += m_Sub[i]->m_Value.ConvertToInteger() * factor; | |
1715 factor *= 0.1; | |
1716 } | |
1717 ClearSubnodes(); | |
1718 } | |
1719 else if (m_Ch == '(') | |
1720 { | |
1721 for (int i = (int)m_Sub.size()-2; i >= 0; i--) | |
1722 { | |
1723 if (m_Sub[i]->m_Type == TYPE_CONSTANT) | |
1724 { | |
1725 delete m_Sub[i]; | |
1726 m_Sub.erase(m_Sub.begin()+i); | |
1727 } | |
1728 } | |
1729 } | |
1730 else if (m_Ch == '+') | |
1731 { | |
1732 if (m_Sub[0]->m_Type == TYPE_CONSTANT && m_Sub[1]->m_Type == TYPE_CONSTANT) | |
1733 { | |
1734 m_Type = TYPE_CONSTANT; | |
1735 OpAdd(&m_Value, m_Sub[0]->m_Value, m_Sub[1]->m_Value); | |
1736 ClearSubnodes(); | |
1737 } | |
1738 } | |
1739 else if (m_Ch == '-' || m_Ch == '*' || m_Ch == '%') | |
1740 { | |
1741 if (m_Sub[0]->m_Type == TYPE_CONSTANT && m_Sub[1]->m_Type == TYPE_CONSTANT) | |
1742 { | |
1743 m_Type = TYPE_CONSTANT; | |
1744 OpSubMulMod(m_Ch, &m_Value, m_Sub[0]->m_Value, m_Sub[1]->m_Value); | |
1745 ClearSubnodes(); | |
1746 } | |
1747 } | |
1748 else if (m_Ch == '/' || m_Ch == '^') | |
1749 { | |
1750 if (m_Sub[0]->m_Type == TYPE_CONSTANT && m_Sub[1]->m_Type == TYPE_CONSTANT) | |
1751 { | |
1752 m_Type = TYPE_CONSTANT; | |
1753 OpDivPow(m_Ch, &m_Value, m_Sub[0]->m_Value, m_Sub[1]->m_Value); | |
1754 ClearSubnodes(); | |
1755 } | |
1756 } | |
1757 else if (m_Ch == '\\') | |
1758 { | |
1759 if (m_Sub[0]->m_Type == TYPE_CONSTANT) | |
1760 { | |
1761 m_Type = TYPE_CONSTANT; | |
1762 OpFloor(&m_Value, m_Sub[0]->m_Value); | |
1763 ClearSubnodes(); | |
1764 } | |
1765 } | |
1766 else if (m_Ch == '\'') | |
1767 { | |
1768 if (m_Sub[0]->m_Type == TYPE_CONSTANT) | |
1769 { | |
1770 m_Type = TYPE_CONSTANT; | |
1771 OpAposConverter(m_ExtraInt, &m_Value, m_Sub[0]->m_Value); | |
1772 ClearSubnodes(); | |
1773 } | |
1774 } | |
1775 else if (m_Ch == '@') | |
1776 { | |
1777 if (m_Sub[0]->m_Type == TYPE_CONSTANT && m_Sub[0]->m_Value.ConvertToBool() == false) | |
1778 { | |
1779 m_Type = TYPE_CONSTANT; | |
1780 m_Value = (int)0; | |
1781 ClearSubnodes(); | |
1782 } | |
1783 } | |
1784 else if (m_Ch == '#') | |
1785 { | |
1786 if (m_Sub[0]->m_Type == TYPE_CONSTANT && m_Sub[1]->m_Type == TYPE_CONSTANT) | |
1787 { | |
1788 m_Type = TYPE_CONSTANT; | |
1789 Value &val_l = m_Sub[0]->m_Value; | |
1790 Value &val_n = m_Sub[1]->m_Value; | |
1791 int index = val_n.ConvertToInteger(); | |
1792 if (val_l.GetType() == Value::TYPE_LIST) | |
1793 { | |
1794 if (index == -1) | |
1795 m_Value = (int)val_l.ReadList().size(); | |
1796 else if (index >= 0 && index < (int)val_l.ReadList().size()) | |
1797 m_Value = val_l.ReadList()[index]; | |
1798 else | |
1799 NodeError("Cannot extract element from list with '#' on index: "+IntToStr(index)+" - index out of bounds", ERR_OPTIMIZE); | |
1800 } | |
1801 else if (val_l.GetType() == Value::TYPE_STRING) | |
1802 { | |
1803 if (index == -1) | |
1804 m_Value = (int)val_l.ReadString().size(); | |
1805 else if (index >= 0 && index < (int)val_l.ReadString().size()) | |
1806 m_Value = CharToStr(val_l.ReadString()[index]); | |
1807 else | |
1808 NodeError("Cannot extract element from string with '#' on index: "+IntToStr(index)+" - index out of bounds", ERR_OPTIMIZE); | |
1809 } | |
1810 else | |
1811 NodeError("Cannot extract element from "+val_l.GetTypeName()+" with '#' on index: "+IntToStr(index)+" - invalid type", ERR_OPTIMIZE); | |
1812 ClearSubnodes(); | |
1813 } | |
1814 } | |
1815 else if (m_Ch == '$') | |
1816 { | |
1817 size_t i; | |
1818 for (i = 0; i < m_Sub.size(); i++) | |
1819 if (m_Sub[i]->m_Type != TYPE_CONSTANT) | |
1820 return; | |
1821 | |
1822 m_Type = TYPE_CONSTANT; | |
1823 m_Value = Value::TYPE_LIST; | |
1824 Value element; | |
1825 for (i = 0; i < m_Sub.size(); i++) | |
1826 m_Value.AccessList().push_back(m_Sub[i]->m_Value); | |
1827 | |
1828 ClearSubnodes(); | |
1829 } | |
1830 else if (m_Ch == '&') | |
1831 { | |
1832 bool Const1 = (m_Sub[0]->m_Type == TYPE_CONSTANT); | |
1833 bool Const2 = (m_Sub[1]->m_Type == TYPE_CONSTANT); | |
1834 | |
1835 if (Const1 && Const2) | |
1836 { | |
1837 m_Type = TYPE_CONSTANT; | |
1838 m_Value = (int)(m_Sub[0]->m_Value.ConvertToBool() && m_Sub[1]->m_Value.ConvertToBool() ? 1 : 0); | |
1839 ClearSubnodes(); | |
1840 } | |
1841 else if (Const1 && m_Sub[0]->m_Value.ConvertToBool() == false) | |
1842 { | |
1843 m_Type = TYPE_CONSTANT; | |
1844 m_Value = (int)0; | |
1845 ClearSubnodes(); | |
1846 } | |
1847 } | |
1848 else if (m_Ch == '|') | |
1849 { | |
1850 bool Const1 = (m_Sub[0]->m_Type == TYPE_CONSTANT); | |
1851 bool Const2 = (m_Sub[1]->m_Type == TYPE_CONSTANT); | |
1852 | |
1853 if (Const1 && Const2) | |
1854 { | |
1855 m_Type = TYPE_CONSTANT; | |
1856 m_Value = (int)(m_Sub[0]->m_Value.ConvertToBool() || m_Sub[1]->m_Value.ConvertToBool() ? 1 : 0); | |
1857 ClearSubnodes(); | |
1858 } | |
1859 else if (Const1 && m_Sub[0]->m_Value.ConvertToBool() == true) | |
1860 { | |
1861 m_Type = TYPE_CONSTANT; | |
1862 m_Value = (int)1; | |
1863 ClearSubnodes(); | |
1864 } | |
1865 } | |
1866 else if (m_Ch == '=' || m_Ch == '>' || m_Ch == '<') | |
1867 { | |
1868 if (m_Sub[0]->m_Type == TYPE_CONSTANT && m_Sub[1]->m_Type == TYPE_CONSTANT) | |
1869 { | |
1870 m_Type = TYPE_CONSTANT; | |
1871 OpComparison(m_Ch, &m_Value, m_Sub[0]->m_Value, m_Sub[1]->m_Value); | |
1872 ClearSubnodes(); | |
1873 } | |
1874 } | |
1875 else if (m_Ch == '[') | |
1876 { | |
1877 if (m_Sub[0]->m_Type == TYPE_CONSTANT) | |
1878 { | |
1879 m_Type = TYPE_CONSTANT; | |
1880 | |
1881 if (m_Sub[0]->m_Value.GetType() == Value::TYPE_LIST) | |
1882 { | |
1883 if (m_Sub[0]->m_Value.ReadList().empty()) | |
1884 NodeError("Empty list for '['", ERR_OPTIMIZE); | |
1885 m_Value = m_Sub[0]->m_Value.ReadList().back(); | |
1886 } | |
1887 else if (m_Sub[0]->m_Value.GetType() == Value::TYPE_STRING) | |
1888 { | |
1889 if (m_Sub[0]->m_Value.ReadString().empty()) | |
1890 NodeError("Empty string for '['", ERR_OPTIMIZE); | |
1891 m_Value = CharToStr(m_Sub[0]->m_Value.ReadString()[m_Sub[0]->m_Value.ReadString().size()-1]); | |
1892 } | |
1893 else | |
1894 NodeError("Invalid l-value for '[' ("+m_Sub[0]->m_Value.GetTypeName()+") - list or string expected", ERR_OPTIMIZE); | |
1895 | |
1896 ClearSubnodes(); | |
1897 } | |
1898 } | |
1899 else if (m_Ch == '?') | |
1900 { | |
1901 if (m_Sub[0]->m_Type == TYPE_CONSTANT && m_Sub[1]->m_Type == TYPE_CONSTANT && m_Sub[2]->m_Type == TYPE_CONSTANT) | |
1902 { | |
1903 m_Type = TYPE_CONSTANT; | |
1904 | |
1905 if (m_Sub[0]->m_Value.ConvertToBool()) | |
1906 m_Value = m_Sub[1]->m_Value; | |
1907 else | |
1908 m_Value = m_Sub[2]->m_Value; | |
1909 | |
1910 ClearSubnodes(); | |
1911 } | |
1912 } | |
1913 } | |
1914 | |
1915 //============================================================================== | |
1916 | |
1917 Scope *g_GlobalScope; | |
1918 | |
1919 void Intro() | |
1920 { | |
1921 std::cerr << "Badly Developed SADOL Machine\n" | |
1922 "Version: 2.0, 21 Dec 2005\n" | |
1923 "\n" | |
1924 "Copyright (C) 2005 Adam Sawicki\n" | |
1925 "All rights reserved\n" | |
1926 "\n" | |
1927 "Implementation of the SADOL esoteric programming language interpreter.\n" | |
1928 "\n" | |
1929 "Usage:\n" | |
1930 " BDSM <source-file>\n"; | |
1931 } | |
1932 | |
1933 void Interpret(const string &Src) | |
1934 { | |
1935 // std::cout << Src << std::endl; | |
1936 | |
1937 for (char ch = 'a'; ch < 'z'; ch++) | |
1938 g_GlobalFunctions[ch] = 0; | |
1939 | |
1940 Source src_obj(&Src); | |
1941 | |
1942 g_GlobalScope = new Scope(0, new Node); | |
1943 g_GlobalScope->ParseToEnd(src_obj); | |
1944 g_GlobalScope->Optimize(); | |
1945 Value VOut; | |
1946 Value VArgs = Value(Value::TYPE_LIST); | |
1947 g_GlobalScope->Execute(&VOut, &VArgs); | |
1948 delete g_GlobalScope; | |
1949 } | |
1950 | |
1951 void Go(const char *FileName) | |
1952 { | |
1953 // Open source file | |
1954 FILE *file = fopen(FileName, "rb"); | |
1955 if (file == 0) | |
1956 Error("Cannot open file: "+string(FileName)); | |
1957 | |
1958 // Read source into string | |
1959 char buf[BUF_SIZE]; | |
1960 size_t count; | |
1961 string src; | |
1962 for (;;) { | |
1963 count = fread(buf, 1, BUF_SIZE, file); | |
1964 if (count > 0) { | |
1965 src.append(buf, count); | |
1966 } | |
1967 else break; | |
1968 } | |
1969 | |
1970 // Close source file | |
1971 fclose(file); | |
1972 | |
1973 // Interpret! | |
1974 Interpret(src); | |
1975 } | |
1976 | |
1977 int main(int argc, char **argv) | |
1978 { | |
1979 if (argc == 2) | |
1980 { | |
1981 Go(argv[1]); | |
1982 return 0; | |
1983 } | |
1984 else { | |
1985 Intro(); | |
1986 return -1; | |
1987 } | |
1988 } | |
1989 | |
1990 /* When error, every function can call Error. | |
1991 */ |