#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 (unsigned int i = 0; i < (unsigned int)argCount && i < 100; i++) { char keyName[6]; 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); 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* k = eval(symbol->args[1], symbolScope); char* key = symtos(k); destroy_sym(k); sym_t* v = eval(symbol->args[0], symbolScope); pair_t p = init_pair(key, (void*)v); int result = hashtable_add_pair(symbolScope->parent, p); if (result == 0) { printf("Hashtable full when attempting to store pair with key %s\n", key); } free(key); return init_sym_int(1); } else if (hash == get_hash("update")) { /* first arg is value, second arg is key */ sym_t* k = eval(symbol->args[1], symbolScope); char* key = symtos(k); destroy_sym(k); sym_t* v = eval(symbol->args[0], symbolScope); pair_t p = init_pair(key, (void*)v); free(key); 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); } /* OR */ else if (hash == get_hash("any")) { for (int i = 0; i < symbol->argCount; i++) { sym_t* v = eval(symbol->args[i], symbolScope); if (symtoi(v) != 0) { destroy_sym(v); return init_sym_int(1); } destroy_sym(v); } return init_sym_int(0); } /* AND */ else if (hash == get_hash("all")) { for (int i = 0; i < symbol->argCount; i++) { sym_t* v = eval(symbol->args[i], symbolScope); if (symtoi(v) == 0) { destroy_sym(v); return init_sym_int(0); } destroy_sym(v); } return init_sym_int(1); } /* XOR */ else if (hash == get_hash("one")) { char b = 0; for (int i = 0; i < symbol->argCount; i++) { sym_t* v = eval(symbol->args[i], symbolScope); if (symtoi(v) == 1) { if (b == 1) { destroy_sym(v); return init_sym_int(0); } b = 1; } destroy_sym(v); } return init_sym_int(b); } else if (hash == get_hash("none")) { for (int i = 0; i < symbol->argCount; i++) { sym_t* v = eval(symbol->args[i], symbolScope); if (symtoi(v) == 1) { destroy_sym(v); return init_sym_int(0); } destroy_sym(v); } 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("while")) { while (1) { sym_t* c = eval(symbol->args[0], symbolScope); if (symtoi(c) != 0) { destroy_sym(c); exec_all(symbol->args + 1, symbol->argCount - 1, symbolScope); } else { destroy_sym(c); return init_sym_int(1); } } } 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")) { for (int i = 0; i < symbol->argCount; i++) { sym_t* v = eval(symbol->args[i], symbolScope); if (v->litType == INT) { printf("%d", symtoi(v)); } else if (v->litType == FLOAT) { printf("%.5f", symtof(v)); } else if (v->litType == STRING) { char* s = symtos(v); printf("%s", s); free(s); } destroy_sym(v); } printf("\n"); return init_sym_int(1); } else { return NULL; } }