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