#include "vm_compile.h" #include "vm.h" #include #include #include #include // 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; }