timesynk/test/vm_compile.c

1020 lines
34 KiB
C

#include "vm_compile.h"
#include "vm.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h> // isdigit
/*** DEFINES ***/
char *vm_datatypes[] = {
#define MAX_TYPES 7
#define TYPE_CHAR 0
"Char",
#define TYPE_INT 1
"Int",
#define TYPE_FLOAT 2
"Float",
#define TYPE_STRING 3
"String",
#define TYPE_TABLE 4
"Table",
#define TYPE_TILE 5
"Tile",
#define TYPE_MAP 6
"Map",
#define TYPE_PLAYER 7
"Player"
};
char *vm_expressions[] = {
#define MAX_EXPS 3
"return",
#define EXP_RETURN 0
"if",
#define EXP_IF 1
"while",
#define EXP_WHILE 2
"for"
#define EXP_FOR 3
};
char *vm_assignments[] = {
#define MAX_ASS 4
#define ASS_EQ 0
"=",
#define ASS_ADD 1
"+=",
#define ASS_MIN 2
"-=",
#define ASS_MUL 3
"*=",
#define ASS_DIV 4
"/="
};
char *vm_operations[] = {
#define MAX_OPS 3
#define OP_ADD 0
"+",
#define OP_MIN 1
"-",
#define OP_MUL 2
"*",
#define OP_DIV 3
"/"
};
const char *vm_pc_binary_operators[] = {
#define PC_BINOPS 12
"*",
#define PC_BINOP_MUL 0
"/",
#define PC_BINOP_DIV 1
"%",
#define PC_BINOP_MOD 2
"+",
#define PC_BINOP_ADD 3
"-",
#define PC_BINOP_SUB 4
"<",
#define PC_BINOP_LT 5
">",
#define PC_BINOP_GT 6
"<=",
#define PC_BINOP_LTE 7
">=",
#define PC_BINOP_GTE 8
"==",
#define PC_BINOP_EQ 9
"!=",
#define PC_BINOP_NEQ 10
"&&",
#define PC_BINOP_AND 11
"||"
#define PC_BINOP_OR 12
};
const char *vm_pc_assignment_operators[] = {
#define PC_ASSOPS 5
"=",
#define PC_ASSOP_EQ 0
"+=",
#define PC_ASSOP_AEQ 1
"-=",
#define PC_ASSOP_SEQ 2
"*=",
#define PC_ASSOP_MEQ 3
"/=",
#define PC_ASSOP_DEQ 4
"%="
#define PC_ASSOP_MOQ 5
};
const char *vm_pc_operators[][6] = {
#define PC_BINOP 0
{
"*",
"/",
"%",
"+",
"-"
},
#define PC_ASSOP 0
{
"=",
"+=",
"-=",
"*=",
"/=",
"%="
}
};
/*** MAIN ***/
int main(int argc, char *argv[]) {
vm_pc_global_scope.variables = newTable(32);
vm_pc_global_scope.functions = newTable(32);
vm_pc_group_scopes = newTable(32);
vm_pc_local_scopes = newTable(32);
char *code_dir = "code/";
struct LList *code_files = dirToLList(code_dir, F_FILES);
struct LList *current_file = code_files;
while(current_file) {
if(strstr((char *)current_file->data, ".vmc") != NULL) {
char temp_string[strlen((char *)current_file->data)+strlen(code_dir)+1];
sprintf(temp_string, "%s%s", code_dir, (char *)current_file->data);
printf("-> precompiling %s\n", temp_string);
int errors = 0;
switch(errors = vm_precompileFile(temp_string)) {
case 0:
printf("-> OK: successfully read %s\n", temp_string);
break;
case -1:
printf("ERROR, could not open file for reading\n");
break;
default:
printf("%d ERRORS encountered while compiling %s\n", errors, temp_string);
break;
}
}
current_file = current_file->next;
}
return 0;
}
/*** PARSING ***/
/*
================================
int vm_precompileFile(const char *file_name)
This function takes in a given file name, opens it, and begins processing the file text character-by-character. When a valid code block is found, such as:
{
// GLOBAL
}
0 {
// GROUP
}
0:0 {
// LOCAL
}
The appropriate scopes are created and passed to vm_precompileSection for actual precompilation.
================================
*/
int vm_precompileFile(const char *file_name) {
FILE *file = fopen(file_name, "r");
if (file == NULL) {
return -1;
}
// NOTE: Temporarily switching to buffer access rather than file, for parsing reasons. Might keep, but we'll see.
char chunk_buffer[16];
int chunk_pos = 0;
int bytes_read = 0;
char *file_buffer = NULL;
int file_size = 0;
int file_pos = 0;
fseek(file, 0, SEEK_END);
file_size = ftell(file);
fseek(file, 0, SEEK_SET);
printf("allocated %d bytes for buffer\n", file_size);
file_buffer = malloc(file_size+1); // +1 for /0
while ((bytes_read = fread(chunk_buffer, 1, 16, file))) {
for (chunk_pos = 0;chunk_pos < bytes_read;chunk_pos++) {
file_buffer[file_pos++] = chunk_buffer[chunk_pos];
}
}
file_buffer[file_pos] = '\0';
file_pos = 0; // reset file pos!
//fclose(file);
char c; // current char!
int cpos = 1; // char position
int lpos = 1; // line position
char first[128]; // max 128 characters for group or id string
int fpos = 0; // char pos for ^
char second[128]; // max 128 for id string
int spos = -1; // char pos for ^, we cheat by using -1 as a way to use spos and fpos for our mode (e.g., group scope == -1, local scope >= 0)
int errors = 0; // error count returned by precompileSection
int total_errors = 0; // total error count, used in return
//while(( c = fgetc(file)) != EOF) {
while(( c = file_buffer[file_pos++]) != '\0') {
if (isdigit(c)) {
if (spos >= 0) {
second[spos++] = c;
} else {
first[fpos++] = c;
}
} else if (c == ':') {
if (spos >= 0) {
printf("second ':' encountered\n");
}
if (fpos == 0) {
first[fpos++] = '0';
}
first[fpos] = '\0';
spos = 0;
} else if (c == '{') {
first[fpos] = '\0';
if (fpos == 0) {
printf("[%d,%d]: starting precompile for global code block\n", lpos, cpos);
//if ((errors = vm_precompileSection(file, &lpos, &cpos, &vm_pc_global_scope, NULL, NULL)) != 0) {
if ((errors = vm_precompileSection(file_buffer, &file_pos, &lpos, &cpos, &vm_pc_global_scope, NULL, NULL)) != 0) {
printf("%d ERRORS encountered while compiling global code block!\n", errors);
total_errors += errors;
}
printf("[%d,%d]: finished precompile for global code block\n", lpos, cpos);
printf(" * dumping precompiled global\n");
vm_pc_dumpScope(&vm_pc_global_scope);
} else if (spos == -1) {
struct vm_pc_Scope *group_scope = getTablePairValue(vm_pc_group_scopes, first);
if (group_scope == NULL) { // create if does not exist
group_scope = malloc(sizeof(struct vm_pc_Scope));
group_scope->functions = newTable(32);
group_scope->variables = newTable(32);
addTablePairPointer(vm_pc_group_scopes, first, group_scope, T_TABLE); // FIXME: define VOID_POINTER in data.c/.h
}
printf("[%d,%d]: starting precompile for group code block %s\n", lpos, cpos, first);
//if ((errors = vm_precompileSection(file, &lpos, &cpos, &vm_pc_global_scope, group_scope, NULL)) != 0) {
if ((errors = vm_precompileSection(file_buffer, &file_pos, &lpos, &cpos, &vm_pc_global_scope, group_scope, NULL)) != 0) {
printf("%d ERRORS encountered while compiling group code block %s!\n", errors, first);
total_errors += errors;
// TODO: perhaps allow potentially broken code?
// TODO: return 1 on failure
vm_pc_freeVariables(group_scope->variables);
}
printf("[%d,%d]: finished precompile for group code block %s\n", lpos, cpos, first);
printf(" * dumping precompiled group\n");
vm_pc_dumpScope(group_scope);
fpos = 0;
first[fpos] = '\0';
} else {
second[spos] = '\0';
// Get/create our scope Table vm_pc_local_scopes[first]
struct Table *local_scopes = getTablePairValue(vm_pc_local_scopes, first);
if (local_scopes == NULL) {
local_scopes = newTable(32);
addTablePairPointer(vm_pc_local_scopes, first, local_scopes, T_TABLE);
}
// Get/create Scope from vm_pc_local_scopes[first][second]
struct vm_pc_Scope *local_scope = getTablePairValue(local_scopes, second);
if (local_scope == NULL) {
local_scope = malloc(sizeof(struct vm_pc_Scope));
local_scope->functions = newTable(32);
local_scope->variables = newTable(32);
addTablePairPointer(local_scopes, second, local_scope, T_TABLE); // FIXME: define VOID_POINTER in data.c/.h
}
// Get/create group scope from vm_pc_group_scopes[first]
struct vm_pc_Scope *group_scope = getTablePairValue(vm_pc_group_scopes, first);
if (group_scope == NULL) {
group_scope = malloc(sizeof(struct vm_pc_Scope));
group_scope->functions = newTable(32);
group_scope->variables = newTable(32);
addTablePairPointer(vm_pc_group_scopes, first, group_scope, T_TABLE); // FIXME: define VOID_POINTER in data.c/.h
}
printf("[%d,%d]: starting precompile for local code block %s:%s\n", lpos, cpos, first, second);
//if ((errors = vm_precompileSection(file, &lpos, &cpos, &vm_pc_global_scope, group_scope, local_scope)) != 0) {
if ((errors = vm_precompileSection(file_buffer, &file_pos, &lpos, &cpos, &vm_pc_global_scope, group_scope, local_scope)) != 0) {
printf("%d ERRORS encountered while compiling local code block %s:%s!\n", errors, first, second);
total_errors += errors;
}
printf("[%d,%d]: finished precompile for local code block %s:%s\n", lpos, cpos, first, second);
/*printf(" * dumping precompiled global variables\n");
vm_pc_dumpScope(&vm_pc_global_scope);
printf(" * dumping precompiled group variables\n");
vm_pc_dumpScope(group_scope);*/
printf(" * dumping precompiled local\n");
vm_pc_dumpScope(local_scope);
fpos = 0;
first[fpos] = '\0';
spos = -1;
second[spos] = '\0';
}
}
if (c == '\n') {
lpos++;
cpos = 1;
} else {
cpos++;
}
}
//fclose(file);
//free(file_buffer);
return total_errors; // success, baby
}
//int vm_precompileSection(FILE *file, int *lpos_, int *cpos_, struct vm_pc_Scope *global, struct vm_pc_Scope *group, struct vm_pc_Scope *local) {
int vm_precompileSection(char *file_buffer, int *file_pos_, int *lpos_, int *cpos_, struct vm_pc_Scope *global, struct vm_pc_Scope *group, struct vm_pc_Scope *local) {
int file_pos = *file_pos_;
int lpos = *lpos_;
int cpos = *cpos_;
int depth = 0;
int pdepth = 0; // parenthesis depth
char words[31][128]; // word list [X][Y]
int wpos = 0; // word position, i.e., X
int wcpos = 0; // word character position, i.e., Y
int error = 0;
int ret = 0;
struct vm_pc_Scope *current_scope; // default scope is local
// if local is NULL, that means we are in group scope. If group is NULL, we are in global
if (local == NULL) {
if (group == NULL) {
//printf(" * Precompiling global\n");
current_scope = global;
} else {
//printf(" * Precompiling group\n");
current_scope = group;
}
} else {
//printf(" * Precompiling local\n");
current_scope = local;
}
memset(&words, '\0', 31*128);
char c; // current char!
//while(( c = fgetc(file)) != EOF) {
while(( c = file_buffer[file_pos++]) != '\0') {
if (c == '{') {
depth++;
} else if (c == '}') {
depth--;
}
if (c == '\n') {
lpos++;
cpos = 1;
} else {
cpos++;
}
if (depth < 0)
break;
// actual conversion of lines to words
// '/' discard double '//' as it is
if (c == '/') {
if (words[wpos][wcpos-1] == '/') {
// step back and remove old line
words[wpos][--wcpos] = '\0';
// discard chars until newline or EOF
char nc; // new char - used in following consumption loop
//while((nc = fgetc(file)) != '\n' && nc != '\r' && nc != EOF);
while((nc = file_buffer[file_pos++]) != '\n' && nc != '\r' && nc != EOF);
lpos++;
cpos = 1;
} else {
words[wpos][wcpos++] = c;
cpos++;
}
// when ( is encountered and parenthesis depth is 0, end the current word, and start new word with '('. Otherwise, add parenthesis to current word.
} else if (c == '(') {
if (pdepth == 0) {
words[wpos++][wcpos] = '\0';
wcpos = 0;
words[wpos][wcpos++] = c;
} else {
words[wpos][wcpos++] = c;
}
pdepth++;
// when ) is encountered, decrease depth and add to current word.
} else if (c == ')') {
pdepth--;
words[wpos][wcpos++] = c;
if (pdepth > 0) {
words[wpos++][wcpos] = '\0';
wcpos = 0;
}
// if parenthesis depth is greater than zero, then add spaces or tabs to the current word. If not, end current word and start new word.
// TODO: quotations should enable skipping of the following
} else if (c == ' ' || c == '\t') {
if (pdepth > 0) {
words[wpos][wcpos++] = c;
} else {
if (wcpos != 0) {
//words[wpos][wcpos++] = c;
words[wpos++][wcpos] = '\0';
wcpos = 0;
}
}
// consume newlines with greed.
} else if (c == '\n' || c == '\r') {
// when a ';' is encountered, this equates to a variable or function declaration.
} else if (c == ';') {
int wwpos = 0;
int wtypes[wpos];
// BEGIN VARIABLE PARSING
for (wwpos=0;wwpos <= wpos;wwpos++) {
// BEGIN VARIABLE DECLARATION
// first we set the first word's type by checking against reserved words
if (wwpos == 0) { // "_int_"
int wtype = vm_isReserved(words[wwpos]);
wtypes[wwpos] = wtype;
if (wpos == 0) {
printf("[%d,%d]: ERROR, floating statement \"%s\".\n", lpos, cpos, words[wwpos]);
error++;
}
if (wtype != 1) {
printf("[%d,%d]: ERROR, \"%s\" is not a valid data type.\n", lpos, cpos, words[wwpos]);
error++;
}
} else if (wwpos == 1) {
// now we check if the first word's type is "1" - a built-in data type
if (wtypes[wwpos-1] == 1) { // "int _x_ . . ."
// we check against a second datatype declaration, such as "int int" - this is invalid
wtypes[wwpos] = vm_isReserved(words[wwpos]);
// TODO: check if variable name is valid (alpha-only)
if (wtypes[wwpos] == 0) {
// now add to our current scope's variable Table
if ((ret = vm_pc_addVariableToScope(current_scope, words[wwpos-1], words[wwpos])) != 0) {
switch(ret) {
case 1:
printf("[%d,%d]: ERROR, could not add \"%s\", as \"%s\" was already defined.\n", lpos, cpos, words[wwpos], words[wwpos]);
error++;
break;
case 2:
printf("[%d,%d]: ERROR, could not add \"%s\", as type \"%s\" is undefined.\n", lpos, cpos, words[wwpos], words[wwpos-1]);
error++;
break;
case 3:
printf("[%d,%d]: ERROR, could not add \"%s\", as type \"%s\" is undefined in translation function.\n", lpos, cpos, words[wwpos], words[wwpos-1]);
error++;
break;
case -1:
printf("[%d,%d]: ERROR, could not add \"%s\", as scope is NULL\n", lpos, cpos, words[wwpos]);
error++;
break;
default:
printf("[%d,%d]: ERROR, unhandled error while adding variable!\n", lpos, cpos);
error++;
break;
}
}
} else {
printf("[%d,%d]: ERROR, bad variable name, \"%s\" is reserved\n", lpos, cpos, words[wwpos]);
error++;
break;
}
}
// END VARIABLE DECLARATION
// now we parse for assignment operations, if available
// BEGIN VARIABLE SETTING
} else if (wwpos == 2) {
wtypes[wwpos] = vm_isReserved(words[wwpos]);
if (wtypes[wwpos-1] == 0) { // variable name
if (wtypes[wwpos] == 0) { // "int _int_"
printf("[%d,%d]: ERROR, \"%s\" given after \"%s\" already provided - perhaps a forgotten assignment op?\n", lpos, cpos, words[wwpos], words[wwpos-1]);
error++;
break;
} else if (wtypes[wwpos] == 4) { // "="
if (wtypes[wwpos-1] == 0) {
if (wwpos+1 > wpos || words[wwpos+1][0] == '\0') {
printf("[%d,%d]: ERROR, right-hand of assignment for \"%s\" empty!\n", lpos, cpos, words[wwpos-1]);
error++;
break;
} else {
// TODO: check if is a value or variable. if right-hand of assignment is a variable and does not exist, complain.
if ((ret = vm_pc_setVariable((struct vm_pc_Variable*)getTablePairValue(current_scope->variables, words[wwpos-1]), words[wwpos+1])) != 0) {
switch(ret) {
case -1:
printf("[%d,%d]: ERROR, variable \"%s\" undeclared!\n", lpos, cpos, words[wwpos-1]);
error++;
break;
default:
printf("[%d,%d]: ERROR, unhandled error while setting variable \"%s\"!\n", lpos, cpos, words[wwpos-1]);
error++;
break;
}
} else {
//printf(" SET (%s)%s=>%s\n", ((struct vm_pc_Variable *)getTablePairValue(current_scope->variables, words[wwpos-1]))->type, words[wwpos-1], ((struct vm_pc_Variable *)getTablePairValue(current_scope->variables, words[wwpos-1]))->data);
}
}
} else {
printf("[%d,%d]: ERROR, \"%s\" after \"%s\" is invalid!\n", lpos, cpos, words[wwpos], words[wwpos-1]);
error++;
}
}
}
// VARIABLE SETTING cont'd
} else {
wtypes[wwpos] = vm_isReserved(words[wwpos]);
if (wtypes[wwpos] == 4) { // "="
if (wtypes[wwpos-1] == 0) {
if (wwpos+1 > wpos) {
printf("[%d,%d]: ERROR, right-hand of assignment for \"%s\" empty!\n", lpos, cpos, words[wwpos-1]);
error++;
break;
} else {
// TODO: check if is a value or variable. if right-hand of assignment is a variable and does not exist, complain.
if ((ret = vm_pc_setVariable((struct vm_pc_Variable*)getTablePairValue(current_scope->variables, words[wwpos-1]), words[wwpos+1])) != 0) {
switch(ret) {
case -1:
printf("[%d,%d]: ERROR, variable \"%s\" undeclared!\n", lpos, cpos, words[wwpos-1]);
error++;
break;
default:
printf("[%d,%d]: ERROR, unhandled error while setting variable!\n", lpos, cpos);
error++;
break;
}
} else {
printf(" SET (%s)%s=>%s\n", ((struct vm_pc_Variable *)getTablePairValue(current_scope->variables, words[wwpos-1]))->type, words[wwpos-1], ((struct vm_pc_Variable *)getTablePairValue(current_scope->variables, words[wwpos-1]))->data);
}
}
} else {
printf("[%d,%d]: ERROR, \"%s\" after \"%s\" is invalid!\n", lpos, cpos, words[wwpos], words[wwpos-1]);
error++;
}
}
}
// END VARIABLE SETTING
}
// END VARIABLE PARSING
/*printf("\t\t");
for(wwpos = 0;wwpos <= wpos;wwpos++) {
printf("%s ", words[wwpos]);
}
printf("\n");*/
// RESET
wpos = 0;
wcpos = 0;
memset(&words, '\0', 31*128);
// when a '{' is encountered, what follows should be a function.
// BEGIN FUNCTION PARSING
} else if (c == '{') {
// Check if first word is a Type or an expression
int wwpos = 0;
if (wpos != 3) { // wordcount is always three for function declaration
printf("[%d,%d]: ERROR, general improper function declaration\n", lpos, cpos);
error++;
} else {
ret = vm_isReserved(words[wwpos]);
if (ret != 1) {
switch(ret) {
case 2: // expression
printf("[%d,%d]: ERROR, expressions not allowed outside of function\n", lpos, cpos);
break;
case 3: // operation
printf("[%d,%d]: ERROR, operations not allowed outside of function\n", lpos, cpos);
break;
case 4: // assignment
printf("[%d,%d]: ERROR, assignment not allowed outside of function\n", lpos, cpos);
break;
default: // unhandled
printf("[%d,%d]: ERROR, unknown return type \"%s\" in function declaration\n", lpos, cpos, words[wwpos]);
break;
}
error++;
} else {
ret = vm_isReserved(words[++wwpos]);
if (ret != 0) {
printf("[%d,%d]: ERROR, function cannot be named \"%s\"\n", lpos, cpos, words[wwpos]);
error++;
} else {
if (words[++wwpos][0] != '(') {
printf("[%d,%d]: ERROR, function parameters missing left-hand parenthesis!\n", lpos, cpos);
error++;
} else {
struct vm_pc_Function *func = vm_pc_newFunction(words[0]);
if (func == NULL) {
printf("[%d,%d]: PC_CRIT_ERR, could not create new function!\n", lpos, cpos);
error++;
} else {
// TODO: parse parameters into vm_pc_Variable(s) and add to function's params
//if ((ret = vm_precompileFunction(file, &lpos, &cpos, global, group, local, func)) != 0) {
if ((ret = vm_precompileFunction(file_buffer, &file_pos, &lpos, &cpos, global, group, local, func)) != 0) {
printf("[%d,%d]: %d ERRORS while precompiling function \"%s\"!\n", lpos, cpos, ret, words[1]);
error += ret;
} else {
depth--;
}
ret = vm_pc_addFunctionToScope(current_scope, func, words[1]);
if (ret != 0) {
switch(ret) {
case -1:
printf("[%d,%d]: PC_CRIT_ERR, local scope is NULL!\n", lpos, cpos);
error++;
break;
case -2:
printf("[%d,%d]: PC_CRIT_ERR, new function is NULL!\n", lpos, cpos);
error++;
break;
case 1:
printf("[%d,%d]: ERROR, function %s already declared!\n", lpos, cpos, words[1]);
error++;
break;
case 2:
printf("[%d,%d]: PC_CRIT_ERR, unknown function return Type!\n", lpos, cpos);
error++;
break;
}
} else {
printf("Added function %s with return %s\n", words[1], words[0]);
}
}
}
}
}
}
// RESET
wpos = 0;
wcpos = 0;
memset(&words, '\0', 31*128);
} else if (c == '}') {
// I guess leave current vm_pc_Function scope here if depth == 0?
/*int wwpos = 0;
for(wwpos = 0;wwpos <= wpos;wwpos++) {
printf("%d: %s\n", wwpos, words[wwpos]);
}*/
// RESET
wpos = 0;
wcpos = 0;
memset(&words, '\0', 31*128);
// END FUNCTION PARSING
} else {
words[wpos][wcpos++] = c;
}
}
*lpos_ = lpos;
*cpos_ = cpos;
*file_pos_ = file_pos;
return error;
}
//int vm_precompileFunction(FILE *file, int *lpos_, int *cpos_, struct vm_pc_Scope *global, struct vm_pc_Scope *group, struct vm_pc_Scope *individual, struct vm_pc_Function *func) {
int vm_precompileFunction(char *file_buffer, int *file_pos_, int *lpos_, int *cpos_, struct vm_pc_Scope *global, struct vm_pc_Scope *group, struct vm_pc_Scope *individual, struct vm_pc_Function *func) {
int file_pos = *file_pos_;
int lpos = *lpos_;
int cpos = *cpos_;
int error = 0;
int depth = 1;
char c;
char words[255][255]; // temp
int word = 0;
int wpos = 0;
//while(( c = fgetc(file)) != EOF) {
//while(( c = fgetc(file)) != EOF) {
while(( c = file_buffer[file_pos++]) != '\0') {
if (c == '{') {
depth++;
} else if (c == '}') {
depth--;
}
if (c == '\n') {
lpos++;
cpos = 1;
} else {
cpos++;
}
if (depth <= 0)
break;
if (c == '\n' || c == '\r' || c == '\t' || c == ' ')
continue;
words[word][wpos] = c;
words[word][wpos+1] = '\0';
// now we check against possible expressions
int op_code;
int reserved = 0;
int match = 0;
for(op_code = 0;op_code < PC_ASSOPS;op_code++) {
int op_length = strlen(vm_pc_assignment_operators[op_code])-1;
// see if current char matches operator's last char
if (words[word][wpos] == vm_pc_assignment_operators[op_code][op_length]) {
reserved = 1;
// potential match, step backwards into word, checking against operator's chars
int op_pos = 1;
while(op_pos <= op_length) {
if (wpos-op_pos < 0) {
// word is not long enough :(
match = 0;
printf("word not long enough\n");
break;
}
if (words[word][wpos-op_pos] == vm_pc_assignment_operators[op_code][op_length-op_pos]) {
printf(" %c matches %c\n", words[word][wpos-op_pos], vm_pc_assignment_operators[op_code][op_length-op_pos]);
if (op_pos == op_length) {
printf("we are equal\n");
match = 1;
break;
}
}
op_pos++;
}
if (match == 0) {
printf("no match, continuing...\n");
} else {
printf("match found, op is %s!! :o\n", vm_pc_assignment_operators[op_code]);
word++;
break;
}
}
}
if (reserved == 1 && match == 0){
printf("hah, could not find op for %s\n", words[word]);
}
wpos++;
// potential code to process:
// Int a, b, c;
// a = b;
// a += c;
// func(a+b);
// a = func(b+c);
// Int d = a + func(c);
// if (d == func(a) || func(b+c)) {
// // . . .
// }
// So our steps would be to identify declaration from expression
// So the first word is checked against types. If found, next word is a variable. If ';' thereafter, end of declaration. if '=', then assignment to some expression.
// expressions are parsed by building an expression tree(ETree). An ETree parses an operation-based expression(i.e., "1 + 2 * my_var / function(2+3) - 3"). This breaks down into:
// +
// / \
// 1 -
// / \
// * 3
// / \
// 2 /
// / \
// my_var function(+)
// / \
// 2 3
//
// logical operations (if a == b || a == c):
// < ?? >
// ||
// / \
// == ==
// / \ / \
// a b a c
//
// (if a+b == c && b+c == d):
// < ?? >
// &&
// / \
// == ==
// / \ / \
// + c + d
// / \ / \
// a b b c
//
// a source code expression is parsed into an expression tree as expression nodes by creating nodes in a specific order. This order begins with operators such as +, -, *, /, and so on. Once an expression tree is complete, it is converted into operations in a left-most inner-most fashion. :3
}
*lpos_ = lpos;
*cpos_ = cpos;
*file_pos_ = file_pos;
return error;
}
/*** POPULATING ***/
/*
Returns:
0 on success
1 if the variable is already defined
2 if the data type does not exist
*/
int vm_pc_addVariableToScope(struct vm_pc_Scope *scope, const char *data_type, const char *data_name) {
if (scope == NULL) {
return -1; // FIXME
}
if (getTablePair(scope->variables, data_name) != NULL) {
return 1;
}
int type;
for (type = 0;type <= MAX_TYPES;type++) {
if (strcmp(data_type, vm_datatypes[type]) == 0) {
struct vm_pc_Variable *new_var = vm_pc_newVariable(data_type, "undef");
addTablePairPointer(scope->variables, data_name, new_var, T_POINTER);
//printf(" ADDED (%s)%s=>%s\n", ((struct vm_pc_Variable *)getTablePairValue(scope->variables, data_name))->type, data_name, ((struct vm_pc_Variable *)getTablePairValue(scope->variables, data_name))->data);
return 0;
}
}
return 2;
}
int vm_pc_addFunctionToScope(struct vm_pc_Scope *scope, struct vm_pc_Function *func, const char *func_name) {
if (scope == NULL) {
return -1; // FIXME
}
if (func == NULL) {
return -2;
}
if (getTablePair(scope->functions, func_name) != NULL) {
return 1;
}
int type;
for (type = 0;type <= MAX_TYPES;type++) {
if (strcmp(func->ret->type, vm_datatypes[type]) == 0) {
addTablePairPointer(scope->functions, func_name, func, T_POINTER);
//printf(" ADDED (%s)%s=>%s\n", ((struct vm_pc_Variable *)getTablePairValue(scope->variables, data_name))->type, data_name, ((struct vm_pc_Variable *)getTablePairValue(scope->variables, data_name))->data);
return 0;
}
}
return 2;
}
int vm_pc_setVariable(struct vm_pc_Variable *var, const char *data) {
// TODO: check for var types - do not set strings to ints, etc.
if (var == NULL) {
return -1;
}
int data_size = strlen(data)+1;
var->data = realloc(var->data, data_size);
memcpy(var->data, data, data_size);
return 0;
}
/*** ALLOC ***/
struct vm_pc_Variable *vm_pc_newVariable(const char *type, const char *value) {
struct vm_pc_Variable *var = malloc(sizeof(struct vm_pc_Variable));
if (var == NULL) {
printf("!!! PC_CRIT_ERR, could not malloc memory for variable\n");
return NULL;
}
int type_size = strlen(type)+1;
if ((var->type = malloc(type_size)) == NULL) {
printf("!!! PC_CRIT_ERR, could not malloc memory for variable type\n");
return NULL;
} else {
memcpy(var->type, type, type_size);
}
int value_size = strlen(value)+1;
if ((var->data = malloc(value_size)) == NULL) {
printf("!!! PC_CRIT_ERR, could not malloc memory for variable data\n");
free(var->type);
return NULL;
} else {
memcpy(var->data, value, value_size);
}
return var;
}
struct vm_pc_Function *vm_pc_newFunction(const char *return_type) {
struct vm_pc_Function *func = malloc(sizeof(struct vm_pc_Function));
if (func == NULL) {
printf("!!! PC_CRIT_ERR, could not malloc memory for function\n");
return NULL;
}
if ((func->parameters = newTable(8)) == NULL) {
printf("!!! PC_CRIT_ERR, could not create new Table for function parameters\n");
return NULL;
}
if ((func->variables = newTable(32)) == NULL) {
printf("!!! PC_CRIT_ERR, could not create new Table for function variables\n");
return NULL;
}
if ((func->operations = newTable(64)) == NULL) {
printf("!!! PC_CRIT_ERR, could not create new Table for function operations\n");
return NULL;
}
if ((func->ret = vm_pc_newVariable(return_type, "undef")) == NULL) {
printf("!!! PC_CRIT_ERR, could not create new return Variable for function\n");
return NULL;
}
return func;
}
struct vm_pc_ENode *vm_pc_newENode(char type, void *data) {
struct vm_pc_ENode *enode = malloc(sizeof(struct vm_pc_ENode));
enode->type = type;
enode->data = data;
enode->left = NULL;
enode->right = NULL;
return enode;
}
/*** FREE ***/
int vm_pc_freeVariable(struct vm_pc_Variable *variable) {
if (variable == NULL) return 1;
if (variable->type != NULL) free(variable->type);
if (variable->data != NULL) free(variable->data);
free(variable);
return 0;
}
int vm_pc_freeVariables(struct Table *variables) {
if (variables == NULL) return 1;
int i = 0;
while (i < variables->size) {
struct TablePair *entry = variables->pair[i];
struct TablePair *next_entry = NULL;
while (entry != NULL) {
next_entry = entry->next;
struct vm_pc_Variable *var = entry->value;
vm_pc_freeVariable(var);
freeTablePair(entry);
variables->count--;
entry = next_entry;
}
variables->pair[i] = NULL;
i++;
}
return 0;
}
int vm_pc_freeFunction(struct vm_pc_Function *function) {
if (function == NULL) return 1;
if (function->variables) vm_pc_freeVariables(function->variables);
// TODO: free ops
free(function);
return 0;
}
int vm_pc_freeFunctions(struct Table *functions) {
int i =0;
while (i < functions->size) {
struct TablePair *entry = functions->pair[i];
struct TablePair *next_entry = NULL;
while (entry != NULL) {
next_entry = entry->next;
struct vm_pc_Function *func = entry->value;
vm_pc_freeFunction(func);
freeTablePair(entry);
functions->count--;
entry = next_entry;
}
i++;
}
return 0;
}
int vm_pc_freeScope(struct vm_pc_Scope *scope) {
if (scope == NULL) return 1;
vm_pc_freeVariables(scope->variables);
vm_pc_freeFunctions(scope->functions);
return 0;
}
/*** ETC ***/
int vm_isReserved(char *word) {
int checkpos;
for (checkpos = 0;checkpos <= MAX_TYPES;checkpos++) {
if (strcmp(word, vm_datatypes[checkpos]) == 0) {
return 1;
}
}
for (checkpos = 0;checkpos <= MAX_EXPS;checkpos++) {
if (strcmp(word, vm_expressions[checkpos]) == 0) {
return 2;
}
}
for (checkpos = 0;checkpos <= MAX_OPS;checkpos++) {
if (strcmp(word, vm_operations[checkpos]) == 0) {
return 3;
}
}
for (checkpos = 0;checkpos <= MAX_ASS;checkpos++) {
if (strcmp(word, vm_assignments[checkpos]) == 0) {
return 4;
}
}
return 0;
}
int vm_pc_dumpScope(struct vm_pc_Scope *scope) {
int i = 0;
printf(" * variables\n");
while (i < scope->variables->size) {
struct TablePair *entry = scope->variables->pair[i];
while (entry != NULL) {
struct vm_pc_Variable *var = entry->value;
printf(" %s %s = %s\n", var->type, entry->key, var->data);
entry = entry->next;
}
i++;
}
i = 0;
printf(" * functions\n");
while (i < scope->functions->size) {
struct TablePair *entry = scope->functions->pair[i];
while (entry != NULL) {
struct vm_pc_Function *var = entry->value;
printf(" %s %s()\n", var->ret->type, entry->key);
entry = entry->next;
}
i++;
}
return 0;
}