timesynk/test/vm_compile.c

782 lines
30 KiB
C

/*
================================================================
This file is the test development area for precompiling and compiling C-syntax VM source files in "code/".
It provides, globally, a Table of vm_Function pointers, as well as two additional Tables of vm_Function pointers for tile-type and tile-specific functions.
Table *vm_T_global_func
Table *vm_T_group_func[max_tile_types]
Table *vm_T_individual_func[max_tile_types][max_tile_ids]
Using Tables is a temporary solution as it stands, as it is quite inefficient. I would eventually like for a vm_Function pointer list to be generated, with particular functions being referred to solely through a vm_Function pointer (or, failing that, an index in an array).
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
Program Structure - file input and initial parsing
````````````````````````````````
The program reads in each timesynk-VM C-style syntax file found in the "code/" directory. These files contains the function declarations for all Tiles, Tile types, and specific Tiles. ex.:
return_type functionName(param_type param_name, param_type, param_name, . . .) {
type result = param_name;
return(param_name);
}
TID {
return_type typeFunct(. . .) {
. . .
}
TID:ID {
return_type tileFunct(. . .) {
. . .
}
}
Categorization of functions into global, group, and individual is accomplished through the following method. During the reading in of a line while depth is equal to 0 (e.g., not in a function declaration): if the first word is solely numeric, it is a group function(s) declaration; if the first word is numeric save for a single colon ':', then it is an individual declaration; if the first word is non-numeric, then it is a global declaration.
Once the scope is found, the Parser begins to search for variable and function declarations. During reading a line, if the line does not end with a ';', then it is checked as a possible function declaration - otherwise, it is checked as a variable declaration. During this stage, spaces, tabs and return characters are eaten, allowing for multiple function declaration styles.
Once a function section is identified, a mid-level function struct is created and populated with the function name, return data type, and variable structs for the parameters and added to the appropriate scope function Table. When a variable is encountered, it is converted into a mid-level variable struct and added into the appropriate scope variable Table.
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
Program Structure - function parsing and pre-compilation
````````````````````````````````
Once the parser is within a function, the source code is reduced to mid-level (precompiled) statements and expressions. At this stage, variables remain referred to via char arrays, with new variables added to the mid-level function's variable Table.
For example, the following variable assignment statement:
int x = 2;
Would be precompiled in the following manner:
add variable { name: "x", type: int }
add variable { name: "2", type: int }
add statement { type: assign, var_1: "x", var_2: "2" }
add statement indicates an added statement to the linked list of statements AND an increment to the line count. add variable indicates adding a variable to the variable Table. Or, for a compound statement:
float y;
if (x > 2) {
y = 0.0;
} else if (x < 1) {
y = 0.5;
} else {
y = 1.0;
}
Would precompile:
add variable { name: "y", type: float, value: "0.0" }
add variable { name: "2", type: int, value "0" } // if not existing
add statement { type: gt, var_1: "x", var_2: "2" }
add statement { type: jump, pos: undef } ---------------------.
// jump[depth][pos++] = this jump |
add variable { name: "0.0", type: float, value: "0.0" } |
add statement { type: assign, var_1: "y", var_2: "0.0" } |
add statement { type: jump, pos: undef } =====================|============================
// jump_to_end[depth][pos++] = this jump | "
// set jump[depth][pos-1].pos = this line <-------------------' "
add variable { name: "1", type: int, value: "1" } "
add statement { type: lt, var_1: "x", var_2: "1" } "
add statement { type: jump, pos: undef } ---------------------------------. "
// jump[depth][pos++] = this jump | "
// set jump[depth][pos-1].pos = this line | "
add variable { name: "0.5", type: float, value: "0.5" } | "
add statement { type: assign, var_1: "y", var_2: "0.5" } | "
add statement { type: jump, pos: undef } =================================|==============="
// jump_to_end[depth][pos++] = this jump | "
// set jump[depth][pos-1].pos = this line <-------------------------------' "
add variable { name: "1.0", type: float, value: "1.0" } "
"
// for(int jpos = pos;jpos > 0;jpos++) jump_to_end[depth][jpos] = this line <<=============
The basic logic for conditionals is that when a left curly bracket is encountered, a jump is created and added by reference to array[depth++][pos++]. When a right curly bracket is found, array[depth--][pos].pos is set to the current line. If pos >= 1, then another jump is added for end-of-conditional-block-jump and added a jump_to_end[depth][pos]. When a right curly bracket is found and pos >= 0, then every jump in jump_to_end is set to the current line.
Or, for a for loop:
for(int z = 0;z < x;z++) {
y += 0.1;
}
Would precompile into:
add variable { name: "z", type: int, value: "0" }
add variable { name: "0", type: int, value: "0" }
add statement { type: assign, var_1: "z", var_2: "0" }
add statement { type: lt, var_1: "z", var_2: "x" }
add statement { type: jump, pos: undef } -------------------------------------------.
// jump[depth][pos++] = this jump |
add variable { name: "1", type: int, value: "1" } |
add statement { type: add, var_1: "z", var_2: "1" } |
add variable { name: "0.1", type: float, value: "0.1" } |
add statement { type: add, var_1: "y", var_2: "0.1" } |
// set jump[depth][pos].pos = this line <-------------------------------------------'
Once parsing is complete, as marked by the depth reaching -1, the precompilation process is complete.
Functions reserve special locations in memory for return and parameters. For example:
int myFunction(int some_value) {
int i = some_value -1;
return i;
}
Would precompile into:
add variable { name: "i", type: int, value: "0" }
add statement { type: assign, var_1: "i", var_2: "some_value" }
add statement { type: min, var_1: "i", var_2: "1" }
add statement { type: return, var_1: "i" }
Then:
int i = myFunction(1);
precompiles into:
add variable { name: "i", type: int, value: "0" }
add variable { name: "1", type: int, value: "1" }
add statement { type: call, var_return: "i", var_1: "myFunction", var_2: "1" }
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
Program Structure - compilation
````````````````````````````````
The compilation process begins by iterating over all precompiled variables and functions. First, memory is allocated for all variables, starting from global, creating vm_Stacks for the bytesize necessary to fit all variables. The values are then copied into their appropriate locations in memory, with the precompiled variable's target pointer set to these locations.
After this, precompiled statements are converted into bytecode operations. Variables are replaced with their memory addresses and statement types with OP codes.
There is more written about the OP code format in my(kts) .plan files for 2014/03, and as such, will not be written here.
================================================================
*/
#include "vm_compile.h"
#include "vm.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char *vm_datatypes[] = {
"char",
"int",
"float",
"string"
};
#define TYPE_CHAR 0
#define TYPE_INT 1
#define TYPE_FLOAT 2
#define TYPE_STRING 3
#define MAX_TYPES 3
char *vm_expressions[] = {
"return",
"if",
"while",
"for"
};
#define EXP_RETURN 0
#define EXP_IF 1
#define EXP_WHILE 2
#define EXP_FOR 3
#define MAX_EXPS 3
char *vm_assignments[] = {
"=",
"+=",
"-=",
"*=",
"/="
};
#define ASS_EQ 0
#define ASS_ADD 1
#define ASS_MIN 2
#define ASS_MUL 3
#define ASS_DIV 4
#define MAX_ASS 4
char *vm_operations[] = {
"+",
"-",
"*",
"/"
};
#define OP_ADD 0
#define OP_MIN 1
#define OP_MUL 2
#define OP_DIV 3
#define MAX_OPS 3
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;
}
/*
================================
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_precompileCode for actual precompilation.
================================
*/
int vm_precompileFile(const char *file_name) {
FILE *file = fopen(file_name, "r");
if (file == NULL) {
return -1;
}
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 precompileCode
int total_errors = 0; // total error count, used in return
while(( c = fgetc(file)) != EOF) {
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_precompileCode(file, &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 variables\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_precompileCode(file, &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 variables\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_precompileCode(file, &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 variables\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);
return total_errors; // success, baby
}
#define DISCOVER 0
int vm_precompileCode(FILE *file, int *lpos_, int *cpos_, struct vm_pc_Scope *global, struct vm_pc_Scope *group, struct vm_pc_Scope *local) {
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) {
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
// when ( is encountered and parenthesis depth is 0, end the current word, and start new word with '('. Otherwise, add parenthesis to current word.
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') {
// when a ';' is encountered, this equates to a variable 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;
}
}
//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;
}
}
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 == '{') {
// TODO: create vm_pc_Function and set some current scope up for statements.
// TODO: also check for conditional thing and convert to ops, of course
// TODO: run a check for function-style adherence
// TODO: call vm_precompileFunction
/*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);
} 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;
return error;
}
/*
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;
}
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;
}
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;
}
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;
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++;
}
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;
}
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_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_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_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;
}