From 30472bf0ca1e0cbdadac5e6f88b7cdcafdfb73b3 Mon Sep 17 00:00:00 2001 From: kts Date: Tue, 15 Apr 2014 11:18:52 -0700 Subject: [PATCH] Precompiler now adds Variables to a pc_Variable Table. Additional precompilation error checking implemented. TablePair now uses a T_POINTER type. If this data type is used, the memory pointed to is _not_ freed when the TablePair or its parent Table is freed. The developer must remember to free this data type manually when it is used. --- common/data.c | 3 + common/data.h | 1 + test/code/all.vmc | 25 ++-- test/vm_compile.c | 283 ++++++++++++++++++++++++++++++++++++++++++---- test/vm_compile.h | 22 +++- 5 files changed, 300 insertions(+), 34 deletions(-) diff --git a/common/data.c b/common/data.c index 565656a..70fd8f1 100644 --- a/common/data.c +++ b/common/data.c @@ -401,6 +401,9 @@ void freeTablePair(struct TablePair *table_pair) { struct TablePair *sub_pair = pair->next; free(pair->key); switch (pair->type) { + case T_POINTER: + // we do nothing with pointers - remember to free yoself! + break; case T_PROTO_INVENTORY: freeInventoryData(pair->value); break; diff --git a/common/data.h b/common/data.h index 7aa5a32..a7f4057 100644 --- a/common/data.h +++ b/common/data.h @@ -14,6 +14,7 @@ #define T_DOUBLE 8 #define T_LONG_DOUBLE 9 #define T_STRING 20 +#define T_POINTER 30 #define T_TABLE 50 diff --git a/test/code/all.vmc b/test/code/all.vmc index 90dcead..d5cd3fa 100644 --- a/test/code/all.vmc +++ b/test/code/all.vmc @@ -1,17 +1,20 @@ { - return; - int x = 2; - int x y; - int x = y = z; - int test = 2; - string hate; + int global_x = 0; + string str = "test string"; + float fl = 0.1f; + char ch = 'a'; int globalFunction(int param_1) { - return (param_1 - 1); + int i = param_1 - 1; + return i; } } -0:0 { - int x; - int y = 2; - int = =; +0 { + int group_x; + int 2; +} + +0:0 { + int local_x = 2; + int y = 2; } diff --git a/test/vm_compile.c b/test/vm_compile.c index 68de5e1..e4c806d 100644 --- a/test/vm_compile.c +++ b/test/vm_compile.c @@ -33,7 +33,7 @@ Categorization of functions into global, group, and individual is accomplished t 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 apropriate 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. +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 ```````````````````````````````` @@ -216,12 +216,16 @@ int main(int argc, char *argv[]) { 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); - switch(vm_precompileFile(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("-> ERR: could not open file for reading\n"); + 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; } } @@ -254,7 +258,7 @@ The appropriate scopes are created and passed to vm_precompileCode for actual pr int vm_precompileFile(const char *file_name) { FILE *file = fopen(file_name, "r"); if (file == NULL) { - return 1; + return -1; } char c; // current char! int cpos = 1; // char position @@ -264,6 +268,7 @@ int vm_precompileFile(const char *file_name) { 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) { @@ -286,8 +291,11 @@ int vm_precompileFile(const char *file_name) { 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 @@ -299,8 +307,14 @@ int vm_precompileFile(const char *file_name) { 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 { @@ -330,8 +344,15 @@ int vm_precompileFile(const char *file_name) { 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; @@ -346,7 +367,7 @@ int vm_precompileFile(const char *file_name) { } } fclose(file); - return 0; // success, baby + return total_errors; // success, baby } #define DISCOVER 0 @@ -359,7 +380,21 @@ int vm_precompileCode(FILE *file, int *lpos_, int *cpos_, struct vm_pc_Scope *gl int wpos = 0; // word position, i.e., X int wcpos = 0; // word character position, i.e., Y int error = 0; - struct vm_pc_Scope *current_scope = local; // default scope is local + 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) { @@ -396,6 +431,7 @@ int vm_precompileCode(FILE *file, int *lpos_, int *cpos_, struct vm_pc_Scope *gl 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; @@ -413,22 +449,62 @@ int vm_precompileCode(FILE *file, int *lpos_, int *cpos_, struct vm_pc_Scope *gl } 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_ . . ." - // check against dbl datatype declaration, i.e., int int + // 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) { - printf("ADDING %s %s\n", words[wwpos-1], words[wwpos]); + // 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 @@ -443,7 +519,20 @@ int vm_precompileCode(FILE *file, int *lpos_, int *cpos_, struct vm_pc_Scope *gl error++; break; } else { - printf("SETTING %s %s %s\n", words[wwpos-1], words[wwpos], words[wwpos+1]); + // 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]); @@ -451,6 +540,7 @@ int vm_precompileCode(FILE *file, int *lpos_, int *cpos_, struct vm_pc_Scope *gl } } } + // VARIABLE SETTING cont'd } else { wtypes[wwpos] = vm_isReserved(words[wwpos]); if (wtypes[wwpos] == 4) { // "=" @@ -460,7 +550,20 @@ int vm_precompileCode(FILE *file, int *lpos_, int *cpos_, struct vm_pc_Scope *gl error++; break; } else { - printf("SETTING %s %s %s\n", words[wwpos-1], words[wwpos], words[wwpos+1]); + // 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]); @@ -468,41 +571,44 @@ int vm_precompileCode(FILE *file, int *lpos_, int *cpos_, struct vm_pc_Scope *gl } } } - + // END VARIABLE SETTING } - printf("\t\t"); + // END VARIABLE PARSING + /*printf("\t\t"); for(wwpos = 0;wwpos <= wpos;wwpos++) { printf("%s ", words[wwpos]); } - printf("\n"); + 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 - printf("func, while, etc. baby\n"); - int wwpos = 0; + // 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? - printf("function body\n"); - int wwpos = 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; } @@ -512,6 +618,68 @@ int vm_precompileCode(FILE *file, int *lpos_, int *cpos_, struct vm_pc_Scope *gl 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++) { @@ -536,3 +704,78 @@ int vm_isReserved(char *word) { } 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; +} diff --git a/test/vm_compile.h b/test/vm_compile.h index 1e4ee52..c0a2eba 100644 --- a/test/vm_compile.h +++ b/test/vm_compile.h @@ -19,7 +19,8 @@ struct Table *vm_pc_groupVariables; struct Table *vm_pc_localVariables; struct vm_pc_Variable { - // ?? + char *type; // data type as string, malloc'd and memcpy'd + char *data; // data as string, malloc'd and memcpy'd }; struct vm_pc_Operation { @@ -31,8 +32,10 @@ struct vm_pc_Operation { }; struct vm_pc_Function { - struct Table *variables; - struct Table *operations; + struct vm_pc_Variable ret; // return variable + struct Table *parameters; // input params + struct Table *variables; // function local variables + struct Table *operations; // operations! :) }; struct vm_pc_Scope { @@ -46,6 +49,19 @@ struct Table *vm_pc_local_scopes; int vm_precompileFile(const char *file_name); 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 vm_pc_addVariableToScope(struct vm_pc_Scope *scope, const char *data_type, const char *data_name); int vm_isReserved(char *word); +int vm_pc_freeScope(struct vm_pc_Scope *scope); + +struct vm_pc_Variable *vm_pc_newVariable(const char *type, const char *value); +int vm_pc_freeVariable(struct vm_pc_Variable *variable); +int vm_pc_freeVariables(struct Table *variables); +int vm_pc_setVariable(struct vm_pc_Variable *variable, const char *value); + +int vm_pc_freeFunction(struct vm_pc_Function *function); +int vm_pc_freeFunctions(struct Table *functions); + +int vm_pc_dumpScope(struct vm_pc_Scope *scope); + #endif