635 lines
17 KiB
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;
|
|
}
|