#include "Decompiler.hpp"
namespace MobileBasic {
using namespace std;
const string Decompiler::decompile(Basic &basic, bool append_nl) {
unsigned short line_num;
unsigned char line_length, token_id;
string source_out = "";
BinaryReader code;
code.setData(basic.code, basic.meta.code_size);
try {
while (!code.isEOF()) {
line_num = code.readShort();
line_length = code.readByte();
source_out.append(to_string(line_num)).append(1, ' ');
size_t line_length_start = code.getOffset();
for (unsigned char i = line_length_start; i < line_length_start + line_length - 3; ++i) {
token_id = code.readByte();
switch (token_id) {
case Basic::TOK_ASSIGN:
source_out.append(1, '=');
break;
case Basic::TOK_MAKEREF:
break;
case Basic::TOK_EOS:
if (append_nl)
source_out.append("\r\n");
break;
case Basic::TOK_VARIABLE:
{
unsigned char var_id = code.readByte();
if (var_id >= basic.vars.size())
DECOMP_ERROR("Unknown variable with id=%d", E_UNKNOWN_VARIABLE, var_id);
source_out.append(basic.vars[var_id].name);
}
break;
case Basic::TOK_DATA:
MB_CONST_STRING_DATA(code, false, "DATA ", source_out);
break;
case Basic::TOK_REM:
MB_CONST_STRING_DATA(code, false, "REM ", source_out);
break;
case Basic::TOK_STRING:
MB_CONST_STRING_DATA(code, true, NULL, source_out);
break;
case Basic::TOK_BYTE:
source_out.append(to_string(code.readSByte()));
break;
case Basic::TOK_UBYTE:
source_out.append(to_string(code.readByte()));
break;
case Basic::TOK_UWORD:
source_out.append(to_string(code.readUShort()));
break;
case Basic::TOK_FLOAT:
if (basic.meta.version == Basic::MAGIC_MB_0191) {
unsigned char var_id = code.readByte();
if (var_id >= basic.meta.float_num)
DECOMP_ERROR("Unknown float with id=%d", E_UNKNOWN_VARIABLE, var_id);
source_out.append(to_string(basic.floats[var_id]));
} else
source_out.append(to_string(unpack_float(code.readUInt())));
break;
case Basic::TOK_INTEGER:
source_out.append(to_string(code.readUInt()));
break;
default:
unsigned int attr = TKN_GET_ATTR(Basic::basic_tokens[token_id].attributes);
if ((attr & Basic::ATTR_PRINT_BEFORE_THIS))
source_out.append(1, ' ');
source_out.append(Basic::basic_tokens[token_id].name);
if ((attr & Basic::ATTR_PRINT_SPACE_AFTER_GEN))
source_out.append(1, ' ');
break;
}
if (token_id == Basic::TOK_EOS)
break;
}
}
} catch (BinaryReaderException &ex) {
DECOMP_ERROR("Parse error[%d]: %s", E_PARSE, ex.getCode(), ex.getMessage());
}
return source_out;
}
}; // MobileBasic