diff --git a/README b/README index 6efb7c9..ab5d5b7 100644 --- a/README +++ b/README @@ -9,3 +9,5 @@ Building can be accomplished using "make," or "make rebuild". To build a debug version, add "DEBUG=yes" after "make". To build a binary with profiling enabled, add "PROFILE=yes" after "make". + +I can be reached at "joseph.kogut(at)gmail.com" diff --git a/SYNTAX b/SYNTAX index e0d3299..5887d71 100644 --- a/SYNTAX +++ b/SYNTAX @@ -78,9 +78,17 @@ Labels must be specified at the beginning of a line or on their own line. // 4. PREPROCESSOR /////////////////////////////// ////////////////////////////////////////////////// -TVM has a preprocessor that allows other source files to be included with the directive "%include filename.vm" +TVM's preprocessor works similarly to many C compilers and uses the prefix "%". -During preprocessing, the entire included source file is inserted in place of the %include directive in memory. + // I. Include // + + %include filename + Pastes all of the contents of filename into the source code before interpretting it. + + // II. Define // + + %define identifier value + Define a constant so that all instances of the string "identifier" will be replaced by "value". ////////////////////////////////////////////////// // 5. INSTRUCTION LISTING //////////////////////// diff --git a/TODO b/TODO index 217478d..04d1804 100644 --- a/TODO +++ b/TODO @@ -14,4 +14,4 @@ TODO: - C interface - C Library written in TVM code -Please send patches to Joseph Kogut +Please send patches to Joseph Kogut diff --git a/include/tvm/tvm_htab.h b/include/tvm/tvm_htab.h index 0adc68e..eb9c4be 100644 --- a/include/tvm/tvm_htab.h +++ b/include/tvm/tvm_htab.h @@ -8,6 +8,7 @@ typedef struct tvm_htab_node_s { char *key; int value; + void *valptr; struct tvm_htab_node_s *next; } tvm_htab_node_t; @@ -22,6 +23,8 @@ tvm_htab_t* htab_create(); void htab_destroy(tvm_htab_t *htab); int htab_add(tvm_htab_t *htab, const char *key, int value); +int htab_add_ref(tvm_htab_t *htab, const char *key, const void *valptr, int len); int htab_find(tvm_htab_t *htab, const char *key); +char *htab_find_ref(tvm_htab_t *htab, const char *key); #endif diff --git a/include/tvm/tvm_lexer.h b/include/tvm/tvm_lexer.h index 6b28a6b..6724b5a 100644 --- a/include/tvm/tvm_lexer.h +++ b/include/tvm/tvm_lexer.h @@ -4,6 +4,8 @@ #define MAX_ARGS 2 #define MAX_TOKENS 4 +#include "tvm_htab.h" + typedef struct tvm_lexer_s { char **source_lines; @@ -14,6 +16,6 @@ tvm_lexer_t *lexer_create(); void lexer_destroy(tvm_lexer_t *l); /* Tokenize the character array "source" into lines and tokens */ -void lex(tvm_lexer_t *lexer, char *source); +void lex(tvm_lexer_t *lexer, char *source, tvm_htab_t *defines); #endif diff --git a/include/tvm/tvm_preprocessor.h b/include/tvm/tvm_preprocessor.h index e999950..9832c62 100644 --- a/include/tvm/tvm_preprocessor.h +++ b/include/tvm/tvm_preprocessor.h @@ -1,6 +1,8 @@ #ifndef TVM_PREPROCESSOR_H_ #define TVM_PREPROCESSOR_H_ -int tvm_preprocess(char *src, int *src_len); +#include "tvm_htab.h" + +int tvm_preprocess(char *src, int *src_len, tvm_htab_t *defines); #endif diff --git a/include/tvm/tvm_program.h b/include/tvm/tvm_program.h index e5722f1..88a85c4 100644 --- a/include/tvm/tvm_program.h +++ b/include/tvm/tvm_program.h @@ -20,6 +20,8 @@ typedef struct tvm_program_s int **values; int num_values; + tvm_htab_t *defines; + tvm_htab_t *label_htab; } tvm_program_t; diff --git a/libtvm/tvm_htab.c b/libtvm/tvm_htab.c index 84f813b..3ad5db3 100644 --- a/libtvm/tvm_htab.c +++ b/libtvm/tvm_htab.c @@ -25,6 +25,8 @@ void htab_destroy(tvm_htab_t *htab) while(node) { next = node->next; + if(node->valptr) + free(node->valptr); free(node->key); free(node); node = next; @@ -65,7 +67,13 @@ static void htab_rehash(tvm_htab_t *orig, unsigned int size) while(node) { next = node->next; - htab_add(new, node->key, node->value); + if (node->valptr) + { + htab_add_ref(new, node->key, node->valptr, strlen(node->valptr) + 1); + free(node->valptr); + } + else + htab_add(new, node->key, node->value); free(node->key); free(node); node = next; @@ -79,8 +87,13 @@ static void htab_rehash(tvm_htab_t *orig, unsigned int size) free(new); } -int htab_add(tvm_htab_t *htab, const char *k, int v) +static tvm_htab_node_t *htab_add_core(tvm_htab_t *htab, const char *k) { + /* Increase bucket count and rehash if the + load factor is too high */ + if((float)++htab->num_nodes / htab->size > HTAB_LOAD_FACTOR) + htab_rehash(htab, htab->num_nodes * 2); + int hash = htab_hash(k, htab->size); tvm_htab_node_t *node = htab->nodes[hash]; tvm_htab_node_t *prev = NULL; @@ -101,33 +114,71 @@ int htab_add(tvm_htab_t *htab, const char *k, int v) node->key = (char *)calloc((strlen(k) + 1), sizeof(char)); strcpy(node->key, k); - node->value = v; - if(prev) prev->next = node; else htab->nodes[hash] = node; /* root node */ node->next = NULL; - /* Increase bucket count and rehash if the - load factor is too high */ - if((float)++htab->num_nodes / htab->size > HTAB_LOAD_FACTOR) - htab_rehash(htab, htab->num_nodes * 2); + return node; +} + +int htab_add(tvm_htab_t *htab, const char *key, int value) +{ + tvm_htab_node_t *node = htab_add_core(htab, key); + + if (!node) + return -1; + + node->value = value; return 0; } -int htab_find(tvm_htab_t *htab, const char *key) +int htab_add_ref(tvm_htab_t *htab, const char *key, const void *valptr, int len) +{ + tvm_htab_node_t *node = htab_add_core(htab, key); + + if (!node) + return -1; + + node->valptr = calloc(len, sizeof(char)); + memcpy(node->valptr, valptr, len); + + return 0; +} + +static tvm_htab_node_t *htab_find_core(tvm_htab_t *htab, const char *key) { int hash = htab_hash(key, htab->size); tvm_htab_node_t *node = htab->nodes[hash]; - while(node) + while (node) { if(!strcmp(node->key, key)) - return node->value; - node = node->next; + return node; + else + node = node->next; } - return -1; + return NULL; } +int htab_find(tvm_htab_t *htab, const char *key) +{ + tvm_htab_node_t *node = htab_find_core(htab, key); + + if(!node) + return -1; + + return node->value; +} + +char *htab_find_ref(tvm_htab_t *htab, const char *key) +{ + tvm_htab_node_t *node = htab_find_core(htab, key); + + if (!node) + return NULL; + + return node->valptr; +} diff --git a/libtvm/tvm_lexer.c b/libtvm/tvm_lexer.c index 9b3aa5e..a856fb3 100644 --- a/libtvm/tvm_lexer.c +++ b/libtvm/tvm_lexer.c @@ -26,7 +26,7 @@ void lexer_destroy(tvm_lexer_t *lexer) free(lexer); } -void lex(tvm_lexer_t *lexer, char *source) +void lex(tvm_lexer_t *lexer, char *source, tvm_htab_t *defines) { int i, j; char *pToken, *pLine = strtok(source, "\n"); @@ -60,12 +60,16 @@ void lex(tvm_lexer_t *lexer, char *source) for(j = 0; (pToken && j < MAX_TOKENS); j++) { - lexer->tokens[i][j] = (char *)calloc(1, (strlen(pToken) + 1)); - strcpy(lexer->tokens[i][j], pToken); + char *token = htab_find_ref(defines, pToken); + token = token ? token : pToken; + + lexer->tokens[i][j] = (char *)calloc(1, (strlen(token) + 1)); + strcpy(lexer->tokens[i][j], token); pToken = strtok(NULL, " \t,"); } } lexer->tokens[i] = NULL; + htab_destroy(defines); } diff --git a/libtvm/tvm_preprocessor.c b/libtvm/tvm_preprocessor.c index 6718fc4..a4b41eb 100644 --- a/libtvm/tvm_preprocessor.c +++ b/libtvm/tvm_preprocessor.c @@ -3,7 +3,7 @@ #include -int tvm_preprocess(char *src, int *src_len) +int tvm_preprocess(char *src, int *src_len, tvm_htab_t *defines) { char* pp_directive_delimiter = NULL; if((pp_directive_delimiter = strstr(src, "%include"))) @@ -22,7 +22,7 @@ int tvm_preprocess(char *src, int *src_len) if(!pFile) { printf("Unable to open file \"%s\"\n", filename); - return 0; + return -1; } free(temp_str); @@ -48,6 +48,63 @@ int tvm_preprocess(char *src, int *src_len) *src_len = strlen(src); return 1; } + else if((pp_directive_delimiter = strstr(src, "%define "))) + { + char *begin = pp_directive_delimiter; + char *end = strchr(begin, '\n'); + + if(!end) return 0; + + int offset = strlen("%define "); + + if(begin + offset >= end) + { + printf("Define missing arguments.\n"); + return -1; + } + + int length = (end - (begin + offset)); + char tempstr[length + 1]; + memset(tempstr, 0, length + 1); + memcpy(tempstr, begin + offset, length); + + char *keystr = tempstr; + char *valstr = strchr(tempstr, ' '); + + /* If there is a value, seperate the key and value + with a null character. */ + if(valstr) + { + *valstr = 0; + valstr += 1; + } + + if(!keystr || !valstr) + { + printf("Define missing arguments.\n"); + return -1; + } + + if(htab_find(defines, keystr) < 0) + htab_add_ref(defines, keystr, valstr, strlen(valstr) + 1); + else + { + printf("Multiple definitions for %s.\n", keystr); + return -1; + } + + /* Remove the define line so it is not processed again. */ + size_t new_length = *src_len - (end - begin); + size_t first_block_len = begin - src; + size_t second_block_len = (src + *src_len) - end; + + memmove(&src[first_block_len], end, second_block_len); + + src = realloc(src, sizeof(char) * new_length); + *src_len = new_length; + + return 1; + } return 0; diff --git a/libtvm/tvm_program.c b/libtvm/tvm_program.c index b8ee315..ed563be 100644 --- a/libtvm/tvm_program.c +++ b/libtvm/tvm_program.c @@ -8,6 +8,7 @@ tvm_program_t *program_create() { tvm_program_t *p = (tvm_program_t *)calloc(1, sizeof(tvm_program_t)); p->label_htab = htab_create(); + p->defines = htab_create(); return p; } @@ -54,10 +55,15 @@ pi_interpret: tvm_fcopy(source, source_length, pFile); fclose(pFile); - while(tvm_preprocess(source, &source_length)); + int err = 0; + while((err = tvm_preprocess(source, &source_length, p->defines)) > 0); + + /* The preprocessor encountered a problem. */ + if (err < 0) + return 1; tvm_lexer_t *lexer_ctx = lexer_create(); - lex(lexer_ctx, source); + lex(lexer_ctx, source, p->defines); free(source); if(parse_labels(p, (const char ***)lexer_ctx->tokens) != 0) return 1; diff --git a/programs/tinyvm/preprocessor/define.vm b/programs/tinyvm/preprocessor/define.vm new file mode 100644 index 0000000..2ade114 --- /dev/null +++ b/programs/tinyvm/preprocessor/define.vm @@ -0,0 +1,20 @@ +%define ONE 1 +%define ZERO 0 + +start: + mov eax, ONE + mov ebx, ZERO + +loop: add eax, ebx + add ebx, eax + + prn eax + prn ebx + + cmp eax, ZERO + jl end + + cmp ebx, ZERO + jg loop + +end: