diff options
| author | Kai Stevenson <kai@kaistevenson.com> | 2023-02-16 14:32:56 -0800 |
|---|---|---|
| committer | Kai Stevenson <kai@kaistevenson.com> | 2023-02-16 14:32:56 -0800 |
| commit | 05540fc6038f452f5dc5f18412c918c33ad96027 (patch) | |
| tree | bb9f572a1cc6f3a66cbf9835593f62db87481e0a /src | |
| parent | 10a1f7e4ad1bc90436f58269a52cddfd0587be33 (diff) | |
changed project structure
Diffstat (limited to 'src')
| -rw-r--r-- | src/eval.c | 134 | ||||
| -rw-r--r-- | src/eval.h | 9 | ||||
| -rw-r--r-- | src/hashtable.c | 39 | ||||
| -rw-r--r-- | src/hashtable.h | 19 | ||||
| -rw-r--r-- | src/parse.c | 143 | ||||
| -rw-r--r-- | src/parse.h | 40 | ||||
| -rw-r--r-- | src/precedent.c | 104 | ||||
| -rw-r--r-- | src/precedent.h | 7 | ||||
| -rw-r--r-- | src/scope.c | 20 | ||||
| -rw-r--r-- | src/scope.h | 13 |
10 files changed, 528 insertions, 0 deletions
diff --git a/src/eval.c b/src/eval.c new file mode 100644 index 0000000..b1d4e0a --- /dev/null +++ b/src/eval.c @@ -0,0 +1,134 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "eval.h" +#include "hashtable.h" +#include "parse.h" + +hashtable_t* ht; +const int hashtableSize = 1000; +const int trueVal = 1; +sym_t trueSym = {LITERAL, INT, (void*)&trueVal, NULL, 0}; +const int falseVal = 0; +sym_t falseSym = {LITERAL, INT, (void*)&falseVal, NULL, 0}; + +void init_eval() { + ht = init_hashtable(hashtableSize); +} +/* TODO: read base hashtable from file to allow modularity +pair value value? */ +void exec_all(sym_t** symbols, int count) { + for (int i = 0; i < count; i++) { + /* dispose of result */ + eval(symbols[i]); + } +} +sym_t* eval(sym_t* symbol) { + if (symbol->province == LITERAL) { + return(symbol); + } + else if (symbol->province == KEY_REF) { + sym_t* ir = try_eval_internal(symbol); + if (ir != NULL) { + return ir; + } + else { + /* not an internal function, search hashtable for + next symbol */ + /* TODO: scope */ + pair_t* p = hashtable_get_pair(ht, (char*)symbol->name); + if (p != NULL) { + return eval((sym_t*)p->value); + } + else { + printf("no matching pair in hashtable\n"); + return NULL; + } + } + } + else { + printf("no symbol province\n"); + return NULL; + } +} +/* internal functions? +this function has side-effects */ +sym_t* try_eval_internal(sym_t* symbol) { + unsigned int hash = get_hash((char*)symbol->name); + /* TODO: return last arg. that's the function return line */ + if (hash == get_hash("root")) { + /* execute all args as roots */ + exec_all(symbol->args, symbol->argCount); + return &trueSym; + } + else if (hash == get_hash("store")) { + /* TODO: scope */ + /* first arg is value, remaining args are names */ + /* TODO: recursion for multiple pairs */ + char* k = symtos(eval(symbol->args[1])); + sym_t* v = symbol->args[0]; + pair_t* p = init_pair(k, (void*)v); + hashtable_add_pair(ht, p); + return &trueSym; + } + /* TODO: release()/free() method? */ + else if (hash == get_hash("eq")) { + litType_t type = NO_TYPE; + void* lastVal = NULL; + for (int i = 0; i < symbol->argCount; i++) { + sym_t* v = eval(symbol->args[i]); + /* initialize */ + if (type == NO_TYPE) { + type = v->litType; + lastVal = v->name; + } + else { + /* interpret type */ + if (type == INT) { + if (symtoi(v) != *((int*)lastVal)) { + return &falseSym; + } + } + if (type == STRING) { + if (strcmp(symtos(v), (char*)lastVal) != 0) { + return &falseSym; + } + } + /* TODO: float */ + } + } + return &trueSym; + } + else if (hash == get_hash("if")) { + sym_t* v = eval(symbol->args[0]); + if (symtoi(v) != 0) { + exec_all(symbol->args + 1, symbol->argCount - 1); + return &trueSym; + } + return &falseSym; + } + else if (hash == get_hash("not")) { + sym_t* v = eval(symbol->args[0]); + int b = symtoi(v); + return b ? &falseSym : &trueSym; + } + else if (hash == get_hash("print")) { + sym_t* v = eval(symbol->args[0]); + switch (v->litType) { + case NO_TYPE: + break; + case INT: + printf("%d\n", symtoi(v)); + break; + case FLOAT: + break; + case STRING: + printf("%s\n", symtos(v)); + break; + } + return &trueSym; + } + else { + return NULL; + } +} diff --git a/src/eval.h b/src/eval.h new file mode 100644 index 0000000..b91c621 --- /dev/null +++ b/src/eval.h @@ -0,0 +1,9 @@ +#include "parse.h" +#ifndef EVAL +#define EVAL +void init_eval(void); +void throw(char* error, int symbolLocale); +void exec_all(sym_t** symbols, int count); +sym_t* eval(sym_t* symbol); +sym_t* try_eval_internal(sym_t* symbol); +#endif diff --git a/src/hashtable.c b/src/hashtable.c new file mode 100644 index 0000000..7cb253c --- /dev/null +++ b/src/hashtable.c @@ -0,0 +1,39 @@ +#include <stdlib.h> +#include <stdio.h> +#include "hashtable.h" + +const unsigned int fnvPrime = 16777619; +const unsigned int fnvOffset = 2166136261U; + +pair_t* init_pair(char* key, void* value) { + pair_t* p = malloc(sizeof(pair_t)); + p->key = key; + p->value = value; + return p; +} +hashtable_t* init_hashtable(unsigned int capacity) { + hashtable_t* ht = malloc(sizeof(hashtable_t)); + ht->pairs = calloc(capacity, sizeof(pair_t*)); + ht->capacity = capacity; + return ht; +} +//FNV-1a hash +unsigned int get_hash(char* str) { + unsigned int hash = fnvOffset; + while (*str != '\0') { + hash = (hash ^ *str) * fnvPrime; + str++; + } + return hash; +} +/* TODO: handle collision +TODO: return 0 if something goes wrong */ +unsigned int hashtable_add_pair(hashtable_t* hashtable, pair_t* pair) { + unsigned int hash = get_hash(pair->key); + hashtable->pairs[hash % hashtable->capacity] = pair; + return hash; +} +pair_t* hashtable_get_pair(hashtable_t* hashtable, char* key) { + unsigned int hash = get_hash(key); + return hashtable->pairs[hash % hashtable->capacity]; +} diff --git a/src/hashtable.h b/src/hashtable.h new file mode 100644 index 0000000..43ab23a --- /dev/null +++ b/src/hashtable.h @@ -0,0 +1,19 @@ +#ifndef HASHTABLE +#define HASHTABLE + +typedef struct HashPair { + char* key; + void* value; +} pair_t; +pair_t* init_pair(char* key, void* value); +typedef struct HashTable { + pair_t** pairs; + int capacity; + int itemCount; +} hashtable_t; +hashtable_t* init_hashtable(unsigned int capacity); +unsigned int get_hash(char* str); +unsigned int hashtable_add_pair(hashtable_t* hashtable, pair_t* pair); +pair_t* hashtable_get_pair(hashtable_t* hashtable, char* key); + +#endif diff --git a/src/parse.c b/src/parse.c new file mode 100644 index 0000000..27ee417 --- /dev/null +++ b/src/parse.c @@ -0,0 +1,143 @@ +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <stdio.h> +#include "parse.h" +#include "hashtable.h" + +int symtoi(sym_t* symbol) { + return *((int*)symbol->name); +} +float symtof(sym_t* symbol) { + return *((float*)symbol->name); +} +char* symtos(sym_t* symbol) { + return (char*)symbol->name; +} + +void symbol_add_arg(sym_t* symbol, sym_t* arg) { + symbol->argCount += 1; + if (symbol->argCount == 1) { + symbol->args = malloc(sizeof(sym_t*)); + } + else { + symbol->args = realloc(symbol->args, symbol->argCount * (sizeof(sym_t*))); + } + (symbol->args)[symbol->argCount - 1] = arg; +} +void symset_add_symbol(symset_t* symbolSet, sym_t* symbol) { + symbolSet->count += 1; + if (symbolSet->count == 1) { + symbolSet->symbols = malloc(sizeof(sym_t*)); + } + else { + symbolSet->symbols = realloc(symbolSet->symbols, symbolSet->count * (sizeof(sym_t*))); + } + (symbolSet->symbols)[symbolSet->count - 1] = symbol; +} +symset_t* parse_symbols(char** str) { + symset_t* symbolSet = malloc(sizeof(symset_t)); + symbolSet->count = 0; + while (1) { + /* clear whitespace */ + while (!isalnum(**str) && **str != '(' && **str != ')' && **str != '\0') { + (*str)++; + } + if (**str == ')') { + (*str)++; + return symbolSet; + } + else if (**str == '\0') { + return symbolSet; + } + char* symbolName = calloc(30, sizeof(char)); + int i = 0; + while (1) { + symbolName[i] = **str; + if (**str == ',' || **str == ';') { + (*str)++; + sym_t* symbol = malloc(sizeof(sym_t)); + symbol->province = LITERAL; + symbol->argCount = 0; + symbolName[i] = '\0'; + /* TODO: float */ + /* string */ + if (isalpha(symbolName[0])) { + //symbolName = realloc(symbolName, i * sizeof(char)); + symbol->name = symbolName; + symbol->litType = STRING; + } + /* int */ + else { + int v = atoi(symbolName); + int* vp = malloc(sizeof(int)); + *vp = v; + symbol->name = (void*)vp; + free(symbolName); + symbol->litType = INT; + } + symset_add_symbol(symbolSet, symbol); + break; + } + else if (**str == '(') { + (*str)++; + symbolName[i] = '\0'; + sym_t* symbol = malloc(sizeof(sym_t)); + symbol->province = KEY_REF; + symbol->argCount = 0; + if (i > 1) { + symbol->name = symbolName; + } + else { + symbol->name = "root"; + } + symset_t* symbols = parse_symbols(str); + for (int s = 0; s < symbols->count; s++) { + symbol_add_arg(symbol, symbols->symbols[s]); + } + symset_add_symbol(symbolSet, symbol); + break; + } + i++; + (*str)++; + } + } +} +sym_t* parse_symbol_final(char* str) { + char** strp = malloc(sizeof(char**)); + *strp = str; + symset_t* finalSymset = parse_symbols(strp); + sym_t* root = malloc(sizeof(sym_t)); + root->name = "root"; + root->province = KEY_REF; + root->argCount = 0; + for (int s = 0; s < finalSymset->count; s++) { + symbol_add_arg(root, finalSymset->symbols[s]); + } + return root; +} +void write_symbol_visual(sym_t* symbol, int offset) { + for (int o = 0; o < offset; o++) { + printf(" "); + } + if (symbol->province == KEY_REF) { + printf("%s (%s)\n", (char*)(symbol->name), "KEY"); + } + else if (symbol->province == LITERAL) { + if (symbol->litType == INT) { + printf("%d (%s)\n", *(int*)(symbol->name), "LITERAL"); + } + else if (symbol->litType == FLOAT) { + printf("%f (%s)\n", *(float*)(symbol->name), "LITERAL"); + } + else if (symbol->litType == STRING) { + printf("%s (%s)\n", (char*)(symbol->name), "LITERAL"); + } + } + else { + printf("symbol parse error\n"); + } + for (int i = 0; i < symbol->argCount; i++) { + write_symbol_visual(symbol->args[i], offset + 4); + } +} diff --git a/src/parse.h b/src/parse.h new file mode 100644 index 0000000..27ce444 --- /dev/null +++ b/src/parse.h @@ -0,0 +1,40 @@ +#ifndef PARSE +#define PARSE + +/* keyword hashes */ +#define VAR_H 2317739966u +#define DEFINE_H 1788839250 + +typedef enum SymbolProvince { + NO_PROVINCE, + KEY_REF, + LITERAL +} prov_t; +typedef enum LiteralType { + NO_TYPE, + INT, + FLOAT, + STRING +} litType_t; +typedef struct Symbol { + prov_t province; + litType_t litType; + void* name; + struct Symbol** args; + int argCount; +} sym_t; +typedef struct SymbolSet { + sym_t** symbols; + int count; +} symset_t; + +int symtoi(sym_t* symbol); +float symtof(sym_t* symbol); +char* symtos(sym_t* symbol); +void symbol_add_arg(sym_t* symbol, sym_t* arg); +void symset_add_symbol(symset_t* symbolSet, sym_t* symbol); +symset_t* parse_symbols(char** str); +sym_t* parse_symbol_final(char* str); +void write_symbol_visual(sym_t* symbol, int offset); + +#endif diff --git a/src/precedent.c b/src/precedent.c new file mode 100644 index 0000000..81555b9 --- /dev/null +++ b/src/precedent.c @@ -0,0 +1,104 @@ +#include <stdlib.h> +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <libgen.h> +#include "precedent.h" +#include "hashtable.h" +#include "parse.h" +#include "eval.h" + +int main(int argc, char** argv) { + int visual = 0; + if (argc > 1) { + for (int i = 1; i < argc; i++) { + if (strcmp("--version", argv[i]) == 0) { + printf("precedent, version 0.1\n"); + printf("Copyright 2023 Kai Stevenson\n"); + printf("All rights reserved. No part of the software may be sold\nor used in derivative works without explicit consent\n"); + return 0; + } + else if (strcmp("--help", argv[i]) == 0) { + printf("usage: precedent <file> [--visualize] [--version] [--help]\n"); + return 0; + } + else if (strcmp("--visualize", argv[i]) == 0) { + visual = 1; + } + } + } + else { + printf("usage: precedent <file> [--visualize] [--version] [--help]\n"); + return 0; + } + /* dirname may modify path, copy first */ + char* path = argv[1]; + char* pathCpy = malloc((strlen(path) + 1) * sizeof(char)); + strcpy(pathCpy, path); + char* dirName = dirname(pathCpy); + char* baseDir = malloc((strlen(dirName) + 2) * sizeof(char)); + strcpy(baseDir, dirName); + strcat(baseDir, "/"); + sym_t* finalSymbol = parse_symbol_final(read_file(path)); + if (visual) { + printf("--BEGIN VISUALIZATION--\n"); + write_symbol_visual(finalSymbol, 0); + printf("--END VISUALIZATION--\n"); + } + init_eval(); + eval(finalSymbol); + free(dirName); + free(pathCpy); + free(baseDir); + return 0; +} +char* read_file(char* path) { + FILE* file = fopen(path, "r"); + fseek(file, 0, SEEK_END); + unsigned long int length = ftell(file); + fseek(file, 0, SEEK_SET); + char* out = malloc((length + 1) * sizeof(char)); + fread(out, length, 1, file); + fclose(file); + out[length] = '\0'; + return out; +} +/* wtf */ +char* preprocess(char* str, char* baseDir) { + char* final = str; + while (1) { + int i = 0; + while (str[i] != '@') { + i++; + if (str[i] == '\0') { + printf("%s\n", final); + return final; + } + } + i++; + char* includeName = malloc(20 * sizeof(char)); + int f = 0; + while (isalnum(str[i]) || str[i] == '/' || str[i] == '.' || str[i] == '_') { + includeName[f] = str[i]; + str[i] = ' '; + i++; + f++; + } + final = str; + includeName[f] = '\0'; + char* path = malloc((strlen(baseDir) + strlen(includeName) + 1) * sizeof(char)); + strcpy(path, baseDir); + strcat(path, includeName); + char* toInclude = preprocess(read_file(path), baseDir); + char* newStr = malloc((strlen(toInclude) + strlen(final) + 1) * sizeof(char)); + strcpy(newStr, toInclude); + strcat(newStr, final); + /* + free(includeName); + free(path); + free(str); + free(toInclude); + */ + final = newStr; + } +} diff --git a/src/precedent.h b/src/precedent.h new file mode 100644 index 0000000..8a5110e --- /dev/null +++ b/src/precedent.h @@ -0,0 +1,7 @@ +#include "parse.h" +#include "hashtable.h" +#ifndef PRECEDENT +char* read_file(char* path); +char* preprocess(char* str, char* baseDir); +#define PRECEDENT +#endif diff --git a/src/scope.c b/src/scope.c new file mode 100644 index 0000000..afb9d5c --- /dev/null +++ b/src/scope.c @@ -0,0 +1,20 @@ +#include <stdlib.h> +#include "scope.h" +#include "hashtable.h" + +scope_t* init_scope(scope_t parent) { + scope_t* scope = malloc(sizeof(scope_t)); + scope->hashtable = init_hashtable(1000); + *(scope->parent) = parent; + return scope; +} +pair_t* get_pair_global(scope_t* scope, char* key) { + while (scope->parent != NULL) { + pair_t* pair = hashtable_get_pair(scope->hashtable, key); + if (pair != NULL) { + return pair; + } + scope = scope->parent; + } + return NULL; +} diff --git a/src/scope.h b/src/scope.h new file mode 100644 index 0000000..d1cda0d --- /dev/null +++ b/src/scope.h @@ -0,0 +1,13 @@ +#include "hashtable.h" +#ifndef SCOPE +#define SCOPE + +typedef struct Scope { + hashtable_t* hashtable; + struct Scope* parent; +} scope_t; +scope_t* init_scope(scope_t parent); +pair_t* get_pair_global(scope_t* scope, char* key); +pair_t* get_pair_local(scope_t* scope, char* key); + +#endif |
