1 // -*- Mode: C++; tab-width:2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi:tw=80:et:ts=2:sts=2
3 //
4 // -----------------------------------------------------------------------
5 //
6 // This file is part of libreallive, a dependency of RLVM.
7 //
8 // -----------------------------------------------------------------------
9 //
10 // Copyright (c) 2006, 2007 Peter Jolly
11 // Copyright (c) 2007 Elliot Glaysher
12 //
13 // Permission is hereby granted, free of charge, to any person
14 // obtaining a copy of this software and associated documentation
15 // files (the "Software"), to deal in the Software without
16 // restriction, including without limitation the rights to use, copy,
17 // modify, merge, publish, distribute, sublicense, and/or sell copies
18 // of the Software, and to permit persons to whom the Software is
19 // furnished to do so, subject to the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 // SOFTWARE.
32 //
33 // -----------------------------------------------------------------------
34 
35 #include "libreallive/expression.h"
36 
37 #include <boost/algorithm/string.hpp>
38 #include <boost/algorithm/string/predicate.hpp>
39 #include <boost/tokenizer.hpp>
40 
41 #include <iomanip>
42 #include <sstream>
43 #include <string>
44 
45 #include "libreallive/defs.h"
46 #include "libreallive/intmemref.h"
47 #include "machine/reference.h"
48 #include "machine/rlmachine.h"
49 
50 namespace {
51 
IntToBytecode(int val)52 std::string IntToBytecode(int val) {
53   std::string prefix("$\xFF");
54   libreallive::append_i32(prefix, val);
55   return prefix;
56 }
57 
IsUnescapedQuotationMark(const char * src,const char * current)58 bool IsUnescapedQuotationMark(const char* src, const char* current) {
59   if (src == current)
60     return *current == '"';
61   else
62     return *current == '"' && *(current - 1) != '\\';
63 }
64 
65 }  // namespace
66 
67 namespace libreallive {
68 
69 // Expression Tokenization
70 //
71 // Functions that tokenize expression data while parsing the bytecode
72 // to create the BytecodeElements. These functions simply tokenize and
73 // mark boundaries; they do not perform any parsing.
74 
NextToken(const char * src)75 size_t NextToken(const char* src) {
76   if (*src++ != '$')
77     return 0;
78   if (*src++ == 0xff)
79     return 6;
80   if (*src++ != '[')
81     return 2;
82   return 4 + NextExpression(src);
83 }
84 
NextTerm(const char * src)85 static size_t NextTerm(const char* src) {
86   if (*src == '(')
87     return 2 + NextExpression(src + 1);
88   if (*src == '\\')
89     return 2 + NextTerm(src + 2);
90   return NextToken(src);
91 }
92 
NextArithmatic(const char * src)93 static size_t NextArithmatic(const char* src) {
94   size_t lhs = NextTerm(src);
95   return (src[lhs] == '\\') ? lhs + 2 + NextArithmatic(src + lhs + 2) : lhs;
96 }
97 
NextCondition(const char * src)98 static size_t NextCondition(const char* src) {
99   size_t lhs = NextArithmatic(src);
100   return (src[lhs] == '\\' && src[lhs + 1] >= 0x28 && src[lhs + 1] <= 0x2d)
101              ? lhs + 2 + NextArithmatic(src + lhs + 2)
102              : lhs;
103 }
104 
NextAnd(const char * src)105 static size_t NextAnd(const char* src) {
106   size_t lhs = NextCondition(src);
107   return (src[lhs] == '\\' && src[lhs + 1] == '<')
108              ? lhs + 2 + NextAnd(src + lhs + 2)
109              : lhs;
110 }
111 
NextExpression(const char * src)112 size_t NextExpression(const char* src) {
113   size_t lhs = NextAnd(src);
114   return (src[lhs] == '\\' && src[lhs + 1] == '=')
115              ? lhs + 2 + NextExpression(src + lhs + 2)
116              : lhs;
117 }
118 
NextString(const char * src)119 size_t NextString(const char* src) {
120   bool quoted = false;
121   const char* end = src;
122 
123   while (true) {
124     if (quoted) {
125       quoted = !IsUnescapedQuotationMark(src, end);
126       if (!quoted && *(end - 1) != '\\') {
127         end++;  // consume the final quote
128         break;
129       }
130     } else {
131       quoted = IsUnescapedQuotationMark(src, end);
132       if (strncmp(end, "###PRINT(", 9) == 0) {
133         end += 9;
134         end += 1 + NextExpression(end);
135         continue;
136       }
137       if (!((*end >= 0x81 && *end <= 0x9f) || (*end >= 0xe0 && *end <= 0xef) ||
138             (*end >= 'a' && *end <= 'z') ||
139             (*end >= 'A' && *end <= 'Z') || (*end >= '0' && *end <= '9') ||
140             *end == ' ' || *end == '?' || *end == '_' || *end == '"' ||
141             *end == '\\')) {
142         break;
143       }
144     }
145     if ((*end >= 0x81 && *end <= 0x9f) || (*end >= 0xe0 && *end <= 0xef))
146       end += 2;
147     else
148       ++end;
149   }
150 
151   return end - src;
152 }
153 
NextData(const char * src)154 size_t NextData(const char* src) {
155   if (*src == ',')
156     return 1 + NextData(src + 1);
157   if (*src == '\n')
158     return 3 + NextData(src + 3);
159   if ((*src >= 0x81 && *src <= 0x9f) || (*src >= 0xe0 && *src <= 0xef) ||
160       (*src >= 'A' && *src <= 'Z') || (*src >= '0' && *src <= '9') ||
161       *src == ' ' || *src == '?' || *src == '_' || *src == '"' ||
162       strcmp(src, "###PRINT(") == 0)
163     return NextString(src);
164   if (*src == 'a' || *src == '(') {
165     const char* end = src;
166     if (*end++ == 'a') {
167       ++end;
168 
169       // Some special cases have multiple tags.
170       if (*end == 'a')
171         end += 2;
172 
173       if (*end != '(') {
174         end += NextData(end);
175         return end - src;
176       } else {
177         end++;
178       }
179     }
180 
181     while (*end != ')')
182       end += NextData(end);
183     end++;
184     if (*end == '\\')
185       end += NextExpression(end);
186     return end - src;
187   } else {
188     return NextExpression(src);
189   }
190 }
191 
192 // -----------------------------------------------------------------------
193 
194 // Expression Parsing
195 //
196 // Functions used at runtime to parse expressions, both as
197 // ExpressionPieces, parameters in function calls, and other uses in
198 // some special cases. These functions form a recursive descent parser
199 // that parses expressions and parameters in Reallive byte code into
200 // ExpressionPieces, which are executed with the current RLMachine.
201 //
202 // These functions were translated from the O'Caml implementation in
203 // dissassembler.ml in RLDev, so really, while I coded this, Haeleth
204 // really gets all the credit.
205 
GetExpressionToken(const char * & src)206 ExpressionPiece GetExpressionToken(const char*& src) {
207   if (src[0] == 0xff) {
208     src++;
209     int value = read_i32(src);
210     src += 4;
211     return ExpressionPiece::IntConstant(value);
212   } else if (src[0] == 0xc8) {
213     src++;
214     return ExpressionPiece::StoreRegister();
215   } else if ((src[0] != 0xc8 && src[0] != 0xff) && src[1] == '[') {
216     int type = src[0];
217     src += 2;
218     ExpressionPiece location = GetExpression(src);
219 
220     if (src[0] != ']') {
221       std::ostringstream ss;
222       ss << "Unexpected character '" << src[0] << "' in GetExpressionToken"
223          << " (']' expected)";
224       throw Error(ss.str());
225     }
226     src++;
227 
228     return ExpressionPiece::MemoryReference(type, std::move(location));
229   } else if (src[0] == 0) {
230     throw Error("Unexpected end of buffer in GetExpressionToken");
231   } else {
232     std::ostringstream err;
233     err << "Unknown toke type 0x" << std::hex << (short)src[0]
234         << " in GetExpressionToken" << std::endl;
235     throw Error(err.str());
236   }
237 }
238 
GetExpressionTerm(const char * & src)239 ExpressionPiece GetExpressionTerm(const char*& src) {
240   if (src[0] == '$') {
241     src++;
242     return GetExpressionToken(src);
243   } else if (src[0] == '\\' && src[1] == 0x00) {
244     src += 2;
245     return GetExpressionTerm(src);
246   } else if (src[0] == '\\' && src[1] == 0x01) {
247     // Uniary -
248     src += 2;
249     return ExpressionPiece::UniaryExpression(0x01, GetExpressionTerm(src));
250   } else if (src[0] == '(') {
251     src++;
252     ExpressionPiece p = GetExpressionBoolean(src);
253     if (src[0] != ')') {
254       std::ostringstream ss;
255       ss << "Unexpected character '" << src[0] << "' in GetExpressionTerm"
256          << " (')' expected)";
257       throw Error(ss.str());
258     }
259     src++;
260     return p;
261   } else if (src[0] == 0) {
262     throw Error("Unexpected end of buffer in GetExpressionTerm");
263   } else {
264     std::ostringstream err;
265     err << "Unknown token type 0x" << std::hex << (short)src[0]
266         << " in GetExpressionTerm";
267     throw Error(err.str());
268   }
269 }
270 
GetExpressionArithmaticLoopHiPrec(const char * & src,ExpressionPiece tok)271 static ExpressionPiece GetExpressionArithmaticLoopHiPrec(
272     const char*& src,
273     ExpressionPiece tok) {
274   if (src[0] == '\\' && src[1] >= 0x02 && src[1] <= 0x09) {
275     char op = src[1];
276     // Advance past this operator
277     src += 2;
278     ExpressionPiece new_piece = ExpressionPiece::BinaryExpression(
279         op, std::move(tok), GetExpressionTerm(src));
280     return GetExpressionArithmaticLoopHiPrec(src, std::move(new_piece));
281   } else {
282     // We don't consume anything and just return our input token.
283     return tok;
284   }
285 }
286 
GetExpressionArithmaticLoop(const char * & src,ExpressionPiece tok)287 static ExpressionPiece GetExpressionArithmaticLoop(
288     const char*& src,
289     ExpressionPiece tok) {
290   if (src[0] == '\\' && (src[1] == 0x00 || src[1] == 0x01)) {
291     char op = src[1];
292     src += 2;
293     ExpressionPiece other = GetExpressionTerm(src);
294     ExpressionPiece rhs =
295         GetExpressionArithmaticLoopHiPrec(src, std::move(other));
296     ExpressionPiece new_piece =
297         ExpressionPiece::BinaryExpression(op, std::move(tok), std::move(rhs));
298     return GetExpressionArithmaticLoop(src, std::move(new_piece));
299   } else {
300     return tok;
301   }
302 }
303 
GetExpressionArithmatic(const char * & src)304 ExpressionPiece GetExpressionArithmatic(const char*& src) {
305   return GetExpressionArithmaticLoop(
306       src, GetExpressionArithmaticLoopHiPrec(src, GetExpressionTerm(src)));
307 }
308 
GetExpressionConditionLoop(const char * & src,ExpressionPiece tok)309 static ExpressionPiece GetExpressionConditionLoop(
310     const char*& src,
311     ExpressionPiece tok) {
312   if (src[0] == '\\' && (src[1] >= 0x28 && src[1] <= 0x2d)) {
313     char op = src[1];
314     src += 2;
315     ExpressionPiece rhs = GetExpressionArithmatic(src);
316     ExpressionPiece new_piece =
317         ExpressionPiece::BinaryExpression(op, std::move(tok), std::move(rhs));
318     return GetExpressionConditionLoop(src, std::move(new_piece));
319   } else {
320     return tok;
321   }
322 }
323 
GetExpressionCondition(const char * & src)324 ExpressionPiece GetExpressionCondition(const char*& src) {
325   return GetExpressionConditionLoop(src, GetExpressionArithmatic(src));
326 }
327 
GetExpressionBooleanLoopAnd(const char * & src,ExpressionPiece tok)328 static ExpressionPiece GetExpressionBooleanLoopAnd(
329     const char*& src,
330     ExpressionPiece tok) {
331   if (src[0] == '\\' && src[1] == '<') {
332     src += 2;
333     ExpressionPiece rhs = GetExpressionCondition(src);
334     return GetExpressionBooleanLoopAnd(
335         src,
336         ExpressionPiece::BinaryExpression(
337             0x3c, std::move(tok), std::move(rhs)));
338   } else {
339     return tok;
340   }
341 }
342 
GetExpressionBooleanLoopOr(const char * & src,ExpressionPiece tok)343 static ExpressionPiece GetExpressionBooleanLoopOr(
344     const char*& src,
345     ExpressionPiece tok) {
346   if (src[0] == '\\' && src[1] == '=') {
347     src += 2;
348     ExpressionPiece innerTerm = GetExpressionCondition(src);
349     ExpressionPiece rhs =
350         GetExpressionBooleanLoopAnd(src, std::move(innerTerm));
351     return GetExpressionBooleanLoopOr(
352         src,
353         ExpressionPiece::BinaryExpression(
354             0x3d, std::move(tok), std::move(rhs)));
355   } else {
356     return tok;
357   }
358 }
359 
GetExpressionBoolean(const char * & src)360 ExpressionPiece GetExpressionBoolean(const char*& src) {
361   return GetExpressionBooleanLoopOr(
362       src,
363       GetExpressionBooleanLoopAnd(src, GetExpressionCondition(src)));
364 }
365 
GetExpression(const char * & src)366 ExpressionPiece GetExpression(const char*& src) {
367   return GetExpressionBoolean(src);
368 }
369 
370 // Parses an expression of the form [dest] = [source expression];
GetAssignment(const char * & src)371 ExpressionPiece GetAssignment(const char*& src) {
372   ExpressionPiece itok(GetExpressionTerm(src));
373   int op = src[1];
374   src += 2;
375   ExpressionPiece etok(GetExpression(src));
376   if (op >= 0x14 && op <= 0x24) {
377     return ExpressionPiece::BinaryExpression(
378         op, std::move(itok), std::move(etok));
379   } else {
380     throw Error("Undefined assignment in GetAssignment");
381   }
382 }
383 
384 // Parses a string in the parameter list.
GetString(const char * & src)385 static ExpressionPiece GetString(const char*& src) {
386   // Get the length of this string in the bytecode:
387   size_t length = NextString(src);
388 
389   string s;
390   // Check to see if the string is quoted;
391   if (src[0] == '"')
392     s = string(src + 1, src + length - 1);
393   else
394     s = string(src, src + length);
395 
396   // Increment the source by that many characters
397   src += length;
398 
399   // Unquote the internal quotations.
400   boost::replace_all(s, "\\\"", "\"");
401 
402   return ExpressionPiece::StrConstant(s);
403 }
404 
405 // Parses a parameter in the parameter list. This is the only method
406 // of all the get_*(const char*& src) functions that can parse
407 // strings. It also deals with things like special and complex
408 // parameters.
GetData(const char * & src)409 ExpressionPiece GetData(const char*& src) {
410   if (*src == ',') {
411     ++src;
412     return GetData(src);
413   } else if (*src == '\n') {
414     src += 3;
415     return GetData(src);
416   } else if ((*src >= 0x81 && *src <= 0x9f) || (*src >= 0xe0 && *src <= 0xef) ||
417              (*src >= 'A' && *src <= 'Z') || (*src >= '0' && *src <= '9') ||
418              *src == ' ' || *src == '?' || *src == '_' || *src == '"' ||
419              strcmp(src, "###PRINT(") == 0) {
420     return GetString(src);
421   } else if (*src == 'a') {
422     // TODO(erg): Cleanup below.
423     const char* end = src;
424 
425     ExpressionPiece cep = ExpressionPiece::ComplexExpression();
426 
427     if (*end++ == 'a') {
428       int tag = *end++;
429 
430       // Some special cases have multiple tags.
431       if (*end == 'a') {
432         end++;
433         int second = *end++;
434         tag = (second << 16) | tag;
435       }
436 
437       cep = ExpressionPiece::SpecialExpression(tag);
438 
439       if (*end != '(') {
440         // We have a single parameter in this special expression;
441         cep.AddContainedPiece(GetData(end));
442         return cep;
443       } else {
444         end++;
445       }
446     } else {
447       cep = ExpressionPiece::ComplexExpression();
448     }
449 
450     while (*end != ')') {
451       cep.AddContainedPiece(GetData(end));
452     }
453 
454     return cep;
455   } else {
456     return GetExpression(src);
457   }
458 }
459 
GetComplexParam(const char * & src)460 ExpressionPiece GetComplexParam(const char*& src) {
461   if (*src == ',') {
462     ++src;
463     return GetData(src);
464   } else if (*src == '(') {
465     ++src;
466     ExpressionPiece cep = ExpressionPiece::ComplexExpression();
467 
468     while (*src != ')')
469       cep.AddContainedPiece(GetData(src));
470 
471     return cep;
472   } else {
473     return GetExpression(src);
474   }
475 }
476 
EvaluatePRINT(RLMachine & machine,const std::string & in)477 std::string EvaluatePRINT(RLMachine& machine, const std::string& in) {
478   // Currently, this doesn't evaluate the # commands inline. See 5.12.11 of the
479   // rldev manual.
480   if (boost::starts_with(in, "###PRINT(")) {
481     const char* expression_start = in.c_str() + 9;
482     ExpressionPiece piece(GetExpression(expression_start));
483 
484     if (*expression_start != ')') {
485       std::ostringstream ss;
486       ss << "Unexpected character '" << *expression_start
487          << "' in evaluatePRINT (')' expected)";
488       throw Error(ss.str());
489     }
490 
491     return piece.GetStringValue(machine);
492   } else {
493     // Just a normal string we can ignore
494     return in;
495   }
496 }
497 
ParsableToPrintableString(const std::string & src)498 std::string ParsableToPrintableString(const std::string& src) {
499   string output;
500 
501   bool firstToken = true;
502   for (char tok : src) {
503     if (firstToken) {
504       firstToken = false;
505     } else {
506       output += " ";
507     }
508 
509     if (tok == '(' || tok == ')' || tok == '$' || tok == '[' || tok == ']') {
510       output.push_back(tok);
511     } else {
512       std::ostringstream ss;
513       ss << std::hex << std::setw(2) << std::setfill('0') << int(tok);
514       output += ss.str();
515     }
516   }
517 
518   return output;
519 }
520 
521 // -----------------------------------------------------------------------
522 
PrintableToParsableString(const std::string & src)523 std::string PrintableToParsableString(const std::string& src) {
524   typedef boost::tokenizer<boost::char_separator<char>> ttokenizer;
525 
526   std::string output;
527 
528   boost::char_separator<char> sep(" ");
529   ttokenizer tokens(src, sep);
530   for (string const& tok : tokens) {
531     if (tok.size() > 2)
532       throw libreallive::Error(
533           "Invalid string given to printableToParsableString");
534 
535     if (tok == "(" || tok == ")" || tok == "$" || tok == "[" || tok == "]") {
536       output.push_back(tok[0]);
537     } else {
538       int charToAdd;
539       std::istringstream ss(tok);
540       ss >> std::hex >> charToAdd;
541       output.push_back((char)charToAdd);
542     }
543   }
544 
545   return output;
546 }
547 
548 // ----------------------------------------------------------------------
549 
550 // OK: Here's the current things I need to do more:
551 //
552 // - I've written a move operator= (I've written the move ctor).
553 // - I need to write both the copy ctor and the copy operator=.
554 // - Lots of integration work still.
555 
556 
557 // static
StoreRegister()558 ExpressionPiece ExpressionPiece::StoreRegister() {
559   ExpressionPiece piece;
560   piece.piece_type = TYPE_STORE_REGISTER;
561   return piece;
562 }
563 
564 // static
IntConstant(const int constant)565 ExpressionPiece ExpressionPiece::IntConstant(const int constant) {
566   ExpressionPiece piece;
567   piece.piece_type = TYPE_INT_CONSTANT;
568   piece.int_constant = constant;
569   return piece;
570 }
571 
572 // static
StrConstant(const std::string constant)573 ExpressionPiece ExpressionPiece::StrConstant(const std::string constant) {
574   ExpressionPiece piece;
575   piece.piece_type = TYPE_STRING_CONSTANT;
576   new (&piece.str_constant) std::string(constant);
577   return piece;
578 }
579 
580 // static
MemoryReference(const int type,ExpressionPiece location)581 ExpressionPiece ExpressionPiece::MemoryReference(const int type,
582                                                  ExpressionPiece location) {
583   ExpressionPiece piece;
584   if (location.piece_type == TYPE_INT_CONSTANT) {
585     piece.piece_type = TYPE_SIMPLE_MEMORY_REFERENCE;
586     piece.simple_mem_reference.type = type;
587     piece.simple_mem_reference.location = location.int_constant;
588   } else {
589     piece.piece_type = TYPE_MEMORY_REFERENCE;
590     piece.mem_reference.type = type;
591     piece.mem_reference.location = new ExpressionPiece(std::move(location));
592   }
593   return piece;
594 }
595 
596 // static
UniaryExpression(const char operation,ExpressionPiece operand)597 ExpressionPiece ExpressionPiece::UniaryExpression(const char operation,
598                                                   ExpressionPiece operand) {
599   ExpressionPiece piece;
600   piece.piece_type = TYPE_UNIARY_EXPRESSION;
601   piece.uniary_expression.operation = operation;
602   piece.uniary_expression.operand = new ExpressionPiece(std::move(operand));
603   return piece;
604 }
605 
606 // static
BinaryExpression(const char operation,ExpressionPiece lhs,ExpressionPiece rhs)607 ExpressionPiece ExpressionPiece::BinaryExpression(const char operation,
608                                                   ExpressionPiece lhs,
609                                                   ExpressionPiece rhs) {
610   ExpressionPiece piece;
611   if (operation == 30 &&
612       lhs.piece_type == TYPE_SIMPLE_MEMORY_REFERENCE &&
613       rhs.piece_type == TYPE_INT_CONSTANT) {
614     // We can fast path so we don't allocate memory by stashing the memory
615     // reference and the value in this piece.
616     piece.piece_type = TYPE_SIMPLE_ASSIGNMENT;
617     piece.simple_assignment.type = lhs.simple_mem_reference.type;
618     piece.simple_assignment.location = lhs.simple_mem_reference.location;
619     piece.simple_assignment.value = rhs.int_constant;
620   } else if (lhs.piece_type == TYPE_INT_CONSTANT &&
621              rhs.piece_type == TYPE_INT_CONSTANT) {
622     // We can fast path so that we just compute the integer expression here.
623     piece.piece_type = TYPE_INT_CONSTANT;
624     piece.int_constant = PerformBinaryOperationOn(
625         operation,
626         lhs.int_constant,
627         rhs.int_constant);
628   } else {
629     piece.piece_type = TYPE_BINARY_EXPRESSION;
630     piece.binary_expression.operation = operation;
631     piece.binary_expression.left_operand = new ExpressionPiece(std::move(lhs));
632     piece.binary_expression.right_operand = new ExpressionPiece(std::move(rhs));
633   }
634   return piece;
635 }
636 
637 // static
ComplexExpression()638 ExpressionPiece ExpressionPiece::ComplexExpression() {
639   ExpressionPiece piece;
640   piece.piece_type = TYPE_COMPLEX_EXPRESSION;
641   new (&piece.complex_expression) std::vector<ExpressionPiece>();
642   return piece;
643 }
644 
645 // static
SpecialExpression(const int tag)646 ExpressionPiece ExpressionPiece::SpecialExpression(const int tag) {
647   ExpressionPiece piece;
648   piece.piece_type = TYPE_SPECIAL_EXPRESSION;
649   piece.special_expression.overload_tag = tag;
650   new (&piece.special_expression.pieces) std::vector<ExpressionPiece>();
651   return piece;
652 }
653 
ExpressionPiece(invalid_expression_piece_t)654 ExpressionPiece::ExpressionPiece(invalid_expression_piece_t)
655     : piece_type(TYPE_INVALID) {
656 }
657 
ExpressionPiece(const ExpressionPiece & rhs)658 ExpressionPiece::ExpressionPiece(const ExpressionPiece& rhs)
659     : piece_type(rhs.piece_type) {
660   switch (piece_type) {
661     case TYPE_STORE_REGISTER:
662       break;
663     case TYPE_INT_CONSTANT:
664       int_constant = rhs.int_constant;
665       break;
666     case TYPE_STRING_CONSTANT:
667       new (&str_constant) std::string(rhs.str_constant);
668       break;
669     case TYPE_MEMORY_REFERENCE:
670       mem_reference.type = rhs.mem_reference.type;
671       mem_reference.location =
672           new ExpressionPiece(*rhs.mem_reference.location);
673       break;
674     case TYPE_SIMPLE_MEMORY_REFERENCE:
675       simple_mem_reference.type = rhs.simple_mem_reference.type;
676       simple_mem_reference.location = rhs.simple_mem_reference.location;
677       break;
678     case TYPE_UNIARY_EXPRESSION:
679       uniary_expression.operation = rhs.uniary_expression.operation;
680       uniary_expression.operand =
681           new ExpressionPiece(*rhs.uniary_expression.operand);
682       break;
683     case TYPE_BINARY_EXPRESSION:
684       binary_expression.operation = rhs.binary_expression.operation;
685       binary_expression.left_operand =
686           new ExpressionPiece(*rhs.binary_expression.left_operand);
687       binary_expression.right_operand =
688           new ExpressionPiece(*rhs.binary_expression.right_operand);
689       break;
690     case TYPE_SIMPLE_ASSIGNMENT:
691       simple_assignment.type = rhs.simple_assignment.type;
692       simple_assignment.location = rhs.simple_assignment.location;
693       simple_assignment.value = rhs.simple_assignment.value;
694       break;
695     case TYPE_COMPLEX_EXPRESSION:
696       new (&complex_expression) std::vector<ExpressionPiece>(
697           rhs.complex_expression);
698       break;
699     case TYPE_SPECIAL_EXPRESSION:
700       special_expression.overload_tag = rhs.special_expression.overload_tag;
701       new (&special_expression.pieces) std::vector<ExpressionPiece>(
702           rhs.special_expression.pieces);
703       break;
704     case TYPE_INVALID:
705       break;
706   }
707 }
708 
ExpressionPiece(ExpressionPiece && rhs)709 ExpressionPiece::ExpressionPiece(ExpressionPiece&& rhs)
710     : piece_type(rhs.piece_type) {
711   switch (piece_type) {
712     case TYPE_STORE_REGISTER:
713       break;
714     case TYPE_INT_CONSTANT:
715       int_constant = rhs.int_constant;
716       break;
717     case TYPE_STRING_CONSTANT:
718       new (&str_constant) std::string(std::move(rhs.str_constant));
719       break;
720     case TYPE_MEMORY_REFERENCE:
721       mem_reference.type = rhs.mem_reference.type;
722       mem_reference.location = rhs.mem_reference.location;
723       rhs.mem_reference.location = nullptr;
724       break;
725     case TYPE_SIMPLE_MEMORY_REFERENCE:
726       simple_mem_reference.type = rhs.simple_mem_reference.type;
727       simple_mem_reference.location = rhs.simple_mem_reference.location;
728       break;
729     case TYPE_UNIARY_EXPRESSION:
730       uniary_expression.operation = rhs.uniary_expression.operation;
731       uniary_expression.operand = rhs.uniary_expression.operand;
732       rhs.uniary_expression.operand = nullptr;
733       break;
734     case TYPE_BINARY_EXPRESSION:
735       binary_expression.operation = rhs.binary_expression.operation;
736       binary_expression.left_operand = rhs.binary_expression.left_operand;
737       binary_expression.right_operand = rhs.binary_expression.right_operand;
738       rhs.binary_expression.left_operand = nullptr;
739       rhs.binary_expression.right_operand = nullptr;
740       break;
741     case TYPE_SIMPLE_ASSIGNMENT:
742       simple_assignment.type = rhs.simple_assignment.type;
743       simple_assignment.location = rhs.simple_assignment.location;
744       simple_assignment.value = rhs.simple_assignment.value;
745       break;
746     case TYPE_COMPLEX_EXPRESSION:
747       new (&complex_expression) std::vector<ExpressionPiece>(std::move(
748           rhs.complex_expression));
749       break;
750     case TYPE_SPECIAL_EXPRESSION:
751       special_expression.overload_tag = rhs.special_expression.overload_tag;
752       new (&special_expression.pieces) std::vector<ExpressionPiece>(std::move(
753           rhs.special_expression.pieces));
754       break;
755     case TYPE_INVALID:
756       break;
757   }
758 
759   rhs.piece_type = TYPE_INVALID;
760 }
761 
~ExpressionPiece()762 ExpressionPiece::~ExpressionPiece() {
763   Invalidate();
764 }
765 
operator =(const ExpressionPiece & rhs)766 ExpressionPiece& ExpressionPiece::operator=(const ExpressionPiece& rhs) {
767   Invalidate();
768 
769   piece_type = rhs.piece_type;
770   switch (piece_type) {
771     case TYPE_STORE_REGISTER:
772       break;
773     case TYPE_INT_CONSTANT:
774       int_constant = rhs.int_constant;
775       break;
776     case TYPE_STRING_CONSTANT:
777       new (&str_constant) std::string(rhs.str_constant);
778       break;
779     case TYPE_MEMORY_REFERENCE:
780       mem_reference.type = rhs.mem_reference.type;
781       mem_reference.location =
782           new ExpressionPiece(*rhs.mem_reference.location);
783       break;
784     case TYPE_SIMPLE_MEMORY_REFERENCE:
785       simple_mem_reference.type = rhs.simple_mem_reference.type;
786       simple_mem_reference.location = rhs.simple_mem_reference.location;
787       break;
788     case TYPE_UNIARY_EXPRESSION:
789       uniary_expression.operation = rhs.uniary_expression.operation;
790       uniary_expression.operand =
791           new ExpressionPiece(*rhs.uniary_expression.operand);
792       break;
793     case TYPE_BINARY_EXPRESSION:
794       binary_expression.operation = rhs.binary_expression.operation;
795       binary_expression.left_operand =
796           new ExpressionPiece(*rhs.binary_expression.left_operand);
797       binary_expression.right_operand =
798           new ExpressionPiece(*rhs.binary_expression.right_operand);
799       break;
800     case TYPE_SIMPLE_ASSIGNMENT:
801       simple_assignment.type = rhs.simple_assignment.type;
802       simple_assignment.location = rhs.simple_assignment.location;
803       simple_assignment.value = rhs.simple_assignment.value;
804       break;
805     case TYPE_COMPLEX_EXPRESSION:
806       new (&complex_expression) std::vector<ExpressionPiece>(
807           rhs.complex_expression);
808       break;
809     case TYPE_SPECIAL_EXPRESSION:
810       special_expression.overload_tag = rhs.special_expression.overload_tag;
811       new (&special_expression.pieces) std::vector<ExpressionPiece>(
812           rhs.special_expression.pieces);
813       break;
814     case TYPE_INVALID:
815       break;
816   }
817 
818   return *this;
819 }
820 
operator =(ExpressionPiece && rhs)821 ExpressionPiece& ExpressionPiece::operator=(ExpressionPiece&& rhs) {
822   Invalidate();
823 
824   piece_type = rhs.piece_type;
825   switch (piece_type) {
826     case TYPE_STORE_REGISTER:
827       break;
828     case TYPE_INT_CONSTANT:
829       int_constant = rhs.int_constant;
830       break;
831     case TYPE_STRING_CONSTANT:
832       new (&str_constant) std::string(std::move(rhs.str_constant));
833       break;
834     case TYPE_MEMORY_REFERENCE:
835       mem_reference.type = rhs.mem_reference.type;
836       mem_reference.location = rhs.mem_reference.location;
837       rhs.mem_reference.location = nullptr;
838       break;
839     case TYPE_SIMPLE_MEMORY_REFERENCE:
840       simple_mem_reference.type = rhs.simple_mem_reference.type;
841       simple_mem_reference.location = rhs.simple_mem_reference.location;
842       break;
843     case TYPE_UNIARY_EXPRESSION:
844       uniary_expression.operation = rhs.uniary_expression.operation;
845       uniary_expression.operand = rhs.uniary_expression.operand;
846       rhs.uniary_expression.operand = nullptr;
847       break;
848     case TYPE_BINARY_EXPRESSION:
849       binary_expression.operation = rhs.binary_expression.operation;
850       binary_expression.left_operand = rhs.binary_expression.left_operand;
851       binary_expression.right_operand = rhs.binary_expression.right_operand;
852       rhs.binary_expression.left_operand = nullptr;
853       rhs.binary_expression.right_operand = nullptr;
854       break;
855     case TYPE_SIMPLE_ASSIGNMENT:
856       simple_assignment.type = rhs.simple_assignment.type;
857       simple_assignment.location = rhs.simple_assignment.location;
858       simple_assignment.value = rhs.simple_assignment.value;
859       break;
860     case TYPE_COMPLEX_EXPRESSION:
861       new (&complex_expression) std::vector<ExpressionPiece>(std::move(
862           rhs.complex_expression));
863       break;
864     case TYPE_SPECIAL_EXPRESSION:
865       special_expression.overload_tag = rhs.special_expression.overload_tag;
866       new (&special_expression.pieces) std::vector<ExpressionPiece>(std::move(
867           rhs.special_expression.pieces));
868       break;
869     case TYPE_INVALID:
870       break;
871   }
872 
873   rhs.piece_type = TYPE_INVALID;
874 
875   return *this;
876 }
877 
IsMemoryReference() const878 bool ExpressionPiece::IsMemoryReference() const {
879   return piece_type == TYPE_STORE_REGISTER ||
880       piece_type == TYPE_MEMORY_REFERENCE ||
881       piece_type == TYPE_SIMPLE_MEMORY_REFERENCE;
882 }
883 
IsComplexParameter() const884 bool ExpressionPiece::IsComplexParameter() const {
885   return piece_type == TYPE_COMPLEX_EXPRESSION;
886 }
887 
IsSpecialParameter() const888 bool ExpressionPiece::IsSpecialParameter() const {
889   return piece_type == TYPE_SPECIAL_EXPRESSION;
890 }
891 
GetExpressionValueType() const892 ExpressionValueType ExpressionPiece::GetExpressionValueType() const {
893   switch (piece_type) {
894     case TYPE_STRING_CONSTANT:
895       return ValueTypeString;
896     case TYPE_MEMORY_REFERENCE:
897       return is_string_location(mem_reference.type) ?
898           ValueTypeString : ValueTypeInteger;
899     case TYPE_SIMPLE_MEMORY_REFERENCE:
900       return is_string_location(simple_mem_reference.type) ?
901           ValueTypeString : ValueTypeInteger;
902     default:
903       return ValueTypeInteger;
904   }
905 }
906 
SetIntegerValue(RLMachine & machine,int rvalue)907 void ExpressionPiece::SetIntegerValue(RLMachine& machine, int rvalue) {
908   switch (piece_type) {
909     case TYPE_STORE_REGISTER:
910       machine.set_store_register(rvalue);
911       break;
912     case TYPE_MEMORY_REFERENCE:
913       machine.SetIntValue(
914           IntMemRef(
915               mem_reference.type,
916               mem_reference.location->GetIntegerValue(machine)),
917           rvalue);
918       break;
919     case TYPE_SIMPLE_MEMORY_REFERENCE:
920       machine.SetIntValue(
921           IntMemRef(
922               simple_mem_reference.type,
923               simple_mem_reference.location),
924           rvalue);
925       break;
926     default: {
927       std::ostringstream ss;
928       ss << "ExpressionPiece::SetIntegerValue() invalid on object of type "
929          << piece_type;
930       throw Error(ss.str());
931     }
932   }
933 }
934 
GetIntegerValue(RLMachine & machine) const935 int ExpressionPiece::GetIntegerValue(RLMachine& machine) const {
936   switch (piece_type) {
937     case TYPE_STORE_REGISTER:
938       return machine.store_register();
939     case TYPE_INT_CONSTANT:
940       return int_constant;
941     case TYPE_MEMORY_REFERENCE:
942       return machine.GetIntValue(IntMemRef(
943           mem_reference.type,
944           mem_reference.location->GetIntegerValue(machine)));
945     case TYPE_SIMPLE_MEMORY_REFERENCE:
946       return machine.GetIntValue(IntMemRef(
947           simple_mem_reference.type,
948           simple_mem_reference.location));
949     case TYPE_UNIARY_EXPRESSION:
950       return PerformUniaryOperationOn(
951           uniary_expression.operand->GetIntegerValue(machine));
952     case TYPE_BINARY_EXPRESSION:
953       if (binary_expression.operation >= 20 &&
954           binary_expression.operation < 30) {
955         int value = PerformBinaryOperationOn(
956             binary_expression.operation,
957             binary_expression.left_operand->GetIntegerValue(machine),
958             binary_expression.right_operand->GetIntegerValue(machine));
959         binary_expression.left_operand->SetIntegerValue(machine, value);
960         return value;
961       } else if (binary_expression.operation == 30) {
962         int value = binary_expression.right_operand->GetIntegerValue(machine);
963         binary_expression.left_operand->SetIntegerValue(machine, value);
964         return value;
965       } else {
966         return PerformBinaryOperationOn(
967             binary_expression.operation,
968             binary_expression.left_operand->GetIntegerValue(machine),
969             binary_expression.right_operand->GetIntegerValue(machine));
970       }
971     case TYPE_SIMPLE_ASSIGNMENT:
972       machine.SetIntValue(
973           IntMemRef(simple_assignment.type,
974                     simple_assignment.location),
975           simple_assignment.value);
976       return simple_assignment.value;
977     default: {
978       std::ostringstream ss;
979       ss << "ExpressionPiece::GetIntegerValue() invalid on object of type "
980          << piece_type;
981       throw Error(ss.str());
982     }
983   }
984 }
985 
SetStringValue(RLMachine & machine,const std::string & rvalue)986 void ExpressionPiece::SetStringValue(RLMachine& machine,
987                                      const std::string& rvalue) {
988   switch (piece_type) {
989     case TYPE_MEMORY_REFERENCE:
990       machine.SetStringValue(mem_reference.type,
991                              mem_reference.location->GetIntegerValue(machine),
992                              rvalue);
993       return;
994     case TYPE_SIMPLE_MEMORY_REFERENCE:
995       machine.SetStringValue(simple_mem_reference.type,
996                              simple_mem_reference.location,
997                              rvalue);
998       return;
999     default:
1000       throw libreallive::Error(
1001           "ExpressionPiece::SetStringValue() invalid on this object");
1002   }
1003 }
1004 
GetStringValue(RLMachine & machine) const1005 const std::string& ExpressionPiece::GetStringValue(RLMachine& machine) const {
1006   switch (piece_type) {
1007     case TYPE_STRING_CONSTANT:
1008       return str_constant;
1009     case TYPE_MEMORY_REFERENCE:
1010       return machine.GetStringValue(mem_reference.type,
1011                                     mem_reference.location->GetIntegerValue(
1012                                         machine));
1013     case TYPE_SIMPLE_MEMORY_REFERENCE:
1014       return machine.GetStringValue(simple_mem_reference.type,
1015                                     simple_mem_reference.location);
1016     default:
1017       throw libreallive::Error(
1018           "ExpressionPiece::GetStringValue() invalid on this object");
1019   }
1020 }
1021 
GetIntegerReferenceIterator(RLMachine & machine) const1022 IntReferenceIterator ExpressionPiece::GetIntegerReferenceIterator(
1023     RLMachine& machine) const {
1024   switch (piece_type) {
1025     case TYPE_STORE_REGISTER:
1026       return IntReferenceIterator(machine.store_register_address());
1027     case TYPE_MEMORY_REFERENCE:
1028       // Make sure that we are actually referencing an integer
1029       if (is_string_location(mem_reference.type)) {
1030         throw Error(
1031             "Request to GetIntegerReferenceIterator() on a string reference!");
1032       }
1033 
1034       return IntReferenceIterator(
1035           &machine.memory(),
1036           mem_reference.type,
1037           mem_reference.location->GetIntegerValue(machine));
1038     case TYPE_SIMPLE_MEMORY_REFERENCE:
1039       // Make sure that we are actually referencing an integer
1040       if (is_string_location(simple_mem_reference.type)) {
1041         throw Error(
1042             "Request to GetIntegerReferenceIterator() on a string reference!");
1043       }
1044 
1045       return IntReferenceIterator(
1046           &machine.memory(),
1047           simple_mem_reference.type,
1048           simple_mem_reference.location);
1049     default:
1050       throw libreallive::Error(
1051           "ExpressionPiece::GetIntegerReferenceIterator() invalid on this object");
1052   }
1053 }
1054 
GetStringReferenceIterator(RLMachine & machine) const1055 StringReferenceIterator ExpressionPiece::GetStringReferenceIterator(
1056     RLMachine& machine) const {
1057   switch (piece_type) {
1058     case TYPE_MEMORY_REFERENCE:
1059       // Make sure that we are actually referencing an integer
1060       if (!is_string_location(mem_reference.type)) {
1061         throw Error(
1062             "Request to GetStringReferenceIterator() on an integer reference!");
1063       }
1064 
1065       return StringReferenceIterator(
1066           &machine.memory(),
1067           mem_reference.type,
1068           mem_reference.location->GetIntegerValue(machine));
1069     case TYPE_SIMPLE_MEMORY_REFERENCE:
1070       // Make sure that we are actually referencing an integer
1071       if (!is_string_location(simple_mem_reference.type)) {
1072         throw Error(
1073             "Request to GetStringReferenceIterator() on an integer reference!");
1074       }
1075 
1076       return StringReferenceIterator(
1077           &machine.memory(),
1078           simple_mem_reference.type,
1079           simple_mem_reference.location);
1080     default:
1081       throw libreallive::Error("ExpressionPiece::GetStringReferenceIterator()"
1082                                " invalid on this object");
1083   }
1084 }
1085 
GetSerializedExpression(RLMachine & machine) const1086 std::string ExpressionPiece::GetSerializedExpression(RLMachine& machine) const {
1087   switch (piece_type) {
1088     case TYPE_STORE_REGISTER:
1089       return IntToBytecode(machine.store_register());
1090     case TYPE_INT_CONSTANT:
1091       return IntToBytecode(int_constant);
1092     case TYPE_STRING_CONSTANT:
1093       return string("\"") + str_constant + string("\"");
1094     case TYPE_MEMORY_REFERENCE:
1095       if (is_string_location(mem_reference.type)) {
1096         return string("\"") + GetStringValue(machine) + string("\"");
1097       } else {
1098         return IntToBytecode(GetIntegerValue(machine));
1099       }
1100     case TYPE_SIMPLE_MEMORY_REFERENCE:
1101       if (is_string_location(simple_mem_reference.type)) {
1102         return string("\"") + GetStringValue(machine) + string("\"");
1103       } else {
1104         return IntToBytecode(GetIntegerValue(machine));
1105       }
1106     case TYPE_UNIARY_EXPRESSION:
1107     case TYPE_BINARY_EXPRESSION:
1108     case TYPE_SIMPLE_ASSIGNMENT:
1109       return IntToBytecode(GetIntegerValue(machine));
1110     case TYPE_COMPLEX_EXPRESSION:
1111       return GetComplexSerializedExpression(machine);
1112     case TYPE_SPECIAL_EXPRESSION:
1113       return GetSpecialSerializedExpression(machine);
1114     case TYPE_INVALID:
1115       throw Error("Called GetSerializedExpression on an invalid piece.");
1116   }
1117 
1118   return "<invalid>";
1119 }
1120 
GetDebugString() const1121 std::string ExpressionPiece::GetDebugString() const {
1122   switch (piece_type) {
1123     case TYPE_STORE_REGISTER:
1124       return "<store>";
1125     case TYPE_INT_CONSTANT:
1126       return std::to_string(int_constant);
1127     case TYPE_STRING_CONSTANT:
1128       return string("\"") + str_constant + string("\"");
1129     case TYPE_MEMORY_REFERENCE:
1130       return GetMemoryDebugString(mem_reference.type,
1131                                   mem_reference.location->GetDebugString());
1132     case TYPE_SIMPLE_MEMORY_REFERENCE:
1133       return GetMemoryDebugString(
1134           simple_mem_reference.type,
1135           std::to_string(simple_mem_reference.location));
1136     case TYPE_UNIARY_EXPRESSION:
1137       return GetUniaryDebugString();
1138     case TYPE_BINARY_EXPRESSION:
1139       return GetBinaryDebugString(
1140           binary_expression.operation,
1141           binary_expression.left_operand->GetDebugString(),
1142           binary_expression.right_operand->GetDebugString());
1143     case TYPE_SIMPLE_ASSIGNMENT:
1144       return GetBinaryDebugString(
1145           30,
1146           GetMemoryDebugString(simple_assignment.type,
1147                                std::to_string(simple_assignment.location)),
1148           std::to_string(simple_assignment.value));
1149     case TYPE_COMPLEX_EXPRESSION:
1150       return GetComplexDebugString();
1151     case TYPE_SPECIAL_EXPRESSION:
1152       return GetSpecialDebugString();
1153     case TYPE_INVALID:
1154       return "<invalid>";
1155   }
1156 
1157   return "<invalid>";
1158 }
1159 
1160 // -----------------------------------------------------------------------------
1161 
ExpressionPiece()1162 ExpressionPiece::ExpressionPiece() : piece_type(TYPE_INVALID) {}
1163 
Invalidate()1164 void ExpressionPiece::Invalidate() {
1165   // Needed to get around a quirk of the language
1166   using string_type = std::string;
1167   using vec_type = std::vector<ExpressionPiece>;
1168 
1169   switch (piece_type) {
1170     case TYPE_STORE_REGISTER:
1171     case TYPE_INT_CONSTANT:
1172       break;
1173     case TYPE_STRING_CONSTANT:
1174       str_constant.~string_type();
1175       break;
1176     case TYPE_MEMORY_REFERENCE:
1177       delete mem_reference.location;
1178       break;
1179     case TYPE_SIMPLE_MEMORY_REFERENCE:
1180       break;
1181     case TYPE_UNIARY_EXPRESSION:
1182       delete uniary_expression.operand;
1183       break;
1184     case TYPE_BINARY_EXPRESSION:
1185       delete binary_expression.left_operand;
1186       delete binary_expression.right_operand;
1187       break;
1188     case TYPE_SIMPLE_ASSIGNMENT:
1189       break;
1190     case TYPE_COMPLEX_EXPRESSION:
1191       complex_expression.~vec_type();
1192       break;
1193     case TYPE_SPECIAL_EXPRESSION:
1194       special_expression.pieces.~vec_type();
1195       break;
1196     case TYPE_INVALID:
1197       break;
1198   }
1199 }
1200 
1201 // -----------------------------------------------------------------------------
1202 
GetComplexSerializedExpression(RLMachine & machine) const1203 std::string ExpressionPiece::GetComplexSerializedExpression(
1204     RLMachine& machine) const {
1205   string s("(");
1206   for (auto const& piece : complex_expression) {
1207     s += "(";
1208     s += piece.GetSerializedExpression(machine);
1209     s += ")";
1210   }
1211   s += ")";
1212   return s;
1213 }
1214 
GetSpecialSerializedExpression(RLMachine & machine) const1215 std::string ExpressionPiece::GetSpecialSerializedExpression(
1216     RLMachine& machine) const {
1217   string s("a");
1218   s += char(special_expression.overload_tag);
1219 
1220   if (special_expression.pieces.size() > 1)
1221     s.append("(");
1222   for (auto const& piece : special_expression.pieces) {
1223     s += piece.GetSerializedExpression(machine);
1224   }
1225   if (special_expression.pieces.size() > 1)
1226     s.append(")");
1227 
1228   return s;
1229 }
1230 
GetMemoryDebugString(int type,const std::string & location) const1231 std::string ExpressionPiece::GetMemoryDebugString(
1232     int type,
1233     const std::string& location) const {
1234   std::ostringstream ret;
1235 
1236   if (type == STRS_LOCATION) {
1237     ret << "strS[";
1238   } else if (type == STRK_LOCATION) {
1239     ret << "strK[";
1240   } else if (type == STRM_LOCATION) {
1241     ret << "strM[";
1242   } else if (type == INTZ_LOCATION_IN_BYTECODE) {
1243     ret << "intZ[";
1244   } else if (type == INTL_LOCATION_IN_BYTECODE) {
1245     ret << "intL[";
1246   } else {
1247     char bank = 'A' + (type % 26);
1248     ret << "int" << bank << "[";
1249   }
1250 
1251   ret << location;
1252 
1253   ret << "]";
1254   return ret.str();
1255 }
1256 
GetUniaryDebugString() const1257 std::string ExpressionPiece::GetUniaryDebugString() const {
1258   std::ostringstream str;
1259   if (uniary_expression.operation == 0x01) {
1260     str << "-";
1261   }
1262   str << uniary_expression.operand->GetDebugString();
1263 
1264   return str.str();
1265 }
1266 
GetBinaryDebugString(char operation,const std::string & lhs,const std::string & rhs) const1267 std::string ExpressionPiece::GetBinaryDebugString(
1268     char operation,
1269     const std::string& lhs,
1270     const std::string& rhs) const {
1271   std::ostringstream str;
1272   str << lhs;
1273   str << " ";
1274 
1275   switch (operation) {
1276     case 0:
1277     case 20:
1278       str << "+";
1279       break;
1280     case 1:
1281     case 21:
1282       str << "-";
1283       break;
1284     case 2:
1285     case 22:
1286       str << "*";
1287       break;
1288     case 3:
1289     case 23:
1290       str << "/";
1291       break;
1292     case 4:
1293     case 24:
1294       str << "%";
1295       break;
1296     case 5:
1297     case 25:
1298       str << "&";
1299       break;
1300     case 6:
1301     case 26:
1302       str << "|";
1303       break;
1304     case 7:
1305     case 27:
1306       str << "^";
1307       break;
1308     case 8:
1309     case 28:
1310       str << "<<";
1311       break;
1312     case 9:
1313     case 29:
1314       str << ">>";
1315       break;
1316     case 30:
1317       str << "=";
1318       break;
1319     case 40:
1320       str << "==";
1321       break;
1322     case 41:
1323       str << "!=";
1324       break;
1325     case 42:
1326       str << "<=";
1327       break;
1328     case 43:
1329       str << "< ";
1330       break;
1331     case 44:
1332       str << ">=";
1333       break;
1334     case 45:
1335       str << "> ";
1336       break;
1337     case 60:
1338       str << "&&";
1339       break;
1340     case 61:
1341       str << "||";
1342       break;
1343     default: {
1344       std::ostringstream ss;
1345       ss << "Invalid operator "
1346          << static_cast<int>(binary_expression.operation)
1347          << " in expression!";
1348       throw Error(ss.str());
1349     }
1350   }
1351 
1352   if (operation >= 0x14 && operation != 30)
1353     str << "=";
1354 
1355   str << " ";
1356   str << rhs;
1357 
1358   return str.str();
1359 }
1360 
GetComplexDebugString() const1361 std::string ExpressionPiece::GetComplexDebugString() const {
1362   string s("(");
1363   for (auto const& piece : complex_expression) {
1364     s += "(";
1365     s += piece.GetDebugString();
1366     s += ")";
1367   }
1368   s += ")";
1369   return s;
1370 }
1371 
GetSpecialDebugString() const1372 std::string ExpressionPiece::GetSpecialDebugString() const {
1373   std::ostringstream oss;
1374 
1375   oss << int(special_expression.overload_tag) << ":{";
1376 
1377   bool first = true;
1378   for (auto const& piece : special_expression.pieces) {
1379     if (!first) {
1380       oss << ", ";
1381     } else {
1382       first = false;
1383     }
1384 
1385     oss << piece.GetDebugString();
1386   }
1387   oss << "}";
1388 
1389   return oss.str();
1390 }
1391 
PerformUniaryOperationOn(int int_operand) const1392 int ExpressionPiece::PerformUniaryOperationOn(int int_operand) const {
1393   int result = int_operand;
1394   switch (uniary_expression.operation) {
1395     case 0x01:
1396       result = -int_operand;
1397       break;
1398     default:
1399       break;
1400   }
1401 
1402   return result;
1403 }
1404 
1405 // Stolen from xclannad
1406 // static
PerformBinaryOperationOn(char operation,int lhs,int rhs)1407 int ExpressionPiece::PerformBinaryOperationOn(char operation,
1408                                               int lhs, int rhs) {
1409   switch (operation) {
1410     case 0:
1411     case 20:
1412       return lhs + rhs;
1413     case 1:
1414     case 21:
1415       return lhs - rhs;
1416     case 2:
1417     case 22:
1418       return lhs * rhs;
1419     case 3:
1420     case 23:
1421       return rhs != 0 ? lhs / rhs : lhs;
1422     case 4:
1423     case 24:
1424       return rhs != 0 ? lhs % rhs : lhs;
1425     case 5:
1426     case 25:
1427       return lhs & rhs;
1428     case 6:
1429     case 26:
1430       return lhs | rhs;
1431     case 7:
1432     case 27:
1433       return lhs ^ rhs;
1434     case 8:
1435     case 28:
1436       return lhs << rhs;
1437     case 9:
1438     case 29:
1439       return lhs >> rhs;
1440     case 40:
1441       return lhs == rhs;
1442     case 41:
1443       return lhs != rhs;
1444     case 42:
1445       return lhs <= rhs;
1446     case 43:
1447       return lhs < rhs;
1448     case 44:
1449       return lhs >= rhs;
1450     case 45:
1451       return lhs > rhs;
1452     case 60:
1453       return lhs && rhs;
1454     case 61:
1455       return lhs || rhs;
1456     default: {
1457       std::ostringstream ss;
1458       ss << "Invalid operator "
1459          << static_cast<int>(operation)
1460          << " in expression!";
1461       throw Error(ss.str());
1462     }
1463   }
1464 }
1465 
1466 // -----------------------------------------------------------------------
1467 
AddContainedPiece(ExpressionPiece piece)1468 void ExpressionPiece::AddContainedPiece(ExpressionPiece piece) {
1469   switch (piece_type) {
1470     case TYPE_COMPLEX_EXPRESSION:
1471       complex_expression.emplace_back(piece);
1472       break;
1473     case TYPE_SPECIAL_EXPRESSION:
1474       special_expression.pieces.emplace_back(piece);
1475       break;
1476     default:
1477       throw Error("Request to AddContainedPiece() invalid!");
1478   }
1479 }
1480 
1481 const std::vector<ExpressionPiece>&
GetContainedPieces() const1482 ExpressionPiece::GetContainedPieces() const {
1483   switch (piece_type) {
1484     case TYPE_COMPLEX_EXPRESSION:
1485       return complex_expression;
1486     case TYPE_SPECIAL_EXPRESSION:
1487       return special_expression.pieces;
1488     default:
1489       throw Error("Request to AddContainedPiece() invalid!");
1490   }
1491 }
1492 
GetOverloadTag() const1493 int ExpressionPiece::GetOverloadTag() const {
1494   switch (piece_type) {
1495     case TYPE_SPECIAL_EXPRESSION:
1496       return special_expression.overload_tag;
1497     default:
1498       throw Error("Request to GetOverloadTag() invalid!");
1499   }
1500 }
1501 
1502 }  // namespace libreallive
1503