Now 'vbgame' is included inside this project. Some fixes.
This commit is contained in:
18
error.cpp
Normal file
18
error.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "error.h"
|
||||
#include <stdio.h>
|
||||
#include "tokenizer.h"
|
||||
|
||||
static char errormsg[255];
|
||||
static bool raised = false;
|
||||
|
||||
|
||||
void error_raise(const char* msg) {
|
||||
raised = true;
|
||||
sprintf(errormsg, "ERROR: %s at %d:%d.", msg, tkn_get_line()+1, tkn_get_row()+1);
|
||||
}
|
||||
|
||||
bool error_raised() { return raised; }
|
||||
|
||||
void error_print() {
|
||||
printf("%s", errormsg);
|
||||
}
|
||||
5
error.h
Normal file
5
error.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
void error_raise(const char* msg);
|
||||
bool error_raised();
|
||||
void error_print();
|
||||
2
main.cpp
2
main.cpp
@@ -7,7 +7,7 @@
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
vm_init("test.bin");
|
||||
vm_init("test.bas");
|
||||
vdp_init();
|
||||
vm_register_out_port(10, vdp_data_out);
|
||||
vm_register_out_port(11, vdp_cmd_out);
|
||||
|
||||
793
parser.cpp
Normal file
793
parser.cpp
Normal file
@@ -0,0 +1,793 @@
|
||||
#include "parser.h"
|
||||
#include "tokenizer.h"
|
||||
#include "error.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_CODE_SIZE 65536
|
||||
#define MAX_LABELS 256
|
||||
#define MAX_EXTERNAL_FUNCTIONS 256
|
||||
#define MAX_IDENTIFIER_LENGTH 40
|
||||
|
||||
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 {
|
||||
char string[256];
|
||||
word references[256];
|
||||
int num_references = 1;
|
||||
};
|
||||
|
||||
static byte* code; // [MAX_CODE_SIZE];
|
||||
static word codepos = 0;
|
||||
|
||||
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 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;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
/* BYTECODE GENERATOR */
|
||||
/****************************************************************************************/
|
||||
|
||||
static void emmit(const byte value) {
|
||||
code[codepos++] = value;
|
||||
}
|
||||
|
||||
static void emmit_w(const word value) {
|
||||
code[codepos++] = value & 255;
|
||||
code[codepos++] = value >> 8;
|
||||
}
|
||||
|
||||
static void patch(const word address, const word dest) {
|
||||
code[address] = dest & 255;
|
||||
code[address + 1] = dest >> 8;
|
||||
}
|
||||
|
||||
static const word 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; }
|
||||
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;
|
||||
}
|
||||
|
||||
static bool is_variable_array() { return variable_is_array; }
|
||||
|
||||
/****************************************************************************************/
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
/* STRING MANAGEMENT */
|
||||
/****************************************************************************************/
|
||||
|
||||
static int register_string(const char* string) {
|
||||
for (int i = 0; i < num_strings; i++) {
|
||||
if (strcmp(strings[i].string, string) == 0) { strings[i].references[strings[i].num_references++] = get_current_address(); return 0; }
|
||||
}
|
||||
strcpy(strings[num_strings].string, string);
|
||||
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 = strlen(strings[i].string);
|
||||
emmit(len);
|
||||
for (int j = 0; j < len; j++) { emmit(strings[i].string[j]); }
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
/* PARSER */
|
||||
/****************************************************************************************/
|
||||
|
||||
static void parse_expression();
|
||||
static void parse_statements();
|
||||
|
||||
#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);
|
||||
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_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;
|
||||
}
|
||||
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 void parse_expr_atom() {
|
||||
// NUM, VAR, UNARY, PAREN
|
||||
if (tkn_get_token() == TOKEN_NUMBER) {
|
||||
emmit(OP_PUSH);
|
||||
emmit(tkn_get_value());
|
||||
tkn_next();
|
||||
return;
|
||||
}
|
||||
if (tkn_get_token() == TOKEN_IDENTIFIER) {
|
||||
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);
|
||||
}
|
||||
tkn_next();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void parse_expression() {
|
||||
parse_expr_bool();
|
||||
while (tkn_get_token() == TOKEN_EQ || 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_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
int ivar = get_variable_index(varname, tkn_get_value());
|
||||
tkn_next(); EXPECT(TOKEN_RPAR, "Expected ')'");
|
||||
tkn_next();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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() {
|
||||
emmit(OP_RET);
|
||||
}
|
||||
|
||||
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_strleft() {
|
||||
EXPECT(TOKEN_IDENTIFIER, "Expected variable");
|
||||
int ivar = get_variable_index(tkn_get_string());
|
||||
tkn_next(); parse_expression();
|
||||
emmit(OP_SETX);
|
||||
emmit_w(ivar);
|
||||
emmit(OP_JSR);
|
||||
emmit_w(get_label_address("_sys_string_left"));
|
||||
}
|
||||
|
||||
static void parse_strlen() {
|
||||
EXPECT(TOKEN_IDENTIFIER, "Expected variable");
|
||||
int ivar = get_variable_index(tkn_get_string());
|
||||
emmit(OP_LOAD);
|
||||
emmit_w(ivar);
|
||||
tkn_next();
|
||||
}
|
||||
|
||||
static void parse_debug() {
|
||||
parse_expression();
|
||||
emmit(OP_JSR);
|
||||
emmit_w(get_label_address("_sys_string_debug"));
|
||||
}
|
||||
|
||||
static void parse_chr() {
|
||||
parse_expression();
|
||||
emmit(OP_PUSH);
|
||||
emmit(1);
|
||||
}
|
||||
|
||||
static void parse_str() {
|
||||
parse_expression();
|
||||
emmit(OP_JSR);
|
||||
emmit_w(get_label_address("_sys_string_str"));
|
||||
}
|
||||
|
||||
static void parse_setsprite() {
|
||||
parse_expression();
|
||||
parse_expression();
|
||||
parse_expression();
|
||||
emmit(OP_JSR);
|
||||
emmit_w(get_label_address("_sys_vdp_setsprite"));
|
||||
}
|
||||
|
||||
static void parse_putsprite() {
|
||||
parse_expression();
|
||||
parse_expression();
|
||||
parse_expression();
|
||||
emmit(OP_JSR);
|
||||
emmit_w(get_label_address("_sys_vdp_putsprite"));
|
||||
}
|
||||
|
||||
static void parse_locate() {
|
||||
parse_expression();
|
||||
parse_expression();
|
||||
emmit(OP_JSR);
|
||||
emmit_w(get_label_address("_sys_vdp_locate"));
|
||||
}
|
||||
|
||||
static void parse_print() {
|
||||
parse_concatenation();
|
||||
emmit(OP_JSR);
|
||||
emmit_w(get_label_address("_sys_vdp_print"));
|
||||
}
|
||||
|
||||
static void parse_putchar() {
|
||||
parse_expression();
|
||||
parse_expression();
|
||||
parse_expression();
|
||||
parse_expression();
|
||||
emmit(OP_JSR);
|
||||
emmit_w(get_label_address("_sys_vdp_putchar"));
|
||||
}
|
||||
|
||||
static void parse_setchar() {
|
||||
parse_expression();
|
||||
parse_concatenation();
|
||||
emmit(OP_JSR);
|
||||
emmit_w(get_label_address("_sys_vdp_setchar"));
|
||||
}
|
||||
|
||||
static void parse_keypressed() {
|
||||
parse_expression();
|
||||
emmit(OP_JSR);
|
||||
emmit_w(get_label_address("_sys_input_keypressed"));
|
||||
}
|
||||
|
||||
static void parse_anykey() {
|
||||
emmit(OP_PUSH);
|
||||
emmit(0);
|
||||
emmit(OP_JSR);
|
||||
emmit_w(get_label_address("_sys_input_keypressed"));
|
||||
}
|
||||
|
||||
static void parse_updatescr() {
|
||||
emmit(OP_JSR);
|
||||
emmit_w(get_label_address("_sys_vdp_flip"));
|
||||
}
|
||||
|
||||
static void parse_color() {
|
||||
parse_expression();
|
||||
emmit(OP_JSR);
|
||||
emmit_w(get_label_address("_sys_vdp_color"));
|
||||
}
|
||||
|
||||
static void parse_border() {
|
||||
parse_expression();
|
||||
emmit(OP_JSR);
|
||||
emmit_w(get_label_address("_sys_vdp_border"));
|
||||
}
|
||||
|
||||
static void parse_statements() {
|
||||
while (!parser_finished) {
|
||||
switch (tkn_get_token()) {
|
||||
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_GOTO:
|
||||
tkn_next(); parse_goto(); break;
|
||||
case TOKEN_GOSUB:
|
||||
tkn_next(); parse_gosub(); break;
|
||||
case TOKEN_RETURN:
|
||||
tkn_next(); parse_return(); break;
|
||||
case TOKEN_LABEL:
|
||||
parse_label(); break;
|
||||
case TOKEN_REM:
|
||||
tkn_next(); break;
|
||||
|
||||
case TOKEN_STRLEFT:
|
||||
tkn_next(); parse_strleft(); break;
|
||||
case TOKEN_STRLEN:
|
||||
tkn_next(); parse_strlen(); break;
|
||||
case TOKEN_DEBUG:
|
||||
tkn_next(); parse_debug(); break;
|
||||
case TOKEN_CHR:
|
||||
tkn_next(); parse_chr(); break;
|
||||
case TOKEN_STR:
|
||||
tkn_next(); parse_str(); break;
|
||||
case TOKEN_SETSPRITE:
|
||||
tkn_next(); parse_setsprite(); break;
|
||||
case TOKEN_PUTSPRITE:
|
||||
tkn_next(); parse_putsprite(); break;
|
||||
case TOKEN_LOCATE:
|
||||
tkn_next(); parse_locate(); break;
|
||||
case TOKEN_PRINT:
|
||||
tkn_next(); parse_print(); break;
|
||||
case TOKEN_PUTCHAR:
|
||||
tkn_next(); parse_putchar(); break;
|
||||
case TOKEN_SETCHAR:
|
||||
tkn_next(); parse_setchar(); break;
|
||||
case TOKEN_KEYPRESSED:
|
||||
tkn_next(); parse_keypressed(); break;
|
||||
case TOKEN_ANYKEY:
|
||||
tkn_next(); parse_anykey(); break;
|
||||
case TOKEN_UPDATESCR:
|
||||
tkn_next(); parse_updatescr(); break;
|
||||
case TOKEN_COLOR:
|
||||
tkn_next(); parse_color(); break;
|
||||
case TOKEN_BORDER:
|
||||
tkn_next(); parse_border(); 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 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);
|
||||
parser_finished = false;
|
||||
include_labels();
|
||||
code = mem;
|
||||
codepos = 2;
|
||||
tkn_next();
|
||||
|
||||
parse_statements();
|
||||
append_strings();
|
||||
|
||||
//return code;
|
||||
}
|
||||
|
||||
const int parser_get_codesize() { return codepos; }
|
||||
const int parser_get_memory_usage() { return num_variables; }
|
||||
|
||||
void parser_register_external_function(const char* name, const int num_parameters) {
|
||||
strcpy(external_functions[num_external_functions].name, name);
|
||||
external_functions[num_external_functions++].num_parameters = num_parameters;
|
||||
}
|
||||
80
parser.h
Normal file
80
parser.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
|
||||
enum OPS {
|
||||
OP_NOP = 0,
|
||||
OP_PUSH,
|
||||
OP_POP,
|
||||
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_JMP,
|
||||
OP_JNT,
|
||||
OP_JTR,
|
||||
OP_JSR,
|
||||
OP_RET,
|
||||
OP_CALL,
|
||||
|
||||
OP_RJ,
|
||||
OP_RB,
|
||||
OP_RJZ,
|
||||
OP_RJN,
|
||||
OP_RBZ,
|
||||
OP_RBN,
|
||||
|
||||
OP_RJYZ,
|
||||
OP_RJYN,
|
||||
OP_RBYZ,
|
||||
OP_RBYN,
|
||||
OP_RJZZ,
|
||||
OP_RJZN,
|
||||
OP_RBZZ,
|
||||
OP_RBZN,
|
||||
|
||||
OP_ADD,
|
||||
OP_SUB,
|
||||
OP_MUL,
|
||||
OP_DIV,
|
||||
OP_MOD,
|
||||
OP_AND,
|
||||
OP_OR,
|
||||
OP_NOT,
|
||||
OP_NEG,
|
||||
OP_INC,
|
||||
OP_DEC,
|
||||
OP_CONCAT,
|
||||
|
||||
OP_EQ,
|
||||
OP_NEQ,
|
||||
OP_LT,
|
||||
OP_GT,
|
||||
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();
|
||||
void parser_register_external_function(const char* name, const int num_parameters);
|
||||
21
test.bas
Normal file
21
test.bas
Normal file
@@ -0,0 +1,21 @@
|
||||
locate 2 1
|
||||
print "HOLA JAILERS"
|
||||
border 5
|
||||
spr = 250
|
||||
setsprite 0 spr 0
|
||||
x = 0
|
||||
dx = 1
|
||||
count = 5
|
||||
peiv:
|
||||
putsprite 0 x 60
|
||||
updatescr
|
||||
x = x + dx
|
||||
if x = 128 then dx = -1 end
|
||||
if x = 8 then dx = 1 end
|
||||
dec count
|
||||
if count = 0 then
|
||||
count = 5
|
||||
if spr = 250 then spr = 251 else spr = 250 end
|
||||
setsprite 0 spr 1
|
||||
end
|
||||
goto peiv
|
||||
142
tokenizer.cpp
Normal file
142
tokenizer.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
#include "tokenizer.h"
|
||||
|
||||
static bool streq(const char* a, const char* b) {
|
||||
while (*a != 0 && *b != 0) {
|
||||
if (*a != *b) return false;
|
||||
a++; b++;
|
||||
}
|
||||
return *a == *b;
|
||||
}
|
||||
|
||||
static const char* ptr;
|
||||
static t_tokentype current_token = TOKEN_ERROR;
|
||||
static char identifier[255];
|
||||
static int value;
|
||||
static int line = 0;
|
||||
static int row = 0;
|
||||
static int current_tokenline = 0;
|
||||
static int current_tokenrow = 0;
|
||||
|
||||
struct t_token_op {
|
||||
char* str;
|
||||
t_tokentype tokentype;
|
||||
};
|
||||
|
||||
t_token_op tkn_tokens[] = {
|
||||
{ "let", TOKEN_LET },
|
||||
{ "if", TOKEN_IF },
|
||||
{ "then", TOKEN_THEN },
|
||||
{ "else", TOKEN_ELSE },
|
||||
{ "end", TOKEN_END },
|
||||
{ "for", TOKEN_FOR },
|
||||
{ "to", TOKEN_TO },
|
||||
{ "break", TOKEN_BREAK },
|
||||
{ "continue", TOKEN_CONTINUE },
|
||||
{ "goto", TOKEN_GOTO },
|
||||
{ "gosub", TOKEN_GOSUB },
|
||||
{ "return", TOKEN_RETURN },
|
||||
{ "rem", TOKEN_REM },
|
||||
{ "quit", TOKEN_QUIT },
|
||||
{ "and", TOKEN_AND },
|
||||
{ "or", TOKEN_OR },
|
||||
{ "not", TOKEN_NOT },
|
||||
{ "mod", TOKEN_MOD },
|
||||
{ "dim", TOKEN_DIM },
|
||||
{ "inc", TOKEN_INC },
|
||||
{ "dec", TOKEN_DEC },
|
||||
{ "strleft", TOKEN_STRLEFT },
|
||||
{ "strlen", TOKEN_STRLEN },
|
||||
{ "debug", TOKEN_DEBUG },
|
||||
{ "chr", TOKEN_CHR },
|
||||
{ "str", TOKEN_STR },
|
||||
{ "setsprite", TOKEN_SETSPRITE },
|
||||
{ "putsprite", TOKEN_PUTSPRITE },
|
||||
{ "locate", TOKEN_LOCATE },
|
||||
{ "print", TOKEN_PRINT },
|
||||
{ "putchar", TOKEN_PUTCHAR },
|
||||
{ "setchar", TOKEN_SETCHAR },
|
||||
{ "keypressed", TOKEN_KEYPRESSED },
|
||||
{ "anykey", TOKEN_ANYKEY },
|
||||
{ "updatescr", TOKEN_UPDATESCR },
|
||||
{ "color", TOKEN_COLOR },
|
||||
{ "border", TOKEN_BORDER },
|
||||
};
|
||||
|
||||
#define CCHR *ptr
|
||||
#define NEXT if(*ptr==10){line++;row=0;}else{row++;};ptr++
|
||||
|
||||
static void tkn_do_next() {
|
||||
identifier[0] = 0;
|
||||
value = 0;
|
||||
char* id = identifier;
|
||||
// Ignore whitespace
|
||||
while (CCHR != 0 && CCHR != 10 && CCHR <= 32) { NEXT; }
|
||||
// If zero, we are at the end of the file
|
||||
current_tokenline = line; current_tokenrow = row;
|
||||
if (CCHR == 0) { current_token = TOKEN_ENDFILE; return; }
|
||||
// if 13, we are at the end of the line
|
||||
if (CCHR == 10) { NEXT; current_token = TOKEN_ENDLINE; return; }
|
||||
// if 34, grab the string
|
||||
if (CCHR == 34) {
|
||||
NEXT;
|
||||
while (CCHR != 0 && CCHR != 34) { *id = CCHR; id++; NEXT; }
|
||||
if (CCHR == 0) { current_token = TOKEN_ERROR; return; }
|
||||
*id = 0; NEXT;
|
||||
current_token = TOKEN_STRING; return;
|
||||
}
|
||||
// If digit, grab the number
|
||||
if (CCHR >= 48 && CCHR <= 57) {
|
||||
do { value = value * 10 + (CCHR - 48); NEXT; } while (CCHR >= 48 && CCHR <= 57);
|
||||
current_token = TOKEN_NUMBER; return;
|
||||
}
|
||||
// if letter, grab the identifier
|
||||
if ((CCHR >= 65 && CCHR <= 90) || (CCHR >= 97 && CCHR <= 122)) {
|
||||
do { *id = CCHR; id++; NEXT; } while ((CCHR >= 48 && CCHR <= 57) || (CCHR >= 65 && CCHR <= 90) || (CCHR >= 97 && CCHR <= 122) || CCHR == 95);
|
||||
*id = 0;
|
||||
int i = 0; while (identifier[i] != 0) { if (identifier[i] < 95) { identifier[i] |= 32; }; i++; } // to lowecase
|
||||
// if it ends with ':', it's a label
|
||||
if (CCHR == ':') { NEXT; current_token = TOKEN_LABEL; return; }
|
||||
// If it matches a keyword, it's a keyword
|
||||
for (auto token : tkn_tokens) {
|
||||
if (streq(token.str, identifier)) {
|
||||
current_token = token.tokentype;
|
||||
if (current_token == TOKEN_REM) { while (CCHR != 0 && CCHR != 13) { NEXT; } }
|
||||
return;
|
||||
}
|
||||
}
|
||||
// else, it's an identifier
|
||||
current_token = TOKEN_IDENTIFIER; return;
|
||||
}
|
||||
// Check if it's any of the operators
|
||||
if (CCHR == '+') { NEXT; current_token = TOKEN_PLUS; return; }
|
||||
if (CCHR == '-') { NEXT; current_token = TOKEN_MINUS; return; }
|
||||
if (CCHR == '*') { NEXT; current_token = TOKEN_ASTERISC; return; }
|
||||
if (CCHR == '/') { NEXT; current_token = TOKEN_SLASH; return; }
|
||||
if (CCHR == '(') { NEXT; current_token = TOKEN_LPAR; return; }
|
||||
if (CCHR == ')') { NEXT; current_token = TOKEN_RPAR; return; }
|
||||
if (CCHR == ':') { NEXT; current_token = TOKEN_COLON; return; }
|
||||
if (CCHR == ',') { NEXT; current_token = TOKEN_COMMA; return; }
|
||||
if (CCHR == '<') { NEXT; if (CCHR == '=') { NEXT; current_token = TOKEN_LEQ; } else { current_token = TOKEN_LT; } return; }
|
||||
if (CCHR == '>') { NEXT; if (CCHR == '=') { NEXT; current_token = TOKEN_GEQ; } else { current_token = TOKEN_GT; } return; }
|
||||
if (CCHR == '=') { NEXT; current_token = TOKEN_EQ; return; }
|
||||
if (CCHR == '%') { NEXT; current_token = TOKEN_MOD; return; }
|
||||
if (CCHR == 39) { NEXT; current_token = TOKEN_REM; while (CCHR != 0 && CCHR != 10) { NEXT; }; return; }
|
||||
|
||||
// if no match, it's an error
|
||||
current_token = TOKEN_ERROR; return;
|
||||
}
|
||||
|
||||
void tkn_init(const char* buffer) {
|
||||
ptr = buffer;
|
||||
current_token = TOKEN_ERROR;
|
||||
value = line = row = current_tokenline = current_tokenrow = 0;
|
||||
identifier[0] = 0;
|
||||
}
|
||||
|
||||
void tkn_next() { do { tkn_do_next(); } while (current_token == TOKEN_REM || current_token == TOKEN_ENDLINE); }
|
||||
|
||||
t_tokentype tkn_get_token() { return current_token; }
|
||||
char* tkn_get_string() { return identifier; }
|
||||
int tkn_get_value() { return value; }
|
||||
int tkn_get_line() { return current_tokenline; }
|
||||
int tkn_get_row() { return current_tokenrow; }
|
||||
77
tokenizer.h
Normal file
77
tokenizer.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned short word;
|
||||
|
||||
enum t_tokentype {
|
||||
TOKEN_ERROR,
|
||||
TOKEN_NUMBER,
|
||||
TOKEN_STRING,
|
||||
|
||||
TOKEN_IDENTIFIER,
|
||||
TOKEN_LABEL,
|
||||
TOKEN_DIM,
|
||||
|
||||
TOKEN_LET,
|
||||
TOKEN_IF,
|
||||
TOKEN_ELSE,
|
||||
TOKEN_END,
|
||||
TOKEN_FOR,
|
||||
TOKEN_BREAK,
|
||||
TOKEN_CONTINUE,
|
||||
TOKEN_GOTO,
|
||||
TOKEN_GOSUB,
|
||||
TOKEN_RETURN,
|
||||
TOKEN_REM,
|
||||
TOKEN_QUIT,
|
||||
TOKEN_INC,
|
||||
TOKEN_DEC,
|
||||
|
||||
TOKEN_THEN,
|
||||
TOKEN_TO,
|
||||
|
||||
TOKEN_AND,
|
||||
TOKEN_OR,
|
||||
TOKEN_NOT,
|
||||
TOKEN_MOD,
|
||||
TOKEN_PLUS,
|
||||
TOKEN_MINUS,
|
||||
TOKEN_ASTERISC,
|
||||
TOKEN_SLASH,
|
||||
TOKEN_LPAR,
|
||||
TOKEN_RPAR,
|
||||
TOKEN_COLON,
|
||||
TOKEN_COMMA,
|
||||
TOKEN_LT,
|
||||
TOKEN_GT,
|
||||
TOKEN_LEQ,
|
||||
TOKEN_GEQ,
|
||||
TOKEN_EQ,
|
||||
TOKEN_ENDLINE,
|
||||
TOKEN_ENDFILE,
|
||||
|
||||
TOKEN_STRLEFT,
|
||||
TOKEN_STRLEN,
|
||||
TOKEN_DEBUG,
|
||||
TOKEN_CHR,
|
||||
TOKEN_STR,
|
||||
TOKEN_SETSPRITE,
|
||||
TOKEN_PUTSPRITE,
|
||||
TOKEN_LOCATE,
|
||||
TOKEN_PRINT,
|
||||
TOKEN_PUTCHAR,
|
||||
TOKEN_SETCHAR,
|
||||
TOKEN_KEYPRESSED,
|
||||
TOKEN_ANYKEY,
|
||||
TOKEN_UPDATESCR,
|
||||
TOKEN_COLOR,
|
||||
TOKEN_BORDER,
|
||||
};
|
||||
|
||||
void tkn_init(const char* buffer);
|
||||
void tkn_next();
|
||||
t_tokentype tkn_get_token();
|
||||
char* tkn_get_string();
|
||||
int tkn_get_value();
|
||||
int tkn_get_line();
|
||||
int tkn_get_row();
|
||||
@@ -56,7 +56,7 @@
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
@@ -79,15 +79,21 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="error.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="parser.cpp" />
|
||||
<ClCompile Include="stack.cpp" />
|
||||
<ClCompile Include="tokenizer.cpp" />
|
||||
<ClCompile Include="vdp.cpp" />
|
||||
<ClCompile Include="vm.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="error.h" />
|
||||
<ClInclude Include="font.h" />
|
||||
<ClInclude Include="parser.h" />
|
||||
<ClInclude Include="stack.h" />
|
||||
<ClInclude Include="stb_image.h" />
|
||||
<ClInclude Include="tokenizer.h" />
|
||||
<ClInclude Include="vdp.h" />
|
||||
<ClInclude Include="vm.h" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -27,6 +27,15 @@
|
||||
<ClCompile Include="vdp.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="error.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="parser.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tokenizer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="vm.h">
|
||||
@@ -44,5 +53,14 @@
|
||||
<ClInclude Include="font.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="tokenizer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="error.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="parser.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
28
vdp.cpp
28
vdp.cpp
@@ -126,21 +126,17 @@ static void flip() {
|
||||
Uint8 col = sprites[i].col;
|
||||
Uint8* sbt = &screen_buffer[((x - 8) * 4) + ((y - 8) * 128 * 4)];
|
||||
for (int l = 0; l < 8; l++) {
|
||||
if (y >= 8) {
|
||||
if (((x+0) >= 8) && (*cm & 128)) memcpy(sbt, palette[col & 0x0F], 4); sbt += 4;
|
||||
if (((x + 1) >= 8) && (*cm & 64)) memcpy(sbt, palette[col & 0x0F], 4); sbt += 4;
|
||||
if (((x + 2) >= 8) && (*cm & 32)) memcpy(sbt, palette[col & 0x0F], 4); sbt += 4;
|
||||
if (((x + 3) >= 8) && (*cm & 16)) memcpy(sbt, palette[col & 0x0F], 4); sbt += 4;
|
||||
if (((x + 4) >= 8) && (*cm & 8)) memcpy(sbt, palette[col & 0x0F], 4); sbt += 4;
|
||||
if (((x+5) >= 8) && (*cm & 4))
|
||||
memcpy(sbt, palette[col & 0x0F], 4);
|
||||
sbt += 4;
|
||||
if (((x+6) >= 8) && (*cm & 2))
|
||||
memcpy(sbt, palette[col & 0x0F], 4);
|
||||
sbt += 4;
|
||||
if (((x+7) >= 8) && (*cm & 1))
|
||||
memcpy(sbt, palette[col & 0x0F], 4);
|
||||
sbt += (512 - 32 + 4);
|
||||
if (y >= 8 && y < 104) {
|
||||
if (((x + 0) >= 8) && ((x + 0) < 136) && (*cm & 128)) memcpy(sbt, palette[col & 0x0F], 4); sbt += 4;
|
||||
if (((x + 1) >= 8) && ((x + 1) < 136) && (*cm & 64)) memcpy(sbt, palette[col & 0x0F], 4); sbt += 4;
|
||||
if (((x + 2) >= 8) && ((x + 2) < 136) && (*cm & 32)) memcpy(sbt, palette[col & 0x0F], 4); sbt += 4;
|
||||
if (((x + 3) >= 8) && ((x + 3) < 136) && (*cm & 16)) memcpy(sbt, palette[col & 0x0F], 4); sbt += 4;
|
||||
if (((x + 4) >= 8) && ((x + 4) < 136) && (*cm & 8)) memcpy(sbt, palette[col & 0x0F], 4); sbt += 4;
|
||||
if (((x + 5) >= 8) && ((x + 5) < 136) && (*cm & 4)) memcpy(sbt, palette[col & 0x0F], 4); sbt += 4;
|
||||
if (((x + 6) >= 8) && ((x + 6) < 136) && (*cm & 2)) memcpy(sbt, palette[col & 0x0F], 4); sbt += 4;
|
||||
if (((x + 7) >= 8) && ((x + 7) < 136) && (*cm & 1)) memcpy(sbt, palette[col & 0x0F], 4); sbt += (512 - 32 + 4);
|
||||
} else {
|
||||
sbt += 512;
|
||||
}
|
||||
cm++; y++;
|
||||
}
|
||||
@@ -201,7 +197,7 @@ void vdp_cmd_out(const unsigned char& value) {
|
||||
break;
|
||||
case VDP_CMD_BORDER:
|
||||
border = data_stack[0] & 0xF;
|
||||
SDL_SetRenderDrawColor(sdlRenderer, palette[border][3], palette[border][2], palette[border][1], palette[border][0]);
|
||||
SDL_SetRenderDrawColor(sdlRenderer, palette[border][0], palette[border][1], palette[border][2], palette[border][3]);
|
||||
break;
|
||||
}
|
||||
data_stack_pos = 0;
|
||||
|
||||
36
vm.cpp
36
vm.cpp
@@ -1,5 +1,8 @@
|
||||
#include "vm.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "parser.h"
|
||||
#include "error.h"
|
||||
|
||||
#define MAX_EXTERNAL_CALLS 256
|
||||
#define MAX_DATA_STACK 256
|
||||
@@ -8,7 +11,7 @@
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned short word;
|
||||
|
||||
enum OPS {
|
||||
/*enum OPS {
|
||||
OP_NOP = 0,
|
||||
OP_PUSH,
|
||||
OP_POP,
|
||||
@@ -80,7 +83,7 @@ enum OPS {
|
||||
OP_IN,
|
||||
OP_OUT,
|
||||
OP_SLEEP,
|
||||
};
|
||||
};*/
|
||||
|
||||
typedef void(*t_extcall)(t_stack&);
|
||||
t_extcall external_calls[MAX_EXTERNAL_CALLS];
|
||||
@@ -113,12 +116,39 @@ static void load_rom() {
|
||||
}
|
||||
|
||||
static void load_program(const char* filename) {
|
||||
FILE *f = fopen(filename, "rb");
|
||||
/* FILE *f = fopen(filename, "rb");
|
||||
fseek(f, 0, SEEK_END);
|
||||
long fsize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
fread(mem, fsize, 1, f);
|
||||
fclose(f);*/
|
||||
FILE *f = fopen(filename, "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;
|
||||
|
||||
//unsigned char* rawCode =
|
||||
parser_parse(program, mem);
|
||||
free(program);
|
||||
|
||||
if (error_raised()) {
|
||||
error_print();
|
||||
//getchar();
|
||||
}
|
||||
else {
|
||||
printf("Compilation complete!\nProgram size: %d bytes\nMemory usage: %d bytes\n", parser_get_codesize(), parser_get_memory_usage());
|
||||
/*FILE *f = fopen("test.bin", "wb");
|
||||
if (f == nullptr) perror("Error");// printf("Error: %d (%s)\n", errno, strerror(errno));
|
||||
fwrite(rawCode, parser_get_codesize(), 1, f);
|
||||
fclose(f);*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void vm_init(const char* filename) {
|
||||
|
||||
Reference in New Issue
Block a user