[FEAT] Implemented 'if' support
[BUG] Variables inside blocks couldn't shadow those outside [FEAT] Decompiler shows address of each opcode
This commit is contained in:
@@ -1,10 +1,20 @@
|
||||
NOP
|
||||
NOP
|
||||
PUSH 4
|
||||
LD 72
|
||||
LD 60
|
||||
MUL
|
||||
SUB
|
||||
ST 144
|
||||
STL 4
|
||||
STL 0
|
||||
0000: NOP
|
||||
0001: NOP
|
||||
0002: PUSH 4
|
||||
0007: LD 72
|
||||
0012: LD 60
|
||||
0017: MUL
|
||||
0018: SUB
|
||||
0019: ST 144
|
||||
0024: RET
|
||||
0025: STL 4
|
||||
0030: STL 0
|
||||
0035: LDL 8
|
||||
0040: PUSH 0
|
||||
0045: GT
|
||||
0046: JNT 66
|
||||
0051: PUSH 1
|
||||
0056: STL 12
|
||||
0061: JMP 76
|
||||
0066: PUSH 2
|
||||
0071: STL 16
|
||||
|
||||
@@ -4,10 +4,22 @@
|
||||
#include <string.h>
|
||||
#include "parser.h"
|
||||
|
||||
#define SIMPLE(X) f << X << std::endl; pos++; break
|
||||
#define SIMPLE(X) f << get_address(pos) << ": " << X << std::endl; pos++; break
|
||||
// [RZC 05/05/2021] To solve alignment problems on ARM architectures we have to first copy the 4 bytes to an aligned byte array, then cast it to float
|
||||
#define FVAR(X) memcpy(data, &code[pos+1], 4); f << X << " " << *((float*)data) << std::endl; pos += 5; break
|
||||
#define IVAR(X) memcpy(data, &code[pos+1], 4); f << X << " " << *((uint32_t*)data) << std::endl; pos += 5; break
|
||||
#define FVAR(X) memcpy(data, &code[pos+1], 4); f << get_address(pos) << ": " << X << " " << *((float*)data) << std::endl; pos += 5; break
|
||||
#define IVAR(X) memcpy(data, &code[pos+1], 4); f << get_address(pos) << ": " << X << " " << *((uint32_t*)data) << std::endl; pos += 5; break
|
||||
|
||||
static std::string get_address(const int pos) {
|
||||
std::string label = "0000";
|
||||
int value = pos;
|
||||
int i = 3;
|
||||
while (value > 0) {
|
||||
label[i] = 48 + (value % 10);
|
||||
value = value / 10;
|
||||
i--;
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
void decompiler_save(const uint8_t *code, const int size) {
|
||||
uint8_t data[4];
|
||||
|
||||
150
parser.cpp
150
parser.cpp
@@ -8,7 +8,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
#include "decompiler.h"
|
||||
|
||||
#define MAX_CODE_SIZE 65536
|
||||
@@ -19,36 +21,12 @@
|
||||
#define MAX_CONSTANTS 256
|
||||
#define MAX_STRUCT_MEMBERS 10
|
||||
|
||||
/*
|
||||
struct t_variable {
|
||||
char name[MAX_IDENTIFIER_LENGTH];
|
||||
int type;
|
||||
int length;
|
||||
int address;
|
||||
};
|
||||
|
||||
struct t_struct {
|
||||
char name[MAX_IDENTIFIER_LENGTH];
|
||||
int num_members;
|
||||
t_variable members[MAX_STRUCT_MEMBERS];
|
||||
};
|
||||
|
||||
struct t_scope {
|
||||
|
||||
};
|
||||
*/
|
||||
|
||||
struct t_label {
|
||||
char name[MAX_IDENTIFIER_LENGTH];
|
||||
word address;
|
||||
std::string name;
|
||||
uint32_t address;
|
||||
};
|
||||
|
||||
/*struct t_variable {
|
||||
char name[MAX_IDENTIFIER_LENGTH];
|
||||
int index = 0;
|
||||
int size = 1;
|
||||
t_variable* next{ nullptr };
|
||||
};
|
||||
/*
|
||||
|
||||
struct t_external_function {
|
||||
char name[MAX_IDENTIFIER_LENGTH];
|
||||
@@ -60,25 +38,21 @@ struct t_string {
|
||||
word references[256];
|
||||
int num_references = 1;
|
||||
};
|
||||
|
||||
struct t_constant {
|
||||
char name[MAX_IDENTIFIER_LENGTH];
|
||||
byte value;
|
||||
};*/
|
||||
*/
|
||||
|
||||
static byte* code; // [MAX_CODE_SIZE];
|
||||
static uint32_t codepos = 0;
|
||||
static uint32_t lines[32768];
|
||||
static uint32_t current_line;
|
||||
|
||||
//static t_label known_labels[MAX_LABELS];
|
||||
static std::vector<t_label> known_labels;
|
||||
//static int num_known_labels = 0;
|
||||
static t_label unknown_labels[MAX_LABELS];
|
||||
static int num_unknown_labels = 0;
|
||||
static std::vector<t_label> unknown_labels;
|
||||
//static int num_unknown_labels = 0;
|
||||
static int num_anonymous_labels = 0;
|
||||
|
||||
static char* breaklabel = nullptr;
|
||||
static char* contlabel = nullptr;
|
||||
static std::string breaklabel = "";
|
||||
static std::string contlabel = "";
|
||||
|
||||
/*
|
||||
static t_variable* variables = nullptr;
|
||||
@@ -102,15 +76,16 @@ static bool global_closed = false;
|
||||
/* GENERIC FUNCTIONS */
|
||||
/****************************************************************************************/
|
||||
|
||||
static void int_to_string(int value, char* label) {
|
||||
for (int i = 0; i < 7; i++) label[i] = '0';
|
||||
label[7] = 0;
|
||||
static const std::string int_to_string(int value) {
|
||||
std::string label = "0000000";
|
||||
//for (int i = 0; i < 7; i++) label[i] = '0';
|
||||
int i = 6;
|
||||
while (value > 0) {
|
||||
label[i] = 48 + (value % 10);
|
||||
value = value / 10;
|
||||
i--;
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
@@ -162,56 +137,44 @@ static const uint32_t get_current_address() {
|
||||
return codepos;
|
||||
}
|
||||
|
||||
#define EXPECT(X, Y) if (tkn_get_token() != X) { parser_finished = true; error_raise(Y); return; }
|
||||
#define EXPECT2(X, Y) if (tkn_get_token() != X) { parser_finished = true; error_raise(Y); return -1; }
|
||||
#define HALT(Y) { parser_finished = true; error_raise(Y); return; }
|
||||
#define HALT2(Y) { parser_finished = true; error_raise(Y); return -1; }
|
||||
|
||||
/****************************************************************************************/
|
||||
/* LABEL MANAGEMENT */
|
||||
/****************************************************************************************/
|
||||
/*
|
||||
static const word get_label_address(const char* string) {
|
||||
for (int i = 0; i < num_known_labels; i++) { if (strcmp(known_labels[i].name, string) == 0) return known_labels[i].address; }
|
||||
//unknown_labels[num_unknown_labels].name = (char*)malloc(strlen(string) + 1);
|
||||
strcpy(unknown_labels[num_unknown_labels].name, string);
|
||||
unknown_labels[num_unknown_labels].address = get_current_address();
|
||||
num_unknown_labels++;
|
||||
|
||||
static const uint32_t get_label_address(const std::string name) {
|
||||
for (auto label : known_labels) if (label.name == name) return label.address;
|
||||
unknown_labels.push_back({name, get_current_address()});
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void register_label_address(const char* string) {
|
||||
static void register_label_address(const std::string name) {
|
||||
// If the label already exists, vomit an error
|
||||
for (int i = 0; i < num_known_labels; i++) {
|
||||
if (strcmp(known_labels[i].name, string) == 0) {
|
||||
parser_finished = true;
|
||||
error_raise("Duplicate label");
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (auto label : known_labels) if (label.name == name) HALT("Duplicate label");
|
||||
|
||||
// register new label
|
||||
//known_labels[num_known_labels].name = (char*)malloc(strlen(string) + 1);
|
||||
strcpy(known_labels[num_known_labels].name, string);
|
||||
known_labels[num_known_labels++].address = get_current_address();
|
||||
known_labels.push_back({name, get_current_address()});
|
||||
|
||||
// patch and remove any references awaiting for this label
|
||||
int i = 0;
|
||||
while (i < num_unknown_labels) {
|
||||
if (strcmp(unknown_labels[i].name, string) == 0) {
|
||||
patch(unknown_labels[i].address, get_current_address());
|
||||
if (i < num_unknown_labels - 1) {
|
||||
//free(unknown_labels[i].name);
|
||||
unknown_labels[i].address = unknown_labels[num_unknown_labels - 1].address;
|
||||
strcpy(unknown_labels[i].name, unknown_labels[num_unknown_labels - 1].name);
|
||||
//unknown_labels[i].name = unknown_labels[num_unknown_labels - 1].name;
|
||||
}
|
||||
num_unknown_labels--;
|
||||
}
|
||||
else {
|
||||
i++;
|
||||
auto i = std::begin(unknown_labels);
|
||||
while (i != std::end(unknown_labels)) {
|
||||
if ((*i).name == name) {
|
||||
patch_dw((*i).address, get_current_address());
|
||||
i = unknown_labels.erase(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
//num_known_labels++;
|
||||
}
|
||||
|
||||
static void generate_anonymous_labelname(char* dest) {
|
||||
int_to_string(num_anonymous_labels++, dest);
|
||||
static const std::string generate_anonymous_labelname() {
|
||||
return int_to_string(num_anonymous_labels++);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -234,11 +197,6 @@ static void parse_getchar();
|
||||
static void parse_getcolor();
|
||||
*/
|
||||
|
||||
#define EXPECT(X, Y) if (tkn_get_token() != X) { parser_finished = true; error_raise(Y); return; }
|
||||
#define EXPECT2(X, Y) if (tkn_get_token() != X) { parser_finished = true; error_raise(Y); return -1; }
|
||||
#define HALT(Y) { parser_finished = true; error_raise(Y); return; }
|
||||
#define HALT2(Y) { parser_finished = true; error_raise(Y); return -1; }
|
||||
|
||||
/*
|
||||
static void parse_concat_atom() {
|
||||
if (tkn_get_token() == TOKEN_STRING) {
|
||||
@@ -418,8 +376,8 @@ static void parse_expression() {
|
||||
}
|
||||
}
|
||||
|
||||
static bool identifier_exists(const std::string identifier) {
|
||||
if (scope_variable_exists(identifier)) return true;
|
||||
static bool identifier_exists(const std::string identifier, const bool can_shadow=false) {
|
||||
if (scope_variable_exists(identifier, can_shadow)) return true;
|
||||
if (types_exist(identifier) != -1) return true;
|
||||
if (function_exists(identifier)) return true;
|
||||
return false;
|
||||
@@ -429,7 +387,7 @@ static void parse_const() {
|
||||
EXPECT(TOKEN_IDENTIFIER, "Expected identifier");
|
||||
char const_name[40];
|
||||
strcpy(const_name, tkn_get_string());
|
||||
if (identifier_exists(const_name)) HALT("Identifier already exists");
|
||||
if (identifier_exists(const_name, true)) HALT("Identifier already exists");
|
||||
tkn_next(); EXPECT(TOKEN_AS, "Expected 'as'");
|
||||
tkn_next(); EXPECT(TOKEN_IDENTIFIER, "Expected type identifier");
|
||||
char type_name[40];
|
||||
@@ -448,7 +406,7 @@ static void parse_var() {
|
||||
int var_length = 1;
|
||||
EXPECT(TOKEN_IDENTIFIER, "Expected identifier");
|
||||
const std::string var_name = tkn_get_string();
|
||||
if (identifier_exists(var_name)) HALT("Identifier already exists");
|
||||
if (identifier_exists(var_name, true)) HALT("Identifier already exists");
|
||||
tkn_next(); EXPECT(TOKEN_AS, "Expected 'as'");
|
||||
tkn_next();
|
||||
if (tkn_get_token() == TOKEN_ARRAY) {
|
||||
@@ -646,28 +604,30 @@ static void parse_dec() {
|
||||
}
|
||||
}*/
|
||||
|
||||
/*
|
||||
|
||||
static void parse_if() {
|
||||
char* previous_breaklabel = breaklabel;
|
||||
const std::string previous_breaklabel = breaklabel;
|
||||
parse_expression();
|
||||
EXPECT(TOKEN_THEN, "Expected 'THEN'");
|
||||
tkn_next();
|
||||
emmit(OP_JNT);
|
||||
char elselabel[8];
|
||||
generate_anonymous_labelname(elselabel);
|
||||
char endlabel[8];
|
||||
generate_anonymous_labelname(endlabel);
|
||||
const std::string elselabel = generate_anonymous_labelname();
|
||||
const std::string endlabel = generate_anonymous_labelname();
|
||||
breaklabel = endlabel;
|
||||
bool else_visited = false;
|
||||
emmit_w(get_label_address(elselabel));
|
||||
emmit_dw(get_label_address(elselabel));
|
||||
scope_open_block();
|
||||
parse_statements();
|
||||
scope_close_block();
|
||||
if (tkn_get_token() == TOKEN_ELSE) {
|
||||
else_visited = true;
|
||||
emmit(OP_JMP);
|
||||
emmit_w(get_label_address(endlabel));
|
||||
emmit_dw(get_label_address(endlabel));
|
||||
register_label_address(elselabel);
|
||||
tkn_next();
|
||||
scope_open_block();
|
||||
parse_statements();
|
||||
scope_close_block();
|
||||
}
|
||||
if (tkn_get_token() == TOKEN_END) {
|
||||
if (!else_visited) register_label_address(elselabel);
|
||||
@@ -679,7 +639,7 @@ static void parse_if() {
|
||||
parser_finished = true;
|
||||
if (!else_visited) error_raise("Expected 'ELSE', 'END' or a statement"); else error_raise("Expected 'END' or a statement");
|
||||
}
|
||||
|
||||
/*
|
||||
static void parse_for() {
|
||||
char* previous_breaklabel = breaklabel;
|
||||
char* previous_contlabel = contlabel;
|
||||
@@ -804,9 +764,9 @@ static void parse_statements() {
|
||||
tkn_next(); parse_const(); break;
|
||||
case TOKEN_VAR:
|
||||
tkn_next(); parse_var(); break;
|
||||
/*
|
||||
case TOKEN_IF:
|
||||
tkn_next(); parse_if(); break;
|
||||
/*
|
||||
case TOKEN_FOR:
|
||||
tkn_next(); parse_for(); break;
|
||||
case TOKEN_BREAK:
|
||||
|
||||
15
scope.cpp
15
scope.cpp
@@ -69,11 +69,18 @@ const int scope_declare_variable(const std::string name, const uint32_t type, co
|
||||
return address;
|
||||
}
|
||||
|
||||
const bool scope_variable_exists(const std::string name) {
|
||||
const bool scope_variable_exists(const std::string name, const bool can_shadow) {
|
||||
t_scope& scope = (are_we_inside_local ? local : global);
|
||||
for (t_variable v : scope.variables) if (v.name == name) {
|
||||
current_var = &v;
|
||||
return true;
|
||||
if (are_we_inside_local && can_shadow) {
|
||||
for (int i = blocks.top(); i < scope.variables.size(); i++ ) if (scope.variables[i].name == name) {
|
||||
current_var = &scope.variables[i];
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
for (t_variable v : scope.variables) if (v.name == name) {
|
||||
current_var = &v;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
2
scope.h
2
scope.h
@@ -11,7 +11,7 @@ void scope_close_block();
|
||||
|
||||
const int scope_declare_variable(const std::string name, const uint32_t type, const uint32_t length);
|
||||
|
||||
const bool scope_variable_exists(const std::string name);
|
||||
const bool scope_variable_exists(const std::string name, const bool can_shadow = false);
|
||||
const uint32_t scope_get_variable_address();
|
||||
const int scope_get_variable_size();
|
||||
const int scope_get_variable_type();
|
||||
|
||||
Reference in New Issue
Block a user