timesynk/test/script.c

635 lines
17 KiB
C

/****** script.c
This is the test/devel environment for the ts interpreter/scripting language. It provides a basic CLI for entering script to be interpreted live.
******/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h> // ULONG_MAX
#define DIGIT 1
#define ALPHA 2
#define VAR_SET 1
#define RETURN 2
//#define TEST_FUNC "var1 = 2;\nvar2 = 4;\ndam = 2 * 2 / 2;\n.dam;\n"
//#define TEST_FUNC "var1 = 8;\ndam = var1 * 2 / 4;\n.dam;\n"
//#define TEST_FUNC "var1 = 2;var2 = 3;var3 = 7;dam = var1 * var2 * var3;dam = dam * var2;.dam;"
#define TEST_FUNC "var1 = 2;var2 = 3;var3 = 7;var4 = 22;dam = var1 * var2 * var4 / var3;dam = dam * var2;.dam;"
#define TEST_FULL_FUNC "test { var1 = 2;var2 = 3;var3 = 7;dam = var1 * var2 * var3;dam = dam * var2;.dam; }"
#define TEST_FUNC_CALL "fcall { var = test();.var; }"
#define ROLL_FUNC "roll { var=_roll($_1,$_2);.var; }"
struct Arguments {
const char *arg1;
const char *arg2;
const char *arg3;
const char *arg4;
};
typedef char *(*fptr)(char*);
struct FuncTable {
int size;
char **keys;
//void (**func)();
fptr *func;
};
struct FuncTable *newFuncTable(int size) {
struct FuncTable *func_table = malloc(sizeof(struct FuncTable));
func_table->size = size;
func_table->keys = malloc(sizeof(char*)*size);
//func_table->func = malloc(sizeof(void*)*size);
func_table->func = malloc(sizeof(fptr*)*size);
return func_table;
}
void freeFuncTable(struct FuncTable *func_table) {
free(func_table->keys);
free(func_table->func);
free(func_table);
}
int getFuncIndex(struct FuncTable *func_table, char *key) {
unsigned long int func = 0;
int i = 0;
while (func < ULONG_MAX && i < strlen(key)) {
func += key[i++];
}
return func % func_table->size;
}
void addFunc(struct FuncTable *func_table, char *key, void(*func)) {
int index = getFuncIndex(func_table, key);
func_table->keys[index] = key;
func_table->func[index] = func;
}
fptr runFunc(struct FuncTable *func_table, char *key) {
return func_table->func[getFuncIndex(func_table, key)];
}
struct HashTable {
int size;
char **keys;
void **values;
};
struct FuncTable *g_functions;
struct HashTable *newHashTable(int size) {
struct HashTable *hash_table = malloc(sizeof(struct HashTable));
hash_table->size = size;
hash_table->keys = malloc(sizeof(char*)*size);
hash_table->values = malloc(sizeof(void*)*size);
return hash_table;
}
void freeHashTable(struct HashTable *hash_table) {
free(hash_table->keys);
free(hash_table->values);
free(hash_table);
}
int getHashIndex(struct HashTable *hash_table, char *key) {
unsigned long int hash = 0;
int i = 0;
while (hash < ULONG_MAX && i < strlen(key)) {
hash += key[i++];
}
return hash % hash_table->size;
}
void addHash(struct HashTable *hash_table, char *key, void *value) {
int index = getHashIndex(hash_table, key);
hash_table->keys[index] = key;
hash_table->values[index] = value;
}
void *getHash(struct HashTable *hash_table, char *key) {
return hash_table->values[getHashIndex(hash_table, key)];
}
struct VarTable {
int size;
char **keys;
char **values;
};
struct VarTable *function_table;
char *parseAndCallFunction(struct VarTable *var_table, const char *buffer);
struct VarTable *newVarTable(int size) {
struct VarTable *var_table = malloc(sizeof(struct VarTable));
var_table->size = size;
var_table->keys = malloc(sizeof(char*)*size);
var_table->values = malloc(sizeof(char*)*size);
return var_table;
}
void freeVarTable(struct VarTable *var_table) {
// TODO: free key-value pairs
free(var_table->keys);
free(var_table->values);
free(var_table);
}
int getVarIndex(struct VarTable *var_table, const char *key) {
// int hash = 0;
unsigned long int hash = 0;
int i = 0;
while (hash < ULONG_MAX && i < strlen(key)) {
//while (i < strlen(key)) {
//hash = hash << 8;
hash += key[i++];
}
return hash % var_table->size;
}
void addVar(struct VarTable *var_table, const char *key, char *value) {
int index = getVarIndex(var_table, key);
int key_length = strlen(key)+1;
var_table->keys[index] = malloc(key_length);
memcpy(var_table->keys[index], key, key_length);
int value_length = strlen(value)+1;
var_table->values[index] = malloc(value_length);
memcpy(var_table->values[index], value, value_length);
}
void freeVar(struct VarTable *var_table, const char *key) {
int index = getVarIndex(var_table, key);
if (var_table->keys[index])
free(var_table->keys[index]);
if (var_table->values[index])
free(var_table->values[index]);
}
char *getVar(struct VarTable *var_table, const char *key) {
int index = getVarIndex(var_table, key);
return var_table->values[index];
}
struct Var {
int bytes;
char type;
char operation;
char *data;
};
char* itoa(int value, char* result, int base) {
// check that the base if valid
if (base < 2 || base > 36) { *result = '\0'; return result; }
char* ptr = result, *ptr1 = result, tmp_char;
int tmp_value;
do {
tmp_value = value;
value /= base;
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
} while ( value );
// Apply negative sign
if (tmp_value < 0) *ptr++ = '-';
*ptr-- = '\0';
while(ptr1 < ptr) {
tmp_char = *ptr;
*ptr--= *ptr1;
*ptr1++ = tmp_char;
}
return result;
}
// TODO: replace Arguments with v_printf stuff
void doOperation(struct VarTable *var_table, const char **args, int arg_count, char *return_string, const char *string) {
printf("args: %d\n", arg_count);
//printf("operation is %s\n", string);
int s_i = 0; // string iterator
int b_i = 0; // buffer iterator
int bt_i = 0; // buffer type iterator
char buffer[255]; // buffer that holds the portion being processed
struct Var vars[31]; // max 31 variables
int var_i = 0;
int c_i = 0; // current var iterator
char *f_return; // function call pointer
while (string[s_i] != '\0') {
switch (string[s_i]) {
case '+':
case '-':
case '/':
case '*':
if (isdigit(buffer[0]))
vars[var_i].type = DIGIT;
else
vars[var_i].type = ALPHA;
buffer[b_i] = '\0';
if (vars[var_i].type == ALPHA) {
if (arg_count > 0)
printf("first part of arg0: %c\n", args[0][0]);
if (buffer[b_i-1] == ')') {
f_return = parseAndCallFunction(var_table, buffer);
vars[var_i].bytes = strlen(f_return)+1;
vars[var_i].data = malloc(vars[var_i].bytes);
strcpy(vars[var_i].data, f_return);
free(f_return);
} else {
vars[var_i].bytes = strlen(getVar(var_table, buffer))+1;
vars[var_i].data = malloc(vars[var_i].bytes);
strcpy(vars[var_i].data, getVar(var_table, buffer));
}
} else {
vars[var_i].bytes = strlen(buffer)+1;
vars[var_i].data = malloc(vars[var_i].bytes);
strcpy(vars[var_i].data, buffer);
}
memset(&buffer, '\0', 255);
b_i = 0;
vars[var_i].operation = string[s_i];
var_i++;
break;
case ';':
buffer[b_i] = '\0';
// determine variable type
if (isdigit(buffer[0]))
vars[var_i].type = DIGIT;
else
vars[var_i].type = ALPHA;
if (vars[var_i].type == ALPHA) {
if (buffer[b_i-1] == ')') {
f_return = parseAndCallFunction(var_table, buffer);
vars[var_i].bytes = strlen(f_return)+1;
vars[var_i].data = malloc(vars[var_i].bytes);
strcpy(vars[var_i].data, f_return);
free(f_return);
} else {
vars[var_i].bytes = strlen(getVar(var_table, buffer))+1;
vars[var_i].data = malloc(vars[var_i].bytes);
strcpy(vars[var_i].data, getVar(var_table, buffer));
}
} else {
vars[var_i].bytes = strlen(buffer)+1;
vars[var_i].data = malloc(vars[var_i].bytes);
strcpy(vars[var_i].data, buffer);
}
// "clear" buffer
memset(&buffer, '\0', 255);
b_i = 0;
// ALRIGHT, now let's do the operaton
c_i = 0;
while (c_i < var_i) {
switch (vars[c_i].operation) {
case '+':
itoa(atoi(vars[c_i].data) + atoi(vars[c_i+1].data), vars[c_i+1].data, 10);
break;
case '-':
itoa(atoi(vars[c_i].data) - atoi(vars[c_i+1].data), vars[c_i+1].data, 10);
break;
case '*':
itoa(atoi(vars[c_i].data) * atoi(vars[c_i+1].data), vars[c_i+1].data, 10);
break;
case '/':
itoa(atoi(vars[c_i].data) / atoi(vars[c_i+1].data), vars[c_i+1].data, 10);
break;
}
c_i++;
}
//printf(" = %s\n", vars[c_i].data);
strcpy(return_string, vars[c_i].data);
break;
case ' ':
break;
default:
buffer[b_i] = string[s_i];
b_i++;
break;
}
s_i++;
}
while (var_i >= 0) {
free(vars[var_i--].data);
}
}
void doVarSet(struct Var *var, const char *string) {
if (var->data)
free(var);
var->bytes = strlen(string)+1;
var->data = malloc(var->bytes);
memcpy(var->data, string, var->bytes);
}
// TODO: use vprintf stuff for arguments (or get byte offsets?)
char *doFunction(const char *function, const char *arguments) {
/* get our args from buffer, delimited by ',' */
int ba_i = 0;
char args[2][31];
int a_i = 0;
int arg_offset = 0;
if (arguments[ba_i] != '\0')
arg_offset++;
while (arguments[ba_i] != '\0') {
switch (arguments[ba_i]) {
case ',':
args[arg_offset][a_i] = '\0';
a_i = 0;
arg_offset++;
break;
case ' ':
break;
default:
args[arg_offset][a_i++] = arguments[ba_i];
break;
}
ba_i++;
}
args[arg_offset][a_i] = '\0';
/* okay, let's do the rolling. TODO: handle lack of args */
if (arg_offset > 0)
printf("passed arg 0: %s\n", args[0]);
printf("running function:\n%s\n-------\n", function);
struct VarTable *local_vars = newVarTable(127);
int b_i = 0; // buffer iterator
int bt_i = 0; // buffer type iterator
char buffer[255]; // buffer that holds the portion being processed
char current_var[31]; // vars cannae have more than 31 chars
char current_value[31];
current_var[0] = '\0';
int mode = 0;
struct Var vars[31]; // max 31 variables
int var_i = 0;
int c_i = 0; // current var iterator
int f_i = 0; // function char pos
int l_i = 0; // line pos
int l_c = 0; // line count
size_t f_bytes = 0;
char *f_return = malloc(1);
while (function[f_i] != '\0') {
switch(function[f_i]) {
case '\n':
l_c++;
break;
case ' ': // skip space
break;
case '=':
buffer[b_i] = '\0';
b_i = 0;
strcpy(current_var, buffer);
memset(&buffer, 0, 255);
mode = VAR_SET;
break;
case ';':
if (mode == VAR_SET) {
buffer[b_i++] = ';';
buffer[b_i] = '\0';
b_i = 0;
doOperation(local_vars, &args, arg_offset, current_value, buffer);
addVar(local_vars, current_var, current_value);
} else if (mode == RETURN) {
buffer[b_i] = '\0';
b_i = 0;
strcpy(current_var, buffer);
f_bytes = strlen(getVar(local_vars, current_var))+1;
realloc(f_return, f_bytes);
memcpy(f_return, getVar(local_vars, current_var), f_bytes);
freeVarTable(local_vars); // free up all our local stuff
return f_return;
}
break;
case '.':
if (b_i == 0) {
mode = RETURN;
} else {
buffer[b_i++] = function[f_i];
}
break;
default:
buffer[b_i++] = function[f_i];
break;
}
f_i++; // next char in func
}
freeVarTable(local_vars); // free up all our local stuff
return f_return;
}
char *callFunction(const char *f_name, const char *f_args) {
return (doFunction(getVar(function_table, f_name), f_args));
}
char *parseAndCallFunction(struct VarTable *var_table, const char *buffer) {
int b_i = 0;
char f_name[32];
char f_args[63];
int f_i = 0;
int mode = 0;
while (buffer[b_i] != '\0') {
switch (buffer[b_i]) {
case '(':
f_name[f_i] = '\0';
f_i = 0;
mode = 1;
break;
case ')':
f_args[f_i] = '\0';
f_i = 0;
mode = 2;
break;
case ' ':
break;
default:
if (mode == 0) {
f_name[f_i++] = buffer[b_i];
} else if (mode > 0) {
f_args[f_i++] = buffer[b_i];
// do something with args...
}
break;
}
b_i++;
}
/* convert args son */
// FIXME: hackish, q'n'd
b_i = 0;
char args[10][31];
int a_i = 0;
int arg_offset = 0;
while (f_args[b_i] != '\0') {
switch (f_args[b_i]) {
case ',':
args[arg_offset][a_i] = '\0';
a_i = 0;
arg_offset++;
break;
case ' ':
break;
default:
args[arg_offset][a_i++] = f_args[b_i];
break;
}
b_i++;
}
args[arg_offset][a_i] = '\0';
if (f_args[0] != '\0') {
a_i = 0;
f_i = 0;
b_i = 0;
while (a_i <= arg_offset) {
if (!isdigit(args[a_i][0])) {
strcpy(args[a_i], getVar(var_table, args[a_i]));
}
//printf("%d = %s\n", a_i, args[a_i]);
b_i = 0;
while (args[a_i][b_i] != '\0') {
f_args[f_i++] = args[a_i][b_i++];
}
if (a_i != arg_offset)
f_args[f_i++] = ',';
a_i++;
}
}
f_args[f_i] = '\0';
if (f_name[0] == '_') {
//printf("trying to run %s\n", f_name);
return runFunc(g_functions, f_name)(f_args);
} else {
// TODO: callFunction should parse f_args as well.
return callFunction(f_name, f_args);
}
//return callFunction(f_name, NULL, NULL, NULL, NULL);
}
int addFunction(const char *buffer) {
char func_name[32];
int f_size = 128;
char *func_data = malloc(f_size*sizeof(char)); // start w/ 128 chars
int f_i = 0; // func_data index offset
int c_i = 0; // iterator for function_name
int i = 0; // iterator for the buffer
int depth = 0;
while (buffer[i] != '\0') {
switch (buffer[i]) {
case ' ':
break;
case '{':
if (depth == 0)
func_name[c_i] = '\0';
depth++;
break;
case '}':
depth--;
break;
default:
if (depth == 0) {
func_name[c_i++] = buffer[i];
} else if (depth > 0) {
// resize if function surpasses our temp func_data buffer
if (f_i+1 >= f_size) {
f_size += 128;
realloc(func_data, f_size);
}
func_data[f_i] = buffer[i];
f_i++;
}
break;
}
i++;
}
func_data[f_i] = '\0';
addVar(function_table, func_name, func_data);
free(func_data);
return 0; // should handle errors for malloc...
}
char *doRoll(const char *buffer) {
/* get our args from buffer, delimited by ',' */
int b_i = 0;
char args[2][31];
int a_i = 0;
int arg_offset = 0;
while (buffer[b_i] != '\0') {
switch (buffer[b_i]) {
case ',':
args[arg_offset][a_i] = '\0';
a_i = 0;
arg_offset++;
break;
case ' ':
break;
default:
args[arg_offset][a_i++] = buffer[b_i];
break;
}
b_i++;
}
args[arg_offset][a_i] = '\0';
/* okay, let's do the rolling. TODO: handle lack of args */
int count = atoi(args[0]);
int faces = atoi(args[1]);
int total = 0;
while (count > 0) {
total += (rand() % faces + 1);
count--;
}
/* return char array pointer that will be freed outside of this func */
char *f_return = malloc(24);
itoa(total, f_return, 10);
return f_return;
}
int main() {
function_table = newVarTable(255);
g_functions = newFuncTable(127); // function pointers
addFunc(g_functions, "_roll", doRoll);
/* #define'd function */
addFunction(TEST_FULL_FUNC);
addFunction(ROLL_FUNC);
char *f_return;
f_return = callFunction("test", "");
printf("called func \"%s\" returned:\n%s\n", "test", f_return);
free(f_return);
/* free hand this ish */
addFunction("add { var = 1 + 2; .var; }");
f_return = callFunction("add", "");
printf("called func \"%s\" returned:\n%s\n", "add", f_return);
free(f_return);
addFunction(TEST_FUNC_CALL);
f_return = callFunction("fcall", "");
printf("called func \"%s\" returned:\n%s\n", "fcall", f_return);
free(f_return);
char user_input[1024];
printf("Enter script:\n> ");
//scanf("%s", user_input);
fgets(user_input, 1024, stdin);
f_return = doFunction(user_input, "");
printf("return:\n%s\n", f_return);
free(f_return);
freeVarTable(function_table);
freeFuncTable(g_functions);
/* char *f_return;
f_return = doFunction(TEST_FUNC, NULL, NULL, NULL, NULL);
printf("return: %s\n", f_return);
free(f_return);*/
return 0;
}