Merge branch 'master' of https://github.com/jakogut/tinyvm
This commit is contained in:
commit
ca762c48ad
12 changed files with 182 additions and 25 deletions
2
README
2
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
|
To build a debug version, add "DEBUG=yes" after "make". To build a binary with
|
||||||
profiling enabled, add "PROFILE=yes" after "make".
|
profiling enabled, add "PROFILE=yes" after "make".
|
||||||
|
|
||||||
|
I can be reached at "joseph.kogut(at)gmail.com"
|
||||||
|
|
|
||||||
12
SYNTAX
12
SYNTAX
|
|
@ -78,9 +78,17 @@ Labels must be specified at the beginning of a line or on their own line.
|
||||||
// 4. PREPROCESSOR ///////////////////////////////
|
// 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 ////////////////////////
|
// 5. INSTRUCTION LISTING ////////////////////////
|
||||||
|
|
|
||||||
2
TODO
2
TODO
|
|
@ -14,4 +14,4 @@ TODO:
|
||||||
- C interface
|
- C interface
|
||||||
- C Library written in TVM code
|
- C Library written in TVM code
|
||||||
|
|
||||||
Please send patches to Joseph Kogut <joseph.kogut@gmail.com>
|
Please send patches to Joseph Kogut <joseph.kogut(at)gmail.com>
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ typedef struct tvm_htab_node_s
|
||||||
{
|
{
|
||||||
char *key;
|
char *key;
|
||||||
int value;
|
int value;
|
||||||
|
void *valptr;
|
||||||
struct tvm_htab_node_s *next;
|
struct tvm_htab_node_s *next;
|
||||||
} tvm_htab_node_t;
|
} tvm_htab_node_t;
|
||||||
|
|
||||||
|
|
@ -22,6 +23,8 @@ tvm_htab_t* htab_create();
|
||||||
void htab_destroy(tvm_htab_t *htab);
|
void htab_destroy(tvm_htab_t *htab);
|
||||||
|
|
||||||
int htab_add(tvm_htab_t *htab, const char *key, int value);
|
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);
|
int htab_find(tvm_htab_t *htab, const char *key);
|
||||||
|
char *htab_find_ref(tvm_htab_t *htab, const char *key);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
#define MAX_ARGS 2
|
#define MAX_ARGS 2
|
||||||
#define MAX_TOKENS 4
|
#define MAX_TOKENS 4
|
||||||
|
|
||||||
|
#include "tvm_htab.h"
|
||||||
|
|
||||||
typedef struct tvm_lexer_s
|
typedef struct tvm_lexer_s
|
||||||
{
|
{
|
||||||
char **source_lines;
|
char **source_lines;
|
||||||
|
|
@ -14,6 +16,6 @@ tvm_lexer_t *lexer_create();
|
||||||
void lexer_destroy(tvm_lexer_t *l);
|
void lexer_destroy(tvm_lexer_t *l);
|
||||||
|
|
||||||
/* Tokenize the character array "source" into lines and tokens */
|
/* 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
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef TVM_PREPROCESSOR_H_
|
#ifndef TVM_PREPROCESSOR_H_
|
||||||
#define 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
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ typedef struct tvm_program_s
|
||||||
int **values;
|
int **values;
|
||||||
int num_values;
|
int num_values;
|
||||||
|
|
||||||
|
tvm_htab_t *defines;
|
||||||
|
|
||||||
tvm_htab_t *label_htab;
|
tvm_htab_t *label_htab;
|
||||||
|
|
||||||
} tvm_program_t;
|
} tvm_program_t;
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ void htab_destroy(tvm_htab_t *htab)
|
||||||
while(node)
|
while(node)
|
||||||
{
|
{
|
||||||
next = node->next;
|
next = node->next;
|
||||||
|
if(node->valptr)
|
||||||
|
free(node->valptr);
|
||||||
free(node->key);
|
free(node->key);
|
||||||
free(node);
|
free(node);
|
||||||
node = next;
|
node = next;
|
||||||
|
|
@ -65,7 +67,13 @@ static void htab_rehash(tvm_htab_t *orig, unsigned int size)
|
||||||
while(node)
|
while(node)
|
||||||
{
|
{
|
||||||
next = node->next;
|
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->key);
|
||||||
free(node);
|
free(node);
|
||||||
node = next;
|
node = next;
|
||||||
|
|
@ -79,8 +87,13 @@ static void htab_rehash(tvm_htab_t *orig, unsigned int size)
|
||||||
free(new);
|
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);
|
int hash = htab_hash(k, htab->size);
|
||||||
tvm_htab_node_t *node = htab->nodes[hash];
|
tvm_htab_node_t *node = htab->nodes[hash];
|
||||||
tvm_htab_node_t *prev = NULL;
|
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));
|
node->key = (char *)calloc((strlen(k) + 1), sizeof(char));
|
||||||
strcpy(node->key, k);
|
strcpy(node->key, k);
|
||||||
|
|
||||||
node->value = v;
|
|
||||||
|
|
||||||
if(prev) prev->next = node;
|
if(prev) prev->next = node;
|
||||||
else htab->nodes[hash] = node; /* root node */
|
else htab->nodes[hash] = node; /* root node */
|
||||||
|
|
||||||
node->next = NULL;
|
node->next = NULL;
|
||||||
|
|
||||||
/* Increase bucket count and rehash if the
|
return node;
|
||||||
load factor is too high */
|
}
|
||||||
if((float)++htab->num_nodes / htab->size > HTAB_LOAD_FACTOR)
|
|
||||||
htab_rehash(htab, htab->num_nodes * 2);
|
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;
|
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);
|
int hash = htab_hash(key, htab->size);
|
||||||
tvm_htab_node_t *node = htab->nodes[hash];
|
tvm_htab_node_t *node = htab->nodes[hash];
|
||||||
|
|
||||||
while(node)
|
while (node)
|
||||||
{
|
{
|
||||||
if(!strcmp(node->key, key))
|
if(!strcmp(node->key, key))
|
||||||
return node->value;
|
return node;
|
||||||
node = node->next;
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ void lexer_destroy(tvm_lexer_t *lexer)
|
||||||
free(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;
|
int i, j;
|
||||||
char *pToken, *pLine = strtok(source, "\n");
|
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++)
|
for(j = 0; (pToken && j < MAX_TOKENS); j++)
|
||||||
{
|
{
|
||||||
lexer->tokens[i][j] = (char *)calloc(1, (strlen(pToken) + 1));
|
char *token = htab_find_ref(defines, pToken);
|
||||||
strcpy(lexer->tokens[i][j], 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,");
|
pToken = strtok(NULL, " \t,");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lexer->tokens[i] = NULL;
|
lexer->tokens[i] = NULL;
|
||||||
|
htab_destroy(defines);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
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;
|
char* pp_directive_delimiter = NULL;
|
||||||
if((pp_directive_delimiter = strstr(src, "%include")))
|
if((pp_directive_delimiter = strstr(src, "%include")))
|
||||||
|
|
@ -22,7 +22,7 @@ int tvm_preprocess(char *src, int *src_len)
|
||||||
if(!pFile)
|
if(!pFile)
|
||||||
{
|
{
|
||||||
printf("Unable to open file \"%s\"\n", filename);
|
printf("Unable to open file \"%s\"\n", filename);
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(temp_str);
|
free(temp_str);
|
||||||
|
|
@ -48,6 +48,63 @@ int tvm_preprocess(char *src, int *src_len)
|
||||||
*src_len = strlen(src);
|
*src_len = strlen(src);
|
||||||
return 1;
|
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;
|
return 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ tvm_program_t *program_create()
|
||||||
{
|
{
|
||||||
tvm_program_t *p = (tvm_program_t *)calloc(1, sizeof(tvm_program_t));
|
tvm_program_t *p = (tvm_program_t *)calloc(1, sizeof(tvm_program_t));
|
||||||
p->label_htab = htab_create();
|
p->label_htab = htab_create();
|
||||||
|
p->defines = htab_create();
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
@ -54,10 +55,15 @@ pi_interpret:
|
||||||
tvm_fcopy(source, source_length, pFile);
|
tvm_fcopy(source, source_length, pFile);
|
||||||
fclose(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();
|
tvm_lexer_t *lexer_ctx = lexer_create();
|
||||||
lex(lexer_ctx, source);
|
lex(lexer_ctx, source, p->defines);
|
||||||
free(source);
|
free(source);
|
||||||
|
|
||||||
if(parse_labels(p, (const char ***)lexer_ctx->tokens) != 0) return 1;
|
if(parse_labels(p, (const char ***)lexer_ctx->tokens) != 0) return 1;
|
||||||
|
|
|
||||||
20
programs/tinyvm/preprocessor/define.vm
Normal file
20
programs/tinyvm/preprocessor/define.vm
Normal file
|
|
@ -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:
|
||||||
Loading…
Reference in a new issue