Compare commits
20 Commits
fd53606ffc
...
e3cea9d3b0
| Author | SHA1 | Date | |
|---|---|---|---|
| e3cea9d3b0 | |||
| f1c1b3e396 | |||
| b40e234013 | |||
| b62cbd2cda | |||
| 835cae35bb | |||
| 287bf565bd | |||
| 8b101e4d3c | |||
| 37fdf1f42f | |||
| 1516043f17 | |||
| 2ff14cd2f1 | |||
| 7297215aeb | |||
| 28b059c57e | |||
| 58808d33a5 | |||
| 567710779a | |||
| c99d5ab781 | |||
| 36caa0b651 | |||
| 38e3bb1630 | |||
| d20663ac7e | |||
| 6923bec289 | |||
| 87bad32300 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,5 @@
|
||||
|
||||
.vscode
|
||||
*.exe
|
||||
jb
|
||||
decompiled.txt
|
||||
|
||||
71
decompiler.cpp
Normal file
71
decompiler.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#include "decompiler.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string.h>
|
||||
#include "parser.h"
|
||||
|
||||
#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 << 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];
|
||||
int pos = 0;
|
||||
float fval = 0;
|
||||
uint32_t ival = 0;
|
||||
std::ofstream f("decompiled.txt");
|
||||
if (f.is_open()) {
|
||||
while (pos < size) {
|
||||
switch (code[pos]) {
|
||||
case OP_NOP: SIMPLE("NOP");
|
||||
case OP_PUSH: FVAR("PUSH");
|
||||
case OP_POP: SIMPLE("POP");
|
||||
case OP_DUP: SIMPLE("DUP");
|
||||
case OP_SWAP: SIMPLE("SWAP");
|
||||
case OP_LD: IVAR("LD");
|
||||
case OP_ST: IVAR("ST");
|
||||
case OP_LDL: IVAR("LDL");
|
||||
case OP_STL: IVAR("STL");
|
||||
case OP_JMP: IVAR("JMP");
|
||||
case OP_JNT: IVAR("JNT");
|
||||
case OP_JTR: IVAR("JTR");
|
||||
case OP_RET: SIMPLE("RET");
|
||||
case OP_CALL: IVAR("CALL");
|
||||
case OP_CALLEX: IVAR("CALLEX");
|
||||
case OP_ADD: SIMPLE("ADD");
|
||||
case OP_SUB: SIMPLE("SUB");
|
||||
case OP_MUL: SIMPLE("MUL");
|
||||
case OP_DIV: SIMPLE("DIV");
|
||||
case OP_MOD: SIMPLE("MOD");
|
||||
case OP_AND: SIMPLE("AND");
|
||||
case OP_OR: SIMPLE("OR");
|
||||
case OP_NOT: SIMPLE("NOT");
|
||||
case OP_NEG: SIMPLE("NEG");
|
||||
case OP_INC: SIMPLE("INC");
|
||||
case OP_DEC: SIMPLE("DEC");
|
||||
case OP_CONCAT: SIMPLE("CONCAT");
|
||||
case OP_EQ: SIMPLE("EQ");
|
||||
case OP_NEQ: SIMPLE("NEQ");
|
||||
case OP_LT: SIMPLE("LT");
|
||||
case OP_GT: SIMPLE("GT");
|
||||
case OP_LEQ: SIMPLE("LEQ");
|
||||
case OP_GEQ: SIMPLE("GEQ");
|
||||
case OP_SLEEP: SIMPLE("SLEEP");
|
||||
}
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
}
|
||||
4
decompiler.h
Normal file
4
decompiler.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
void decompiler_save(const uint8_t *code, const int size);
|
||||
16
error.cpp
16
error.cpp
@@ -1,18 +1,25 @@
|
||||
#include "error.h"
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include "tokenizer.h"
|
||||
|
||||
static char errormsg[255];
|
||||
static bool raised = false;
|
||||
|
||||
static std::string warning_msg = "";
|
||||
|
||||
void error_raise(const char* msg) {
|
||||
if (!raised) {
|
||||
raised = true;
|
||||
sprintf(errormsg, "ERROR AT SOURCE:%s at %d:%d.", msg, tkn_get_line() + 1, tkn_get_row() + 1);
|
||||
sprintf(errormsg, "ERROR: %s at %d:%d.\n", msg, tkn_get_line() + 1, tkn_get_row() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void error_warning(const char *msg) {
|
||||
char warningmsg[255];
|
||||
sprintf(warningmsg, "WARNING: %s at %d:%d.\n", msg, tkn_get_line() + 1, tkn_get_row() + 1);
|
||||
warning_msg += warningmsg;
|
||||
}
|
||||
|
||||
bool error_raised() { return raised; }
|
||||
|
||||
void error_print(unsigned char* mem) {
|
||||
@@ -20,3 +27,8 @@ void error_print(unsigned char* mem) {
|
||||
//while (*msg != 0) *mem++ = *msg++;
|
||||
printf("%s", errormsg);
|
||||
}
|
||||
|
||||
void error_print_warnings() {
|
||||
if (warning_msg == "") warning_msg = "Compilation OK.\n";
|
||||
printf("%s", warning_msg.c_str());
|
||||
}
|
||||
2
error.h
2
error.h
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
void error_raise(const char* msg);
|
||||
void error_warning(const char* msg);
|
||||
bool error_raised();
|
||||
void error_print(unsigned char* mem);
|
||||
void error_print_warnings();
|
||||
|
||||
57
function.cpp
Normal file
57
function.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#include "function.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct t_parameter {
|
||||
std::string name;
|
||||
uint32_t type;
|
||||
};
|
||||
|
||||
struct t_function {
|
||||
std::string name;
|
||||
uint32_t address;
|
||||
int type;
|
||||
std::vector<t_parameter> parameters;
|
||||
};
|
||||
|
||||
static std::vector<t_function> functions;
|
||||
static int current_function = -1;
|
||||
|
||||
const bool function_register(const std::string name, const uint32_t address) {
|
||||
for (auto f : functions) if (f.name == name) return false;
|
||||
functions.push_back({name, address, -1});
|
||||
current_function = functions.size()-1;
|
||||
return true;
|
||||
}
|
||||
|
||||
void function_set_type(const uint32_t type) {
|
||||
functions[current_function].type = type;
|
||||
}
|
||||
|
||||
const int function_get_type() {
|
||||
return functions[current_function].type;
|
||||
}
|
||||
|
||||
const bool function_parameter_add(const std::string name, const uint32_t type) {
|
||||
for (auto p : functions[current_function].parameters) if (p.name == name) return false;
|
||||
functions[current_function].parameters.push_back({name, type});
|
||||
return true;
|
||||
}
|
||||
|
||||
const bool function_exists(const std::string name) {
|
||||
for (auto f : functions) if (f.name == name) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t function_get_address(const std::string name) {
|
||||
for (auto f : functions) if (f.name == name) return f.address;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int function_get_num_parameters() {
|
||||
return functions[current_function].parameters.size();
|
||||
}
|
||||
|
||||
const int function_get_parameter_type(const int index) {
|
||||
return functions[current_function].parameters[index].type;
|
||||
}
|
||||
28
function.h
Normal file
28
function.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
// Register a new function. Returns false if a function with the same name already exists
|
||||
const bool function_register(const std::string name, const uint32_t address);
|
||||
|
||||
// Set the return type of the last searched function
|
||||
void function_set_type(const uint32_t type);
|
||||
|
||||
// Get the return type of the last searched function or -1 if none
|
||||
const int function_get_type();
|
||||
|
||||
// Add a parameter to the last registered function, returns false if there's a parameter already named like that
|
||||
const bool function_parameter_add(const std::string name, const uint32_t type);
|
||||
|
||||
// Check if there's a function with that name
|
||||
const bool function_exists(const std::string name);
|
||||
|
||||
|
||||
// Retrieve the address of the specified function, or zero if there's no such function
|
||||
const uint32_t function_get_address(const std::string name);
|
||||
|
||||
// Retrieve the number of parameters of the last searched function
|
||||
const int function_get_num_parameters();
|
||||
|
||||
// Retrieve the type of the nth parameter of the last searched function
|
||||
const int function_get_parameter_type(const int index);
|
||||
21
main.cpp
Normal file
21
main.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#include "parser.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static unsigned char mem[65536];
|
||||
|
||||
int main(void) {
|
||||
|
||||
FILE *f = fopen("test.vb", "rb");
|
||||
fseek(f, 0, SEEK_END);
|
||||
long fsize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET); //same as rewind(f);
|
||||
char *program = (char*)malloc(fsize + 1);
|
||||
fread(program, fsize, 1, f);
|
||||
fclose(f);
|
||||
program[fsize] = 0;
|
||||
parser_parse(program, mem);
|
||||
free(program);
|
||||
|
||||
return 0;
|
||||
}
|
||||
633
parser.cpp
633
parser.cpp
@@ -1,9 +1,17 @@
|
||||
#include "parser.h"
|
||||
#include "tokenizer.h"
|
||||
#include "scope.h"
|
||||
#include "types.h"
|
||||
#include "function.h"
|
||||
#include "error.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
#include "decompiler.h"
|
||||
|
||||
#define MAX_CODE_SIZE 65536
|
||||
#define MAX_LABELS 256
|
||||
@@ -13,34 +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];
|
||||
@@ -52,26 +38,23 @@ 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 word codepos = 0;
|
||||
static word lines[32768];
|
||||
static word current_line;
|
||||
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;
|
||||
static int num_variables = 0;
|
||||
static bool variable_is_array = false;
|
||||
@@ -82,24 +65,27 @@ static int num_external_functions = 0;
|
||||
static t_string strings[256];
|
||||
static int num_strings = 0;
|
||||
|
||||
static bool parser_finished = false;
|
||||
|
||||
static t_constant constants[MAX_CONSTANTS];
|
||||
static int num_constants;
|
||||
*/
|
||||
|
||||
static bool parser_finished = false;
|
||||
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;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
@@ -118,6 +104,14 @@ static void emmit_w(const word value) {
|
||||
code[codepos++] = value >> 8;
|
||||
}
|
||||
|
||||
static void emmit_dw(const uint32_t value) {
|
||||
byte *v = (byte*)&value;
|
||||
lines[codepos] = current_line; code[codepos++] = *(v++);
|
||||
lines[codepos] = current_line; code[codepos++] = *(v++);
|
||||
lines[codepos] = current_line; code[codepos++] = *(v++);
|
||||
lines[codepos] = current_line; code[codepos++] = *(v++);
|
||||
}
|
||||
|
||||
static void emmit_f(const float value) {
|
||||
byte *v = (byte*)&value;
|
||||
lines[codepos] = current_line; code[codepos++] = *(v++);
|
||||
@@ -126,168 +120,72 @@ static void emmit_f(const float value) {
|
||||
lines[codepos] = current_line; code[codepos++] = *(v++);
|
||||
}
|
||||
|
||||
static void patch(const word address, const word dest) {
|
||||
static void patch(const uint32_t address, const word dest) {
|
||||
code[address] = dest & 255;
|
||||
code[address + 1] = dest >> 8;
|
||||
}
|
||||
|
||||
static const word get_current_address() {
|
||||
static void patch_dw(const uint32_t address, const uint32_t dest) {
|
||||
byte *v = (byte*)&dest;
|
||||
code[address] = v[0];
|
||||
code[address+1] = v[1];
|
||||
code[address+2] = v[2];
|
||||
code[address+3] = v[3];
|
||||
}
|
||||
|
||||
static const uint32_t get_current_address() {
|
||||
return codepos;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
/* VARIABLE MANAGEMENT */
|
||||
/****************************************************************************************/
|
||||
|
||||
static int get_variable_index(const char* string, const int array_size = 1) {
|
||||
t_variable* variable = variables;
|
||||
t_variable* last = variables;
|
||||
while (variable != nullptr) {
|
||||
if (strcmp(variable->name, string) == 0) { variable_is_array = (variable->size > 1); return variable->index + 0xC000; }
|
||||
last = variable;
|
||||
variable = variable->next;
|
||||
}
|
||||
t_variable* newvar = (t_variable*)malloc(sizeof(t_variable));
|
||||
//newvar->name = (char*)malloc(strlen(string) + 1);
|
||||
strcpy(newvar->name, string);
|
||||
newvar->index = num_variables;
|
||||
num_variables += array_size;
|
||||
newvar->size = array_size;
|
||||
variable_is_array = (newvar->size > 1);
|
||||
newvar->next = nullptr;
|
||||
if (last != nullptr) {
|
||||
last->next = newvar;
|
||||
}
|
||||
else {
|
||||
variables = newvar;
|
||||
}
|
||||
return newvar->index + 0xC000;
|
||||
}
|
||||
|
||||
static bool is_variable_array() { return variable_is_array; }
|
||||
|
||||
/****************************************************************************************/
|
||||
/* CONSTANT MANAGEMENT */
|
||||
/****************************************************************************************/
|
||||
void parser_register_constant(const char* name, const unsigned char value) {
|
||||
strcpy(constants[num_constants].name, name);
|
||||
constants[num_constants++].value = value;
|
||||
}
|
||||
|
||||
static const int get_constant(const char* name) {
|
||||
for (int i = 0; i < num_constants; i++) {
|
||||
if (strcmp(constants[i].name, name) == 0)
|
||||
return constants[i].value;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#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++);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
/* STRING MANAGEMENT */
|
||||
/****************************************************************************************/
|
||||
static const bool same_string(const unsigned char* a, const unsigned char*b) {
|
||||
for (int i = 0; i <= a[0]; i++) if (a[i] != b[i]) return false;
|
||||
return true;
|
||||
}
|
||||
static void copy_string(unsigned char* dest, const unsigned char* src) {
|
||||
memcpy(dest, src, src[0] + 1);
|
||||
//for (int i = 0; i <= src[0]; i++) dest[i] = src[i];
|
||||
}
|
||||
static void to_basic_string(unsigned char* dest, const char* src) {
|
||||
int len = strlen(src);
|
||||
*dest = len; dest++;
|
||||
memcpy(dest, src, len);
|
||||
}
|
||||
|
||||
static int register_array(const unsigned char* string) {
|
||||
for (int i = 0; i < num_strings; i++) {
|
||||
if (same_string(strings[i].string, string)) { strings[i].references[strings[i].num_references++] = get_current_address(); return 0; }
|
||||
}
|
||||
copy_string(strings[num_strings].string, string);
|
||||
strings[num_strings++].references[0] = get_current_address();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int register_string(const char* string) {
|
||||
unsigned char new_str[255]; to_basic_string(new_str, string);
|
||||
for (int i = 0; i < num_strings; i++) {
|
||||
if (same_string(strings[i].string, new_str)) { strings[i].references[strings[i].num_references++] = get_current_address(); return 0; }
|
||||
}
|
||||
copy_string(strings[num_strings].string, new_str);
|
||||
strings[num_strings++].references[0] = get_current_address();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void append_strings() {
|
||||
code[0] = codepos & 255;
|
||||
code[1] = codepos >> 8;
|
||||
emmit(num_strings);
|
||||
for (int i = 0; i < num_strings; i++) {
|
||||
for (int j = 0; j < strings[i].num_references; j++) { patch(strings[i].references[j], get_current_address()); }
|
||||
//char len = strings[i].string[0];
|
||||
//emmit(len);
|
||||
for (int j = 0; j <= strings[i].string[0]; j++) { emmit(strings[i].string[j]); }
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
/* PARSER */
|
||||
/****************************************************************************************/
|
||||
|
||||
static void parse_expression();
|
||||
static void parse_statements();
|
||||
static const bool parse_statements();
|
||||
|
||||
/* [RZC 27/04/2021] No usat en JailScript
|
||||
/* XXX [RZC 27/04/2021] No usat en JailBasic
|
||||
//static void parse_strleft();
|
||||
static void parse_str();
|
||||
static void parse_chr();
|
||||
@@ -299,8 +197,7 @@ static void parse_getchar();
|
||||
static void parse_getcolor();
|
||||
*/
|
||||
|
||||
#define EXPECT(X, Y) if (tkn_get_token() != X) { parser_finished = true; error_raise(Y); return; }
|
||||
|
||||
/*
|
||||
static void parse_concat_atom() {
|
||||
if (tkn_get_token() == TOKEN_STRING) {
|
||||
emmit(OP_SETX);
|
||||
@@ -342,6 +239,39 @@ static void parse_concatenation() {
|
||||
emmit(OP_CONCAT);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
static int get_variable_address() {
|
||||
int address = scope_get_variable_address();
|
||||
uint32_t var_length = scope_get_variable_size();
|
||||
uint32_t var_type = scope_get_variable_type();
|
||||
|
||||
while (true) {
|
||||
// Si es un array...
|
||||
if (var_length > 1) {
|
||||
tkn_next(); EXPECT2(TOKEN_LBRACKET, "Expected '['");
|
||||
tkn_next(); EXPECT2(TOKEN_NUMBER, "Expected number");
|
||||
const int index = (int)tkn_get_value();
|
||||
if (tkn_get_value() > index) HALT2("Expected integer value");
|
||||
if (index >= var_length) HALT2("Index out of bounds");
|
||||
tkn_next(); EXPECT2(TOKEN_RBRACKET, "Expected ']'");
|
||||
address += index * types_get_length(var_type);
|
||||
}
|
||||
// Si es un struct...
|
||||
if (var_type >= 2) {
|
||||
tkn_next(); EXPECT2(TOKEN_DOT, "Expected '.'");
|
||||
tkn_next(); EXPECT2(TOKEN_IDENTIFIER, "Expected identifier");
|
||||
const std::string member_name = tkn_get_string();
|
||||
const int member_num = types_member_exists(var_type, member_name);
|
||||
if (member_num == -1) HALT2("Unknown member");
|
||||
address += types_get_member_offset(var_type, member_num);
|
||||
var_length = types_get_member_length(var_type, member_num);
|
||||
var_type = types_get_member_type(var_type, member_num);
|
||||
} else {
|
||||
return address;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_expr_atom() {
|
||||
// NUM, VAR, UNARY, PAREN
|
||||
@@ -352,32 +282,19 @@ static void parse_expr_atom() {
|
||||
return;
|
||||
}
|
||||
if (tkn_get_token() == TOKEN_IDENTIFIER) {
|
||||
// [RZC 27/04/2021] Per ara llevem les constants
|
||||
/*int constvalue = get_constant(tkn_get_string());
|
||||
if (constvalue != -1) {
|
||||
emmit(OP_PUSH);
|
||||
emmit(constvalue);
|
||||
if (scope_variable_exists(tkn_get_string())) {
|
||||
const int address = get_variable_address();
|
||||
if (address == -1) return;
|
||||
emmit(scope_is_local() ? OP_LDL : OP_LD);
|
||||
emmit_dw(address);
|
||||
tkn_next();
|
||||
return;
|
||||
}*/
|
||||
|
||||
// [RZC 27/04/2021] Per ara llevem les variables
|
||||
/*int ivar = get_variable_index(tkn_get_string());
|
||||
if (is_variable_array()) {
|
||||
tkn_next(); EXPECT(TOKEN_LPAR, "Expected array index");
|
||||
tkn_next(); parse_expr_atom();
|
||||
EXPECT(TOKEN_RPAR, "Expected ')'");
|
||||
emmit(OP_SETY);
|
||||
emmit(OP_LOADI);
|
||||
emmit_w(ivar);
|
||||
} else {
|
||||
emmit(OP_LOAD);
|
||||
emmit_w(ivar);
|
||||
}*/
|
||||
// [RZC 27/04/2021] Atenció! Ara les variables han de estar declarades abans, pel que pot haver error ací si no s'ha trobat.
|
||||
tkn_next();
|
||||
// TODO [RZC 03/05/2021] Revisar funcions
|
||||
parser_finished = true; error_raise("Unknown identifier");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (tkn_get_token() == TOKEN_MINUS) {
|
||||
tkn_next();
|
||||
parse_expr_atom();
|
||||
@@ -397,14 +314,6 @@ static void parse_expr_atom() {
|
||||
tkn_next();
|
||||
return;
|
||||
}
|
||||
// [RZC 27/04/2021] No usat en JailScript, pero hi haurà que afegir les funcions
|
||||
/*
|
||||
if (tkn_get_token() == TOKEN_STRLEN) { tkn_next(); parse_strlen(); return; }
|
||||
if (tkn_get_token() == TOKEN_KEYPRESSED) { tkn_next(); parse_keypressed(); return; }
|
||||
if (tkn_get_token() == TOKEN_ANYKEY) { tkn_next(); parse_anykey(); return; }
|
||||
if (tkn_get_token() == TOKEN_GETCHAR) { tkn_next(); parse_getchar(); return; }
|
||||
if (tkn_get_token() == TOKEN_GETCOLOR) { tkn_next(); parse_getcolor(); return; }
|
||||
*/
|
||||
parser_finished = true; error_raise("Syntax error");
|
||||
return;
|
||||
}
|
||||
@@ -467,22 +376,146 @@ static void parse_expression() {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void parse_const() {
|
||||
EXPECT(TOKEN_IDENTIFIER, "Expected identifier");
|
||||
char const_name[40];
|
||||
strcpy(const_name, tkn_get_string());
|
||||
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];
|
||||
strcpy(type_name, tkn_get_string());
|
||||
const int type_num = types_exist(type_name);
|
||||
if (type_num == -1) HALT("Unknown type");
|
||||
if (type_num >= 2) HALT("Only 'number' or 'string' constants allowed");
|
||||
tkn_next(); EXPECT(TOKEN_EQ, "Expected '='");
|
||||
tkn_next(); EXPECT(TOKEN_NUMBER, "Expected integer constant");
|
||||
int constvalue = tkn_get_value();
|
||||
parser_register_constant(constname, constvalue);
|
||||
tkn_next(); parse_expression();
|
||||
const int var_address = scope_declare_variable(const_name, type_num, 0);
|
||||
emmit(scope_is_local() ? OP_STL : OP_ST);
|
||||
emmit_dw(var_address);
|
||||
}
|
||||
|
||||
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, true)) HALT("Identifier already exists");
|
||||
tkn_next(); EXPECT(TOKEN_AS, "Expected 'as'");
|
||||
tkn_next();
|
||||
if (tkn_get_token() == TOKEN_ARRAY) {
|
||||
tkn_next(); EXPECT(TOKEN_OF, "Expected 'of'");
|
||||
tkn_next(); EXPECT(TOKEN_NUMBER, "Expected number");
|
||||
const float length = tkn_get_value();
|
||||
var_length = (int)length;
|
||||
if (length > var_length) HALT("Expected integer value");
|
||||
tkn_next();
|
||||
}
|
||||
EXPECT(TOKEN_IDENTIFIER, "Expected type identifier");
|
||||
const std::string type_name = tkn_get_string();
|
||||
const int type_num = types_exist(type_name);
|
||||
if (type_num == -1) HALT("Unknown type");
|
||||
tkn_next();
|
||||
if (tkn_get_token() == TOKEN_EQ) {
|
||||
if (type_num >= 2) HALT("Only 'number' or 'string' variables can be initialized on declaration")
|
||||
if (var_length > 1) HALT("Array variables cannot be initialized on declaration")
|
||||
tkn_next(); parse_expression();
|
||||
const int var_address = scope_declare_variable(var_name, type_num, var_length);
|
||||
emmit(scope_is_local() ? OP_STL : OP_ST);
|
||||
emmit_dw(var_address);
|
||||
} else {
|
||||
scope_declare_variable(var_name, type_num, var_length);
|
||||
//tkn_next();
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_struct() {
|
||||
EXPECT(TOKEN_IDENTIFIER, "Expected identifier");
|
||||
const std::string struct_name = tkn_get_string();
|
||||
if (identifier_exists(struct_name)) HALT("Identifier already exists");
|
||||
const int struct_num = types_add(struct_name);
|
||||
tkn_next();
|
||||
while (tkn_get_token() != TOKEN_END) {
|
||||
int member_length = 1;
|
||||
EXPECT(TOKEN_IDENTIFIER, "Expected identifier");
|
||||
char member_name[40];
|
||||
strcpy(member_name, tkn_get_string());
|
||||
tkn_next(); EXPECT(TOKEN_AS, "Expected 'as'");
|
||||
tkn_next();
|
||||
if (tkn_get_token() == TOKEN_ARRAY) {
|
||||
tkn_next(); EXPECT(TOKEN_OF, "Expected 'of'");
|
||||
tkn_next(); EXPECT(TOKEN_NUMBER, "Expected number");
|
||||
member_length = (int)tkn_get_value();
|
||||
if (tkn_get_value() > member_length) HALT("Expected integer value");
|
||||
tkn_next();
|
||||
}
|
||||
EXPECT(TOKEN_IDENTIFIER, "Expected type identifier");
|
||||
const std::string type_name = tkn_get_string();
|
||||
const int type_num = types_exist(type_name);
|
||||
if (type_num == -1) HALT("Unknown type");
|
||||
types_add_member(struct_num, member_name, type_num, member_length);
|
||||
tkn_next();
|
||||
}
|
||||
tkn_next();
|
||||
}
|
||||
|
||||
static void parse_dim() {
|
||||
static void parse_function() {
|
||||
|
||||
if (!global_closed) {
|
||||
emmit(OP_RET);
|
||||
global_closed = true;
|
||||
}
|
||||
EXPECT(TOKEN_IDENTIFIER, "Expected identifier");
|
||||
const std::string function_name = tkn_get_string();
|
||||
if (identifier_exists(function_name)) HALT("Identifier already exists");
|
||||
function_register(function_name, codepos);
|
||||
tkn_next(); EXPECT(TOKEN_LPAR, "Expected '('");
|
||||
tkn_next();
|
||||
scope_open_local();
|
||||
std::stack<uint32_t> addresses;
|
||||
while (tkn_get_token() != TOKEN_RPAR) {
|
||||
if (function_get_num_parameters() != 0) {
|
||||
EXPECT(TOKEN_COMMA, "Expected ',' or ')'");
|
||||
tkn_next();
|
||||
}
|
||||
EXPECT(TOKEN_IDENTIFIER, "Expected identifier");
|
||||
const std::string param_name = tkn_get_string();
|
||||
tkn_next(); EXPECT(TOKEN_AS, "Expected 'as'");
|
||||
tkn_next(); EXPECT(TOKEN_IDENTIFIER, "Expected type identifier");
|
||||
const std::string type_name = tkn_get_string();
|
||||
const int type_num = types_exist(type_name);
|
||||
if (type_num == -1) HALT("Unknown type");
|
||||
if (!function_parameter_add(param_name, type_num)) HALT("Parameter name already used");
|
||||
addresses.push(scope_declare_variable(param_name, type_num, 1));
|
||||
tkn_next();
|
||||
}
|
||||
while (!addresses.empty()) {
|
||||
emmit(OP_STL);
|
||||
emmit_dw(addresses.top());
|
||||
addresses.pop();
|
||||
}
|
||||
tkn_next();
|
||||
if (tkn_get_token() == TOKEN_AS) {
|
||||
tkn_next(); EXPECT(TOKEN_IDENTIFIER, "Expected type identifier");
|
||||
const std::string type_name = tkn_get_string();
|
||||
const int type_num = types_exist(type_name);
|
||||
if (type_num == -1) HALT("Unknown type");
|
||||
function_set_type(type_num);
|
||||
tkn_next();
|
||||
}
|
||||
if (!parse_statements() && (function_get_type() != -1)) HALT("Not all paths return a value");
|
||||
scope_close_local();
|
||||
EXPECT(TOKEN_END, "Expected statement or 'end'");
|
||||
tkn_next();
|
||||
}
|
||||
|
||||
/*static void parse_dim() {
|
||||
EXPECT(TOKEN_IDENTIFIER, "Expected variable");
|
||||
char varname[40];
|
||||
strcpy(varname, tkn_get_string());
|
||||
@@ -491,8 +524,8 @@ static void parse_dim() {
|
||||
get_variable_index(varname, tkn_get_value()); // register variable with size, no need to keep ival
|
||||
tkn_next(); EXPECT(TOKEN_RPAR, "Expected ')'");
|
||||
tkn_next();
|
||||
}
|
||||
// [RZC 27/04/2021] Desactivat INC i DEC per ara
|
||||
}*/
|
||||
// XXX [RZC 27/04/2021] Desactivat INC i DEC per ara
|
||||
/*static void parse_inc() {
|
||||
EXPECT(TOKEN_IDENTIFIER, "Expected variable");
|
||||
int ivar = get_variable_index(tkn_get_string());
|
||||
@@ -540,7 +573,7 @@ static void parse_dec() {
|
||||
tkn_next();
|
||||
}*/
|
||||
|
||||
// [RZC 27/04/2021] Desactivat, no se molt be ni què es
|
||||
// XXX [RZC 27/04/2021] Desactivat, no se molt be ni què es
|
||||
/*static void parse_let() {
|
||||
EXPECT(TOKEN_IDENTIFIER, "Expected variable");
|
||||
int ivar = get_variable_index(tkn_get_string());
|
||||
@@ -572,85 +605,90 @@ static void parse_dec() {
|
||||
}
|
||||
}*/
|
||||
|
||||
static void parse_if() {
|
||||
char* previous_breaklabel = breaklabel;
|
||||
|
||||
static const bool parse_if() {
|
||||
bool ret_at_else = true;
|
||||
const std::string previous_breaklabel = breaklabel;
|
||||
parse_expression();
|
||||
EXPECT(TOKEN_THEN, "Expected 'THEN'");
|
||||
EXPECT2(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));
|
||||
parse_statements();
|
||||
emmit_dw(get_label_address(elselabel));
|
||||
scope_open_block();
|
||||
const bool ret_at_then = 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();
|
||||
parse_statements();
|
||||
scope_open_block();
|
||||
ret_at_else = parse_statements();
|
||||
scope_close_block();
|
||||
}
|
||||
if (tkn_get_token() == TOKEN_END) {
|
||||
if (!else_visited) register_label_address(elselabel);
|
||||
register_label_address(endlabel);
|
||||
tkn_next();
|
||||
breaklabel = previous_breaklabel;
|
||||
return;
|
||||
return ret_at_else && ret_at_then;
|
||||
}
|
||||
parser_finished = true;
|
||||
if (!else_visited) error_raise("Expected 'ELSE', 'END' or a statement"); else error_raise("Expected 'END' or a statement");
|
||||
return false;
|
||||
}
|
||||
|
||||
static void parse_for() {
|
||||
char* previous_breaklabel = breaklabel;
|
||||
char* previous_contlabel = contlabel;
|
||||
EXPECT(TOKEN_IDENTIFIER, "Expected variable");
|
||||
int ivar = get_variable_index(tkn_get_string());
|
||||
tkn_next();
|
||||
EXPECT(TOKEN_EQ, "Expected '='");
|
||||
static const bool parse_for() {
|
||||
const std::string previous_breaklabel = breaklabel;
|
||||
const std::string previous_contlabel = contlabel;
|
||||
EXPECT2(TOKEN_IDENTIFIER, "Expected variable");
|
||||
if (scope_variable_exists(tkn_get_string(), true)) HALT2("Identifier already used");
|
||||
const uint32_t var_address = scope_declare_variable(tkn_get_string(), 0, 0);
|
||||
tkn_next(); EXPECT2(TOKEN_EQ, "Expected '='");
|
||||
tkn_next();
|
||||
parse_expression();
|
||||
emmit(OP_STORE);
|
||||
emmit_w(ivar);
|
||||
char forlabel[8];
|
||||
generate_anonymous_labelname(forlabel);
|
||||
char endlabel[8];
|
||||
generate_anonymous_labelname(endlabel);
|
||||
char continuelabel[8];
|
||||
generate_anonymous_labelname(continuelabel);
|
||||
emmit(OP_STL);
|
||||
emmit_dw(var_address);
|
||||
const std::string forlabel = generate_anonymous_labelname();
|
||||
const std::string endlabel = generate_anonymous_labelname();
|
||||
const std::string continuelabel = generate_anonymous_labelname();
|
||||
breaklabel = endlabel;
|
||||
contlabel = continuelabel;
|
||||
register_label_address(forlabel);
|
||||
EXPECT(TOKEN_TO, "Expected 'TO'");
|
||||
EXPECT2(TOKEN_TO, "Expected 'TO'");
|
||||
tkn_next();
|
||||
parse_expression();
|
||||
emmit(OP_LOAD);
|
||||
emmit_w(ivar);
|
||||
emmit(OP_LDL);
|
||||
emmit_dw(var_address);
|
||||
emmit(OP_EQ);
|
||||
emmit(OP_JTR);
|
||||
emmit_w(get_label_address(endlabel));
|
||||
emmit_dw(get_label_address(endlabel));
|
||||
//int endLabel = GetCurrentAddress();
|
||||
parse_statements();
|
||||
EXPECT(TOKEN_END, "Expected 'END'");
|
||||
scope_open_block();
|
||||
const bool ret_called = parse_statements();
|
||||
scope_close_block();
|
||||
EXPECT2(TOKEN_END, "Expected 'END'");
|
||||
tkn_next();
|
||||
register_label_address(continuelabel);
|
||||
emmit(OP_LOAD);
|
||||
emmit_w(ivar);
|
||||
emmit(OP_LDL);
|
||||
emmit_dw(var_address);
|
||||
emmit(OP_INC);
|
||||
emmit(OP_STORE);
|
||||
emmit_w(ivar);
|
||||
emmit(OP_STL);
|
||||
emmit_dw(var_address);
|
||||
emmit(OP_JMP);
|
||||
emmit_w(get_label_address(forlabel));
|
||||
emmit_dw(get_label_address(forlabel));
|
||||
register_label_address(endlabel);
|
||||
//Patch(endLabel, GetCurrentAddress());
|
||||
breaklabel = previous_breaklabel;
|
||||
contlabel = previous_contlabel;
|
||||
return ret_called;
|
||||
}
|
||||
|
||||
/*
|
||||
static void parse_break() {
|
||||
if (breaklabel == nullptr) { parser_finished = true; error_raise("Can't break outside of a loop or condition"); return; }
|
||||
emmit(OP_JMP);
|
||||
@@ -662,8 +700,9 @@ static void parse_continue() {
|
||||
emmit(OP_JMP);
|
||||
emmit_w(get_label_address(contlabel));
|
||||
}
|
||||
*/
|
||||
|
||||
// [RZC 27/04/2021] Ni GOTO ni GOSUB
|
||||
// XXX [RZC 27/04/2021] Ni GOTO ni GOSUB
|
||||
/*static void parse_goto() {
|
||||
emmit(OP_JMP);
|
||||
EXPECT(TOKEN_IDENTIFIER, "Expected label name");
|
||||
@@ -678,17 +717,27 @@ static void parse_gosub() {
|
||||
tkn_next();
|
||||
}*/
|
||||
|
||||
|
||||
static void parse_return() {
|
||||
// [RZC 27/04/2021] [TODO] Falta afegir paràmetre de retorn
|
||||
const int return_type = function_get_type();
|
||||
if (return_type != -1) {
|
||||
if (return_type == 0) {
|
||||
parse_expression();
|
||||
} else if (return_type == 1) {
|
||||
// TODO [RZC 04/05/2021] Falta gestionar tipus string
|
||||
}
|
||||
}
|
||||
emmit(OP_RET);
|
||||
}
|
||||
|
||||
// [RZC 27/04/2021] No hi ha labels
|
||||
|
||||
// XXX [RZC 27/04/2021] No hi ha labels
|
||||
/*static void parse_label() {
|
||||
register_label_address(tkn_get_string());
|
||||
tkn_next();
|
||||
}*/
|
||||
|
||||
/*
|
||||
static void parse_call() {
|
||||
for (int i = 0; i < num_external_functions; i++) {
|
||||
if (strcmp(external_functions[i].name, tkn_get_string()) == 0) {
|
||||
@@ -709,43 +758,59 @@ static void parse_call() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_statements() {
|
||||
*/
|
||||
static const bool parse_statements() {
|
||||
bool return_called = false;
|
||||
bool local_return = false;
|
||||
bool already_warned = false;
|
||||
while (!parser_finished) {
|
||||
current_line = tkn_get_line();
|
||||
switch (tkn_get_token()) {
|
||||
case TOKEN_CONST:
|
||||
tkn_next(); parse_const(); break;
|
||||
case TOKEN_DIM:
|
||||
tkn_next(); parse_dim(); break;
|
||||
case TOKEN_LET:
|
||||
tkn_next(); parse_let(); break;
|
||||
case TOKEN_INC:
|
||||
tkn_next(); parse_inc(); break;
|
||||
case TOKEN_DEC:
|
||||
tkn_next(); parse_dec(); break;
|
||||
tkn_next();
|
||||
if (local_return && !already_warned) { error_warning("Unreachable code"); already_warned = true; }
|
||||
parse_const();
|
||||
break;
|
||||
case TOKEN_VAR:
|
||||
tkn_next();
|
||||
if (local_return && !already_warned) { error_warning("Unreachable code"); already_warned = true; }
|
||||
parse_var();
|
||||
break;
|
||||
case TOKEN_IF:
|
||||
tkn_next(); parse_if(); break;
|
||||
tkn_next();
|
||||
if (local_return && !already_warned) { error_warning("Unreachable code"); already_warned = true; }
|
||||
if (parse_if()) { return_called = true; } break;
|
||||
case TOKEN_FOR:
|
||||
tkn_next(); parse_for(); break;
|
||||
/*case TOKEN_BREAK:
|
||||
tkn_next();
|
||||
if (local_return && !already_warned) { error_warning("Unreachable code"); already_warned = true; }
|
||||
if (parse_for()) { return_called = true; } break;
|
||||
/*
|
||||
case TOKEN_BREAK:
|
||||
tkn_next(); parse_break(); break;
|
||||
case TOKEN_CONTINUE:
|
||||
tkn_next(); parse_continue(); break;*/
|
||||
tkn_next(); parse_continue(); break;
|
||||
*/
|
||||
case TOKEN_RETURN:
|
||||
tkn_next(); parse_return(); break;
|
||||
tkn_next();
|
||||
if (local_return && !already_warned) { error_warning("Unreachable code"); already_warned = true; }
|
||||
parse_return();
|
||||
local_return = return_called = true;
|
||||
break;
|
||||
case TOKEN_REM:
|
||||
tkn_next(); break;
|
||||
|
||||
/*
|
||||
case TOKEN_IDENTIFIER:
|
||||
for (int i = 0; i < num_external_functions; i++) {
|
||||
if (strcmp(external_functions[i].name, tkn_get_string()) == 0) { parse_call(); break; }
|
||||
}
|
||||
parse_let(); break;
|
||||
*/
|
||||
default:
|
||||
return;
|
||||
return return_called;
|
||||
}
|
||||
}
|
||||
return return_called;
|
||||
}
|
||||
|
||||
static void parse_global_statements() {
|
||||
@@ -753,22 +818,25 @@ static void parse_global_statements() {
|
||||
current_line = tkn_get_line();
|
||||
switch (tkn_get_token()) {
|
||||
case TOKEN_CONST:
|
||||
tkn_next(); parse_const(); break;
|
||||
tkn_next(); if (!global_closed) { parse_const(); } else { HALT("Global constants must be defined before functions"); } break;
|
||||
case TOKEN_VAR:
|
||||
tkn_next(); parse_var(); break;
|
||||
tkn_next(); if (!global_closed) { parse_var(); } else { HALT("Global variables must be defined before functions"); } break;
|
||||
case TOKEN_STRUCT:
|
||||
tkn_next(); parse_struct(); break;
|
||||
tkn_next(); if (!global_closed) { parse_struct(); } else { HALT("Structs must be defined before functions") } break;
|
||||
case TOKEN_FUNCTION:
|
||||
tkn_next(); parse_function(); break;
|
||||
case TOKEN_REM:
|
||||
tkn_next(); break;
|
||||
case TOKEN_ENDFILE:
|
||||
return;
|
||||
default:
|
||||
HALT("Syntax error");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// [RZC 27/04/2021] No usat en JailScript
|
||||
// XXX [RZC 27/04/2021] No usat en JailBasic
|
||||
/*static void include_labels() {
|
||||
FILE *f = fopen("rom.lbl", "rb");
|
||||
byte num_labels;
|
||||
@@ -793,20 +861,25 @@ static void parse_global_statements() {
|
||||
void parser_parse(const char* buffer, byte* mem) {
|
||||
|
||||
tkn_init(buffer);
|
||||
scope_init();
|
||||
types_init();
|
||||
parser_finished = false;
|
||||
//include_labels();
|
||||
code = mem;
|
||||
codepos = 2; // [RZC 27/04/2021] [TODO] Perquè 2?
|
||||
codepos = 2; // XXX [RZC 27/04/2021] Perquè 2?
|
||||
tkn_next();
|
||||
|
||||
parse_global_statements();
|
||||
append_strings(); // [RZC 27/04/2021] [TODO] Encara vull açò? si el bytecode no ha de ser independent, no veig que faça falta
|
||||
//append_strings(); // XXX [RZC 27/04/2021] Encara vull açò? si el bytecode no ha de ser independent, no veig que faça falta
|
||||
|
||||
if (error_raised()) { // [RZC 27/04/2021] Res, per ara que printf el error i pete
|
||||
if (error_raised()) { // XXX [RZC 27/04/2021] Res, per ara que printf el error i pete
|
||||
error_print(NULL);
|
||||
//codepos = 0xA000;
|
||||
//emmit(OP_JMP);
|
||||
//emmit_w(0xA000);
|
||||
} else {
|
||||
error_print_warnings();
|
||||
decompiler_save(code, codepos);
|
||||
}
|
||||
|
||||
//FILE *f = fopen("test.bin", "wb");
|
||||
@@ -816,11 +889,13 @@ void parser_parse(const char* buffer, byte* mem) {
|
||||
//return code;
|
||||
}
|
||||
|
||||
const int parser_get_codesize() { return codepos; }
|
||||
const int parser_get_memory_usage() { return num_variables; }
|
||||
unsigned short* parser_get_lines() { return lines; }
|
||||
//const int parser_get_codesize() { return codepos; }
|
||||
//const int parser_get_memory_usage() { return num_variables; }
|
||||
//unsigned short* parser_get_lines() { return lines; }
|
||||
|
||||
/*
|
||||
void parser_register_external_function(const char* name, const char* parameters, void (*fun)(void)) {
|
||||
strcpy(external_functions[num_external_functions].name, name);
|
||||
external_functions[num_external_functions++].num_parameters = num_parameters;
|
||||
}
|
||||
*/
|
||||
|
||||
55
parser.h
55
parser.h
@@ -7,49 +7,18 @@ enum OPS {
|
||||
OP_DUP,
|
||||
OP_SWAP,
|
||||
|
||||
OP_LOAD,
|
||||
//OP_LOADI,
|
||||
OP_STORE,
|
||||
//OP_STOREI,
|
||||
/*
|
||||
OP_LOADXY,
|
||||
OP_STOREXY,
|
||||
OP_SETX,
|
||||
OP_SETY,
|
||||
OP_SETZ,
|
||||
OP_GETY,
|
||||
OP_GETZ,
|
||||
OP_INCX,
|
||||
OP_DECX,
|
||||
OP_INCY,
|
||||
OP_DECY,
|
||||
OP_INCZ,
|
||||
OP_DECZ,
|
||||
*/
|
||||
OP_LD,
|
||||
OP_ST,
|
||||
OP_LDL,
|
||||
OP_STL,
|
||||
|
||||
OP_JMP,
|
||||
OP_JNT,
|
||||
OP_JTR,
|
||||
//OP_JSR,
|
||||
OP_RET,
|
||||
OP_CALL,
|
||||
OP_CALLEX, // AFEGIT PER A JAILSCRIPT
|
||||
/*
|
||||
OP_RJ,
|
||||
OP_RB,
|
||||
OP_RJZ,
|
||||
OP_RJN,
|
||||
OP_RBZ,
|
||||
OP_RBN,
|
||||
OP_CALLEX, // AFEGIT PER A JAILBASIC
|
||||
|
||||
OP_RJYZ,
|
||||
OP_RJYN,
|
||||
OP_RBYZ,
|
||||
OP_RBYN,
|
||||
OP_RJZZ,
|
||||
OP_RJZN,
|
||||
OP_RBZZ,
|
||||
OP_RBZN,
|
||||
*/
|
||||
OP_ADD,
|
||||
OP_SUB,
|
||||
OP_MUL,
|
||||
@@ -70,16 +39,14 @@ enum OPS {
|
||||
OP_LEQ,
|
||||
OP_GEQ,
|
||||
|
||||
//OP_IN,
|
||||
//OP_OUT,
|
||||
OP_SLEEP,
|
||||
};
|
||||
|
||||
void parser_parse(const char* buffer, unsigned char* mem);
|
||||
const int parser_get_codesize();
|
||||
const int parser_get_memory_usage();
|
||||
unsigned short* parser_get_lines();
|
||||
//const int parser_get_codesize();
|
||||
//const int parser_get_memory_usage();
|
||||
//unsigned short* parser_get_lines();
|
||||
|
||||
void parser_register_external_function(const char* name, const char* parameters, void (*fun)(void));
|
||||
//void parser_register_external_function(const char* name, const char* parameters, void (*fun)(void));
|
||||
|
||||
void parser_register_constant(const char* name, const unsigned char value);
|
||||
//void parser_register_constant(const char* name, const unsigned char value);
|
||||
119
scope.cpp
119
scope.cpp
@@ -1,50 +1,107 @@
|
||||
#include "scope.h"
|
||||
#include "variables.h"
|
||||
#include "types.h"
|
||||
#include <vector>
|
||||
#include "heap.h"
|
||||
|
||||
struct t_variable {
|
||||
//char name[MAX_IDENTIFIER_LENGTH];
|
||||
std::string name;
|
||||
int type;
|
||||
int length;
|
||||
int address;
|
||||
};
|
||||
|
||||
struct t_struct {
|
||||
//char name[MAX_IDENTIFIER_LENGTH];
|
||||
std::string name;
|
||||
std::vector<t_variable> members;
|
||||
};
|
||||
#include <stack>
|
||||
|
||||
struct t_scope {
|
||||
std::vector<t_variable> variables;
|
||||
t_scope* parent_scope;
|
||||
int total_size;
|
||||
};
|
||||
|
||||
static t_scope scope_global;
|
||||
static t_scope* scope_current = &scope_global;
|
||||
static t_scope global;
|
||||
static t_scope local;
|
||||
static std::stack<int> blocks;
|
||||
static bool are_we_inside_local = false;
|
||||
static t_variable *current_var = NULL;
|
||||
|
||||
void scope_init() {
|
||||
scope_current = &scope_global;
|
||||
scope_global.variables.clear();
|
||||
global.variables.clear();
|
||||
global.total_size = 0;
|
||||
local.variables.clear();
|
||||
local.total_size = 0;
|
||||
while (!blocks.empty()) blocks.pop();
|
||||
are_we_inside_local = false;
|
||||
}
|
||||
|
||||
const bool scope_is_local() {
|
||||
return are_we_inside_local;
|
||||
}
|
||||
|
||||
void scope_open_local() {
|
||||
t_scope* new_scope = new t_scope;
|
||||
new_scope->parent_scope = scope_current;
|
||||
scope_current = new_scope;
|
||||
are_we_inside_local = true;
|
||||
blocks.push(0);
|
||||
}
|
||||
|
||||
void scope_close_local() {
|
||||
t_scope* closing_scope = scope_current;
|
||||
scope_current = scope_current->parent_scope;
|
||||
delete closing_scope;
|
||||
const int scope_close_local() {
|
||||
if (!blocks.empty()) {
|
||||
// Malament, no havem tancat algún block. No se si es detectarà abans per altra part. Per ara anem a deixar este comentari.
|
||||
}
|
||||
const int return_value = local.total_size;
|
||||
while (!blocks.empty()) blocks.pop();
|
||||
local.variables.clear();
|
||||
local.total_size = 0;
|
||||
are_we_inside_local = false;
|
||||
return return_value;
|
||||
}
|
||||
|
||||
const int scope_declare_variable(const std::string name, const int type, const int length) {
|
||||
for (t_variable v : scope_current->variables) { if (v.name == name) return -1; }
|
||||
const int address = heap_get_address();
|
||||
void scope_open_block() {
|
||||
blocks.push(local.variables.size());
|
||||
}
|
||||
|
||||
void scope_close_block() {
|
||||
const int size_before_block = blocks.top();
|
||||
blocks.pop();
|
||||
while (local.variables.size() > size_before_block) local.variables.pop_back();
|
||||
}
|
||||
|
||||
const int scope_declare_variable(const std::string name, const uint32_t type, const uint32_t length) {
|
||||
t_scope& scope = (are_we_inside_local ? local : global);
|
||||
if (are_we_inside_local) {
|
||||
for (int i = blocks.top(); i < scope.variables.size(); i++ ) if (scope.variables[i].name == name) return -1;
|
||||
} else {
|
||||
for (t_variable v : scope.variables) if (v.name == name) return -1;
|
||||
}
|
||||
const uint32_t address = scope.total_size;
|
||||
const t_variable var {name, type, length, address};
|
||||
scope_current->variables.push_back(var);
|
||||
scope.variables.push_back(var);
|
||||
scope.total_size += types_get_length(type) * (length == 0 ? 1 : length);
|
||||
return address;
|
||||
}
|
||||
|
||||
const bool scope_variable_exists(const std::string name, const bool can_shadow) {
|
||||
t_scope& scope = (are_we_inside_local ? local : global);
|
||||
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;
|
||||
}
|
||||
|
||||
const uint32_t scope_get_variable_address() {
|
||||
if (current_var == NULL) {
|
||||
// ERROR INTERN
|
||||
}
|
||||
return current_var->address;
|
||||
}
|
||||
|
||||
const int scope_get_variable_size() {
|
||||
if (current_var == NULL) {
|
||||
// ERROR INTERN
|
||||
}
|
||||
return current_var->length;
|
||||
}
|
||||
|
||||
const int scope_get_variable_type() {
|
||||
if (current_var == NULL) {
|
||||
// ERROR INTERN
|
||||
}
|
||||
return current_var->type;
|
||||
}
|
||||
|
||||
15
scope.h
15
scope.h
@@ -1,8 +1,17 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
void scope_init();
|
||||
const bool scope_is_local();
|
||||
void scope_open_local();
|
||||
void scope_close_local();
|
||||
const int scope_declare_variable(const std::string name, const int type, const int length);
|
||||
//scope_get_variable...
|
||||
const int scope_close_local();
|
||||
void scope_open_block();
|
||||
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 can_shadow = false);
|
||||
const uint32_t scope_get_variable_address();
|
||||
const int scope_get_variable_size();
|
||||
const int scope_get_variable_type();
|
||||
|
||||
29
test.vb
Normal file
29
test.vb
Normal file
@@ -0,0 +1,29 @@
|
||||
' Esto es un comentario
|
||||
struct point
|
||||
x as number
|
||||
y as array of 5 number
|
||||
end
|
||||
|
||||
struct triangle
|
||||
a as point
|
||||
b as point
|
||||
c as point
|
||||
end
|
||||
|
||||
var peiv as array of 2 triangle
|
||||
const perico as number = 4-peiv[1].a.x * peiv[0].c.y[2]
|
||||
|
||||
function tarari(a as number, b as number) as number
|
||||
var local1 as number
|
||||
if local1 > 0 then
|
||||
var local1 as number = 1
|
||||
for i = 0 to 10
|
||||
var local1 as number = local1 + 1
|
||||
end
|
||||
return local1
|
||||
else
|
||||
var local3 as number = 2
|
||||
end
|
||||
return 1
|
||||
end
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "tokenizer.h"
|
||||
#include "error.h"
|
||||
#include <string>
|
||||
|
||||
static bool streq(const char* a, const char* b) {
|
||||
while (*a != 0 && *b != 0) {
|
||||
@@ -79,8 +80,8 @@ static void tkn_do_next() {
|
||||
if (CCHR >= 48 && CCHR <= 57) {
|
||||
do { value = value * 10 + (CCHR - 48); NEXT; } while (CCHR >= 48 && CCHR <= 57);
|
||||
if (CCHR == '.') {
|
||||
int d = 10;
|
||||
do { value = value + ((CCHR - 48) / d); d *= 10; NEXT; } while (CCHR >= 48 && CCHR <= 57);
|
||||
float d = 0.1f; NEXT;
|
||||
do { value = value + (float(CCHR - 48) * d); d *= 0.1f; NEXT; } while (CCHR >= 48 && CCHR <= 57);
|
||||
}
|
||||
current_token = TOKEN_NUMBER; return;
|
||||
}
|
||||
@@ -118,7 +119,7 @@ static void tkn_do_next() {
|
||||
if (CCHR == '%') { NEXT; current_token = TOKEN_MOD; return; }
|
||||
if (CCHR == 39) { NEXT; current_token = TOKEN_REM; while (CCHR != 0 && CCHR != 10) { NEXT; }; return; }
|
||||
|
||||
// Per a agafar numeros en hexadecimal o binari, heretat de PaCO, no se si li fa falta a JailScript
|
||||
// Per a agafar numeros en hexadecimal o binari, heretat de PaCO, no se si li fa falta a JailBasic
|
||||
/*if (CCHR == '&') {
|
||||
NEXT;
|
||||
if ((CCHR | 32) == 'h') {
|
||||
|
||||
66
types.cpp
Normal file
66
types.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
#include "types.h"
|
||||
#include "variables.h"
|
||||
#include <vector>
|
||||
|
||||
struct t_struct {
|
||||
std::string name;
|
||||
uint32_t size;
|
||||
std::vector<t_variable> members;
|
||||
};
|
||||
static std::vector<t_struct> types;
|
||||
|
||||
void types_init() {
|
||||
types.clear();
|
||||
const t_struct type_number {"number", 4}; types.push_back(type_number);
|
||||
const t_struct type_string {"string", 4}; types.push_back(type_string);
|
||||
}
|
||||
|
||||
const int types_add(const std::string name) {
|
||||
for (auto t : types) if (t.name == name) return -1;
|
||||
t_struct new_type {name, 0};
|
||||
types.push_back(new_type);
|
||||
return types.size()-1;
|
||||
}
|
||||
|
||||
const int types_exist(const std::string name) {
|
||||
for (int i = 0; i < types.size(); i++) if (types[i].name == name) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int types_get_length(const uint32_t type) {
|
||||
if (type >= types.size()) return -1; // ERROR INTERN: No deuria donar-se mai
|
||||
return types[type].size;
|
||||
}
|
||||
|
||||
const int types_add_member(const uint32_t type, const std::string name, const uint32_t var_type, const uint32_t length) {
|
||||
if (type >= types.size()) return -1; // ERROR INTERN: No deuria donar-se mai
|
||||
for (auto m : types[type].members) if (m.name == name) return -1;
|
||||
const t_variable new_var {name, var_type, length, types[type].size};
|
||||
types[type].members.push_back(new_var);
|
||||
types[type].size += types_get_length(var_type) * length;
|
||||
return types[type].members.size()-1;
|
||||
}
|
||||
|
||||
const int types_member_exists(const uint32_t type, const std::string name) {
|
||||
if (type >= types.size()) return -1; // ERROR INTERN: No deuria donar-se mai
|
||||
for (int i = 0; i < types[type].members.size(); i++) if (types[type].members[i].name == name) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int types_get_member_type(const uint32_t type, const uint32_t member) {
|
||||
if (type >= types.size()) return -1; // ERROR INTERN: No deuria donar-se mai
|
||||
if (member >= types[type].members.size()) return -1; // ERROR INTERN: No deuria donar-se mai
|
||||
return types[type].members[member].type;
|
||||
}
|
||||
|
||||
const int types_get_member_length(const uint32_t type, const uint32_t member) {
|
||||
if (type >= types.size()) return -1; // ERROR INTERN: No deuria donar-se mai
|
||||
if (member >= types[type].members.size()) return -1; // ERROR INTERN: No deuria donar-se mai
|
||||
return types[type].members[member].length;
|
||||
}
|
||||
|
||||
const int types_get_member_offset(const uint32_t type, const uint32_t member) {
|
||||
if (type >= types.size()) return -1; // ERROR INTERN: No deuria donar-se mai
|
||||
if (member >= types[type].members.size()) return -1; // ERROR INTERN: No deuria donar-se mai
|
||||
return types[type].members[member].address;
|
||||
}
|
||||
14
types.h
Normal file
14
types.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
void types_init();
|
||||
|
||||
const int types_add(const std::string name);
|
||||
const int types_exist(const std::string name);
|
||||
const int types_get_length(const uint32_t type);
|
||||
|
||||
const int types_add_member(const uint32_t type, const std::string name, const uint32_t var_type, const uint32_t length);
|
||||
const int types_member_exists(const uint32_t type, const std::string name);
|
||||
const int types_get_member_type(const uint32_t type, const uint32_t member);
|
||||
const int types_get_member_length(const uint32_t type, const uint32_t member);
|
||||
const int types_get_member_offset(const uint32_t type, const uint32_t member);
|
||||
8
variables.h
Normal file
8
variables.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
struct t_variable {
|
||||
std::string name;
|
||||
uint32_t type;
|
||||
uint32_t length;
|
||||
uint32_t address;
|
||||
};
|
||||
Reference in New Issue
Block a user