#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 firstType = NO_TYPE; int firstInt = 0; float firstFloat = 0; char* firstString = NULL; for (int i = 0; i < symbol->argCount; i++) { sym_t* v = eval(symbol->args[i], symbolScope); /* initialize */ if (firstType == NO_TYPE) { firstType = v->litType; if (firstType == INT) { firstInt = symtoi(v); } else if (firstType == FLOAT) { firstFloat = symtof(v); } else if (firstType == STRING) { firstString = symtos(v); } destroy_sym(v); } else { /* interpret type */ if (v->litType == INT) { int si = symtoi(v); destroy_sym(v); if (si != (firstType == FLOAT ? firstFloat : firstInt)) { return init_sym_int(0); } } else if (v->litType == FLOAT) { float sf = symtof(v); destroy_sym(v); if (sf != (firstType == FLOAT ? firstFloat : firstInt)) { return init_sym_int(0); } } else if (v->litType == STRING) { if (firstType == STRING) { char* ss = symtos(v); if (strcmp(ss, firstString) != 0) { destroy_sym(v); free(firstString); return init_sym_int(0); } } else { destroy_sym(v); return init_sym_int(0); } destroy_sym(v); } } } if (firstString != NULL) { 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; float fSum = 0; char isFloat = 0; for (int i = 0; i < symbol->argCount; i++) { sym_t* v = eval(symbol->args[i], symbolScope); if (v->litType == INT) { sum += symtoi(v); } else if (v->litType == FLOAT) { fSum += symtof(v); isFloat = 1; } destroy_sym(v); } if (!isFloat) { return init_sym_int(sum); } else { return init_sym_float(sum + fSum); } } else if (hash == get_hash("sub")) { sym_t* v1 = eval(symbol->args[0], symbolScope); int sum = 0; float fSum = 0; char isFloat = 0; if (v1->litType == INT) { sum = symtoi(v1); } else if (v1->litType == FLOAT) { fSum = symtof(v1); isFloat = 1; } destroy_sym(v1); for (int i = 1; i < symbol->argCount; i++) { sym_t* v = eval(symbol->args[i], symbolScope); if (v->litType == INT) { sum -= symtoi(v); } else if (v->litType == FLOAT) { fSum -= symtof(v); isFloat = 1; } destroy_sym(v); } if (!isFloat) { return init_sym_int(sum); } else { return init_sym_float(sum + fSum); } } 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) { printf("%.5f\n", symtof(v)); } 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; } }