996
|
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 */
|