#include #include #include #include "eval.h" #include "hashtable.h" #include "parse.h" sym_t* eval(sym_t* symbol, hashtable_t* parentScope) { if (symbol->province == LITERAL) { if (symbol->litType == INT) { return init_sym_int(*((int*)symbol->name)); } else if (symbol->litType == FLOAT) { return init_sym_float(*((float*)symbol->name)); } else if (symbol->litType == STRING) { return init_sym_str((char*)symbol->name); } else { return NULL; } } else if (symbol->province == KEY_REF) { sym_t* returnV = NULL; /* entering new scope, so create a new table */ hashtable_t* newScope = init_hashtable(50, parentScope); sym_t* ir = try_eval_internal(symbol, newScope); if (ir != NULL) { returnV = ir; } else { /* not an internal function, search hashtable for next symbol */ pair_t p = hashtable_get_pair_recurse(parentScope, (char*)symbol->name); if (p.key != NULL) { sym_t* nextSym = (sym_t*)p.value; if (symbol->argCount > 0) { returnV = eval_with_args(nextSym, symbol->args, symbol->argCount, newScope); } else { returnV = eval(nextSym, newScope); } } else { printf("no matching pair in hashtable\n"); } } /* clear new scope, then return */ destroy_hashtable(newScope); return returnV; } else { printf("no symbol province\n"); return NULL; } } void exec_all(sym_t** symbols, int count, hashtable_t* symbolScope) { for (int i = 0; i < count; i++) { sym_t* sym = eval(symbols[i], symbolScope); destroy_sym(sym); } } sym_t* eval_with_args(sym_t* symbol, sym_t** args, int argCount, hashtable_t* symbolScope) { sym_t** addedArgs = malloc(100 * sizeof(sym_t*)); for (int i = 0; i < argCount && i < 100; i++) { char* keyName = malloc(6 * sizeof(char)); strcpy(keyName, "arg"); char index[3]; snprintf(index, 3, "%d", i); strcat(keyName, index); sym_t* argV = eval(args[i], symbolScope->parent); addedArgs[i] = argV; pair_t argPair = init_pair(keyName, argV); free(keyName); hashtable_add_pair(symbolScope, argPair); } sym_t* v = eval(symbol, symbolScope); /* clean up args */ for (int i = 0; i < argCount && i < 100; i++) { destroy_sym(addedArgs[i]); } free(addedArgs); return v; } /* internal functions? this function has side-effects */ sym_t* try_eval_internal(sym_t* symbol, hashtable_t* symbolScope) { unsigned int hash = get_hash((char*)symbol->name); if (hash == get_hash("root")) { /* execute all args as roots except for the last */ /* return last arg, that's the function return line */ exec_all(symbol->args, symbol->argCount - 1, symbolScope); return eval(symbol->args[symbol->argCount - 1], symbolScope); } else if (hash == get_hash("ref")) { return symbol->args[0]; } else if (hash == get_hash("eval")) { sym_t* v; if (symbol->argCount > 1) { v = eval_with_args(eval(symbol->args[0], symbolScope), symbol->args + 1, symbol->argCount - 1, symbolScope); } else { v = eval(eval(symbol->args[0], symbolScope), symbolScope); } return v; } else if (hash == get_hash("store")) { /* first arg is value, second arg is key */ sym_t* v = eval(symbol->args[1], symbolScope); char* k = symtos(v); destroy_sym(v); sym_t* value = eval(symbol->args[0], symbolScope); pair_t p = init_pair(k, (void*)value); free(k); hashtable_add_pair(symbolScope->parent, p); return init_sym_int(1); } else if (hash == get_hash("update")) { /* first arg is value, second arg is key */ sym_t* v = eval(symbol->args[1], symbolScope); char* k = symtos(v); destroy_sym(v); sym_t* value = symbol->args[0]; pair_t p = init_pair(k, (void*)value); free(k); hashtable_update_pair_recurse(symbolScope->parent, p); return init_sym_int(1); } else if (hash == get_hash("eq")) { litType_t type = NO_TYPE; int firstInt = 0; float firstFloat = 0; char* firstString; for (int i = 0; i < symbol->argCount; i++) { sym_t* v = eval(symbol->args[i], symbolScope); /* initialize */ if (type == NO_TYPE) { type = v->litType; if (type == INT) { firstInt = symtoi(v); } else if (type == FLOAT) { firstFloat = symtof(v); } else if (type == STRING) { firstString = symtos(v); } destroy_sym(v); } else { /* interpret type */ if (type == INT) { int si = symtoi(v); destroy_sym(v); if (si != firstInt) { return init_sym_int(0); } } else if (type == FLOAT) { float sf = symtof(v); destroy_sym(v); if (sf != firstFloat) { return init_sym_int(0); } } else if (type == STRING) { char* ss = symtos(v); if (strcmp(ss, firstString) != 0) { destroy_sym(v); free(firstString); return init_sym_int(0); } destroy_sym(v); } } } if (type == STRING) { free(firstString); } return init_sym_int(1); } else if (hash == get_hash("if")) { sym_t* v = eval(symbol->args[0], symbolScope); int si = symtoi(v); destroy_sym(v); if (si != 0) { exec_all(symbol->args + 1, symbol->argCount - 1, symbolScope); return init_sym_int(1); } return init_sym_int(0); } else if (hash == get_hash("not")) { sym_t* v = eval(symbol->args[0], symbolScope); int b = symtoi(v); destroy_sym(v); return init_sym_int(!b); } else if (hash == get_hash("sum")) { int sum = 0; for (int i = 0; i < symbol->argCount; i++) { sym_t* v = eval(symbol->args[i], symbolScope); sum += symtoi(v); destroy_sym(v); } return init_sym_int(sum); } else if (hash == get_hash("sub")) { sym_t* v1 = eval(symbol->args[0], symbolScope); int sum = symtoi(v1); destroy_sym(v1); for (int i = 1; i < symbol->argCount; i++) { sym_t* v = eval(symbol->args[i], symbolScope); sum -= symtoi(v); destroy_sym(v); } return init_sym_int(sum); } else if (hash == get_hash("print")) { sym_t* v = eval(symbol->args[0], symbolScope); if (v->litType == INT) { printf("%d\n", symtoi(v)); } else if (v->litType == FLOAT) { } else if (v->litType == STRING) { char* s = symtos(v); printf("%s\n", s); free(s); } destroy_sym(v); return init_sym_int(1); } else { return NULL; } }