863 lines
24 KiB
C++
863 lines
24 KiB
C++
#include "parser.h"
|
|
#include "tokenizer.h"
|
|
#include "scope.h"
|
|
#include "types.h"
|
|
#include "error.h"
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#define MAX_CODE_SIZE 65536
|
|
#define MAX_LABELS 256
|
|
#define MAX_FUNCTIONS 256
|
|
#define MAX_EXTERNAL_FUNCTIONS 256
|
|
#define MAX_IDENTIFIER_LENGTH 40
|
|
#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;
|
|
};
|
|
|
|
/*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];
|
|
int num_parameters = 0;
|
|
};
|
|
|
|
struct t_string {
|
|
unsigned char string[256];
|
|
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 int num_known_labels = 0;
|
|
static t_label unknown_labels[MAX_LABELS];
|
|
static int num_unknown_labels = 0;
|
|
static int num_anonymous_labels = 0;
|
|
|
|
static char* breaklabel = nullptr;
|
|
static char* contlabel = nullptr;
|
|
|
|
/*
|
|
static t_variable* variables = nullptr;
|
|
static int num_variables = 0;
|
|
static bool variable_is_array = false;
|
|
|
|
static t_external_function external_functions[MAX_EXTERNAL_FUNCTIONS];
|
|
static int num_external_functions = 0;
|
|
|
|
static t_string strings[256];
|
|
static int num_strings = 0;
|
|
|
|
static t_constant constants[MAX_CONSTANTS];
|
|
static int num_constants;
|
|
*/
|
|
|
|
static bool parser_finished = 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;
|
|
int i = 6;
|
|
while (value > 0) {
|
|
label[i] = 48 + (value % 10);
|
|
value = value / 10;
|
|
i--;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************************/
|
|
/* BYTECODE GENERATOR */
|
|
/****************************************************************************************/
|
|
|
|
static void emmit(const byte value) {
|
|
lines[codepos] = current_line;
|
|
code[codepos++] = value;
|
|
}
|
|
|
|
static void emmit_w(const word value) {
|
|
lines[codepos] = current_line;
|
|
code[codepos++] = value & 255;
|
|
lines[codepos] = current_line;
|
|
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++);
|
|
lines[codepos] = current_line; code[codepos++] = *(v++);
|
|
lines[codepos] = current_line; code[codepos++] = *(v++);
|
|
lines[codepos] = current_line; code[codepos++] = *(v++);
|
|
}
|
|
|
|
static void patch(const uint32_t address, const word dest) {
|
|
code[address] = dest & 255;
|
|
code[address + 1] = dest >> 8;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/****************************************************************************************/
|
|
/* 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++;
|
|
return 0;
|
|
}
|
|
|
|
static void register_label_address(const char* string) {
|
|
// 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;
|
|
}
|
|
}
|
|
// 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();
|
|
// 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++;
|
|
}
|
|
}
|
|
//num_known_labels++;
|
|
}
|
|
|
|
static void generate_anonymous_labelname(char* dest) {
|
|
int_to_string(num_anonymous_labels++, dest);
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
/****************************************************************************************/
|
|
/* PARSER */
|
|
/****************************************************************************************/
|
|
|
|
static void parse_expression();
|
|
static void parse_statements();
|
|
|
|
/* XXX [RZC 27/04/2021] No usat en JailBasic
|
|
//static void parse_strleft();
|
|
static void parse_str();
|
|
static void parse_chr();
|
|
|
|
static void parse_strlen();
|
|
static void parse_keypressed();
|
|
static void parse_anykey();
|
|
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) {
|
|
emmit(OP_SETX);
|
|
emmit_w(register_string(tkn_get_string()));
|
|
emmit(OP_JSR);
|
|
emmit_w(get_label_address("_sys_string_load"));
|
|
tkn_next();
|
|
return;
|
|
}
|
|
if (tkn_get_token() == TOKEN_HEXSTRING) {
|
|
emmit(OP_SETX);
|
|
emmit_w(register_array(tkn_get_array()));
|
|
emmit(OP_JSR);
|
|
emmit_w(get_label_address("_sys_string_load"));
|
|
tkn_next();
|
|
return;
|
|
}
|
|
if (tkn_get_token() == TOKEN_IDENTIFIER) {
|
|
int ivar = get_variable_index(tkn_get_string());
|
|
if (!is_variable_array()) { parser_finished = true; error_raise("Expected string constant or variable"); return; }
|
|
emmit(OP_SETX);
|
|
emmit_w(ivar);
|
|
emmit(OP_JSR);
|
|
emmit_w(get_label_address("_sys_string_load"));
|
|
tkn_next();
|
|
return;
|
|
}
|
|
if (tkn_get_token() == TOKEN_STRLEFT) { tkn_next(); parse_strleft(); return; }
|
|
if (tkn_get_token() == TOKEN_STR) { tkn_next(); parse_str(); return; }
|
|
if (tkn_get_token() == TOKEN_CHR) { tkn_next(); parse_chr(); return; }
|
|
parser_finished = true; error_raise("Syntax error");
|
|
return;
|
|
}
|
|
|
|
static void parse_concatenation() {
|
|
parse_concat_atom();
|
|
while (tkn_get_token() == TOKEN_COMMA) {
|
|
tkn_next(); parse_concat_atom();
|
|
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
|
|
if (tkn_get_token() == TOKEN_NUMBER) {
|
|
emmit(OP_PUSH);
|
|
emmit_f(tkn_get_value());
|
|
tkn_next();
|
|
return;
|
|
}
|
|
if (tkn_get_token() == TOKEN_IDENTIFIER) {
|
|
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(address);
|
|
tkn_next();
|
|
return;
|
|
} else {
|
|
// 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();
|
|
emmit(OP_NEG);
|
|
return;
|
|
}
|
|
if (tkn_get_token() == TOKEN_NOT) {
|
|
tkn_next();
|
|
parse_expr_atom();
|
|
emmit(OP_NOT);
|
|
return;
|
|
}
|
|
if (tkn_get_token() == TOKEN_LPAR) {
|
|
tkn_next();
|
|
parse_expression();
|
|
EXPECT(TOKEN_RPAR, "Expected ')'");
|
|
tkn_next();
|
|
return;
|
|
}
|
|
parser_finished = true; error_raise("Syntax error");
|
|
return;
|
|
}
|
|
|
|
static void parse_expr_mul() {
|
|
parse_expr_atom();
|
|
while (tkn_get_token() == TOKEN_ASTERISC || tkn_get_token() == TOKEN_SLASH || tkn_get_token() == TOKEN_MOD) {
|
|
t_tokentype operat = tkn_get_token();
|
|
tkn_next();
|
|
parse_expr_atom();
|
|
switch (operat) {
|
|
case TOKEN_ASTERISC: emmit(OP_MUL); break;
|
|
case TOKEN_SLASH: emmit(OP_DIV); break;
|
|
case TOKEN_MOD: emmit(OP_MOD); break;
|
|
default: /* Impossible */ break;
|
|
}
|
|
}
|
|
}
|
|
static void parse_expr_sum() {
|
|
parse_expr_mul();
|
|
while (tkn_get_token() == TOKEN_PLUS || tkn_get_token() == TOKEN_MINUS) {
|
|
t_tokentype operat = tkn_get_token();
|
|
tkn_next();
|
|
parse_expr_mul();
|
|
switch (operat) {
|
|
case TOKEN_PLUS: emmit(OP_ADD); break;
|
|
case TOKEN_MINUS: emmit(OP_SUB); break;
|
|
default: /* Impossible */ break;
|
|
}
|
|
}
|
|
}
|
|
static void parse_expr_bool() {
|
|
parse_expr_sum();
|
|
while (tkn_get_token() == TOKEN_AND || tkn_get_token() == TOKEN_OR) {
|
|
t_tokentype operat = tkn_get_token();
|
|
tkn_next();
|
|
parse_expr_sum();
|
|
switch (operat) {
|
|
case TOKEN_AND: emmit(OP_AND); break;
|
|
case TOKEN_OR: emmit(OP_OR); break;
|
|
default: /* Impossible */ break;
|
|
}
|
|
}
|
|
}
|
|
static void parse_expression() {
|
|
parse_expr_bool();
|
|
while (tkn_get_token() == TOKEN_EQ || tkn_get_token() == TOKEN_NEQ || tkn_get_token() == TOKEN_LT || tkn_get_token() == TOKEN_GT || tkn_get_token() == TOKEN_LEQ || tkn_get_token() == TOKEN_GEQ) {
|
|
t_tokentype operat = tkn_get_token();
|
|
tkn_next();
|
|
parse_expr_bool();
|
|
switch (operat) {
|
|
case TOKEN_EQ: emmit(OP_EQ); break;
|
|
case TOKEN_NEQ: emmit(OP_NEQ); break;
|
|
case TOKEN_LT: emmit(OP_LT); break;
|
|
case TOKEN_GT: emmit(OP_GT); break;
|
|
case TOKEN_LEQ: emmit(OP_LEQ); break;
|
|
case TOKEN_GEQ: emmit(OP_GEQ); break;
|
|
default: /* Impossible */ break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool identifier_exists(const std::string identifier) {
|
|
if (scope_variable_exists(identifier)) return true;
|
|
if (types_exist(identifier) != -1) 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)) 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(); 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)) 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");
|
|
char struct_name[40];
|
|
strcpy(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'");
|
|
// TODO [RZC 04/05/2021] Implement support for arrays
|
|
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");
|
|
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");
|
|
types_add_member(struct_num, member_name, type_num, member_length);
|
|
tkn_next();
|
|
}
|
|
tkn_next();
|
|
}
|
|
|
|
/*static void parse_dim() {
|
|
EXPECT(TOKEN_IDENTIFIER, "Expected variable");
|
|
char varname[40];
|
|
strcpy(varname, tkn_get_string());
|
|
tkn_next(); EXPECT(TOKEN_LPAR, "Expected array size");
|
|
tkn_next(); EXPECT(TOKEN_NUMBER, "Expected integer constant as array size");
|
|
get_variable_index(varname, tkn_get_value()); // register variable with size, no need to keep ival
|
|
tkn_next(); EXPECT(TOKEN_RPAR, "Expected ')'");
|
|
tkn_next();
|
|
}*/
|
|
// 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());
|
|
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);
|
|
emmit(OP_INC);
|
|
emmit(OP_STOREI);
|
|
emmit_w(ivar);
|
|
} else {
|
|
emmit(OP_LOAD);
|
|
emmit_w(ivar);
|
|
emmit(OP_INC);
|
|
emmit(OP_STORE);
|
|
emmit_w(ivar);
|
|
}
|
|
tkn_next();
|
|
}
|
|
|
|
static void parse_dec() {
|
|
EXPECT(TOKEN_IDENTIFIER, "Expected variable");
|
|
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);
|
|
emmit(OP_DEC);
|
|
emmit(OP_STOREI);
|
|
emmit_w(ivar);
|
|
}
|
|
else {
|
|
emmit(OP_LOAD);
|
|
emmit_w(ivar);
|
|
emmit(OP_DEC);
|
|
emmit(OP_STORE);
|
|
emmit_w(ivar);
|
|
}
|
|
tkn_next();
|
|
}*/
|
|
|
|
// 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());
|
|
if (is_variable_array()) {
|
|
tkn_next();
|
|
if (tkn_get_token() == TOKEN_COLON) {
|
|
tkn_next(); parse_concatenation();
|
|
emmit(OP_SETX);
|
|
emmit_w(ivar);
|
|
emmit(OP_JSR);
|
|
emmit_w(get_label_address("_sys_string_store"));
|
|
return;
|
|
} else {
|
|
EXPECT(TOKEN_LPAR, "Expected ':' or '('");
|
|
tkn_next(); parse_expr_atom();
|
|
EXPECT(TOKEN_RPAR, "Expected ')'");
|
|
emmit(OP_SETY);
|
|
}
|
|
}
|
|
tkn_next();
|
|
EXPECT(TOKEN_EQ, "Expected '='");
|
|
tkn_next(); parse_expression();
|
|
if (is_variable_array()) {
|
|
emmit(OP_STOREI);
|
|
emmit_w(ivar);
|
|
} else {
|
|
emmit(OP_STORE);
|
|
emmit_w(ivar);
|
|
}
|
|
}*/
|
|
|
|
/*
|
|
static void parse_if() {
|
|
char* 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);
|
|
breaklabel = endlabel;
|
|
bool else_visited = false;
|
|
emmit_w(get_label_address(elselabel));
|
|
parse_statements();
|
|
if (tkn_get_token() == TOKEN_ELSE) {
|
|
else_visited = true;
|
|
emmit(OP_JMP);
|
|
emmit_w(get_label_address(endlabel));
|
|
register_label_address(elselabel);
|
|
tkn_next();
|
|
parse_statements();
|
|
}
|
|
if (tkn_get_token() == TOKEN_END) {
|
|
if (!else_visited) register_label_address(elselabel);
|
|
register_label_address(endlabel);
|
|
tkn_next();
|
|
breaklabel = previous_breaklabel;
|
|
return;
|
|
}
|
|
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;
|
|
EXPECT(TOKEN_IDENTIFIER, "Expected variable");
|
|
int ivar = get_variable_index(tkn_get_string());
|
|
tkn_next();
|
|
EXPECT(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);
|
|
breaklabel = endlabel;
|
|
contlabel = continuelabel;
|
|
register_label_address(forlabel);
|
|
EXPECT(TOKEN_TO, "Expected 'TO'");
|
|
tkn_next();
|
|
parse_expression();
|
|
emmit(OP_LOAD);
|
|
emmit_w(ivar);
|
|
emmit(OP_EQ);
|
|
emmit(OP_JTR);
|
|
emmit_w(get_label_address(endlabel));
|
|
//int endLabel = GetCurrentAddress();
|
|
parse_statements();
|
|
EXPECT(TOKEN_END, "Expected 'END'");
|
|
tkn_next();
|
|
register_label_address(continuelabel);
|
|
emmit(OP_LOAD);
|
|
emmit_w(ivar);
|
|
emmit(OP_INC);
|
|
emmit(OP_STORE);
|
|
emmit_w(ivar);
|
|
emmit(OP_JMP);
|
|
emmit_w(get_label_address(forlabel));
|
|
register_label_address(endlabel);
|
|
//Patch(endLabel, GetCurrentAddress());
|
|
breaklabel = previous_breaklabel;
|
|
contlabel = previous_contlabel;
|
|
}
|
|
|
|
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);
|
|
emmit_w(get_label_address(breaklabel));
|
|
}
|
|
|
|
static void parse_continue() {
|
|
if (contlabel == nullptr) { parser_finished = true; error_raise("Can't continue outside of a loop"); return; }
|
|
emmit(OP_JMP);
|
|
emmit_w(get_label_address(contlabel));
|
|
}
|
|
*/
|
|
|
|
// XXX [RZC 27/04/2021] Ni GOTO ni GOSUB
|
|
/*static void parse_goto() {
|
|
emmit(OP_JMP);
|
|
EXPECT(TOKEN_IDENTIFIER, "Expected label name");
|
|
emmit_w(get_label_address(tkn_get_string()));
|
|
tkn_next();
|
|
}
|
|
|
|
static void parse_gosub() {
|
|
emmit(OP_JSR);
|
|
EXPECT(TOKEN_IDENTIFIER, "Expected label name");
|
|
emmit_w(get_label_address(tkn_get_string()));
|
|
tkn_next();
|
|
}*/
|
|
|
|
/*
|
|
static void parse_return() {
|
|
// TODO [RZC 27/04/2021] Falta afegir paràmetre de retorn
|
|
emmit(OP_RET);
|
|
}
|
|
*/
|
|
|
|
// 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) {
|
|
if (external_functions[i].num_parameters == -1) {
|
|
tkn_next();
|
|
EXPECT(TOKEN_STRING, "Expected string");
|
|
emmit(OP_PUSH);
|
|
emmit(register_string(tkn_get_string()));
|
|
} else {
|
|
tkn_next();
|
|
for (int j = 0; j < external_functions[i].num_parameters; j++) {
|
|
//if (j != 0) EXPECT(TOKEN_COMMA, "Expected comma");
|
|
parse_expression();
|
|
}
|
|
}
|
|
emmit(OP_CALL);
|
|
emmit(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void parse_statements() {
|
|
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;
|
|
case TOKEN_IF:
|
|
tkn_next(); parse_if(); break;
|
|
case TOKEN_FOR:
|
|
tkn_next(); parse_for(); break;
|
|
case TOKEN_BREAK:
|
|
tkn_next(); parse_break(); break;
|
|
case TOKEN_CONTINUE:
|
|
tkn_next(); parse_continue(); break;
|
|
case TOKEN_RETURN:
|
|
tkn_next(); parse_return(); 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
*/
|
|
static void parse_global_statements() {
|
|
while (!parser_finished) {
|
|
current_line = tkn_get_line();
|
|
switch (tkn_get_token()) {
|
|
case TOKEN_CONST:
|
|
tkn_next(); parse_const(); break;
|
|
case TOKEN_VAR:
|
|
tkn_next(); parse_var(); break;
|
|
case TOKEN_STRUCT:
|
|
tkn_next(); parse_struct(); break;
|
|
/*case TOKEN_FUNCTION:
|
|
tkn_next(); parse_function(); break;*/
|
|
case TOKEN_REM:
|
|
tkn_next(); break;
|
|
case TOKEN_ENDFILE:
|
|
return;
|
|
default:
|
|
HALT("Syntax error");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// XXX [RZC 27/04/2021] No usat en JailBasic
|
|
/*static void include_labels() {
|
|
FILE *f = fopen("rom.lbl", "rb");
|
|
byte num_labels;
|
|
fread(&num_labels, 1, 1, f);
|
|
for (int i = 0; i < num_labels; i++) {
|
|
word address; fread(&address, 2, 1, f);
|
|
byte len; fread(&len, 1, 1, f);
|
|
char label[50];
|
|
fread(label, len, 1, f);
|
|
label[len] = 0;
|
|
strcpy(known_labels[num_known_labels].name, label);
|
|
known_labels[num_known_labels++].address = address;
|
|
}
|
|
fclose(f);
|
|
|
|
}*/
|
|
|
|
/****************************************************************************************/
|
|
/* INTERFACE */
|
|
/****************************************************************************************/
|
|
|
|
void parser_parse(const char* buffer, byte* mem) {
|
|
|
|
tkn_init(buffer);
|
|
scope_init();
|
|
types_init();
|
|
parser_finished = false;
|
|
//include_labels();
|
|
code = mem;
|
|
codepos = 2; // XXX [RZC 27/04/2021] Perquè 2?
|
|
tkn_next();
|
|
|
|
parse_global_statements();
|
|
//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()) { // 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);
|
|
}
|
|
|
|
//FILE *f = fopen("test.bin", "wb");
|
|
//fwrite(mem, codepos, 1, f);
|
|
//fclose(f);
|
|
|
|
//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; }
|
|
|
|
/*
|
|
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;
|
|
}
|
|
*/
|